๐Ÿ“ฆ payloadcms / payload

๐Ÿ“„ mcp.mdx ยท 460 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460---
title: MCP Plugin
label: MCP
order: 49
desc: MCP (Model Context Protocol) capabilities with Payload
keywords: plugins, mcp, ai, model context protocol, plugin, payload, cms
---

![https://www.npmjs.com/package/@payloadcms/plugin-mcp](https://img.shields.io/npm/v/@payloadcms/plugin-mcp)

<Banner type="warning">
  This plugin is currently in Beta and may have breaking changes in future
  releases.
</Banner>

This plugin adds [Model Context Protocol](https://modelcontextprotocol.io/docs/getting-started/intro) capabilities.

<Banner type="info">
  This plugin is completely open-source and the [source code can be found
  here](https://github.com/payloadcms/payload/tree/main/packages/plugin-mcp). If
  you need help, check out our [Community
  Help](https://payloadcms.com/community-help). If you think you've found a bug,
  please [open a new
  issue](https://github.com/payloadcms/payload/issues/new?assignees=&labels=plugin%3A%mcp&template=bug_report.md&title=plugin-mcp%3A)
  with as much detail as possible.
</Banner>

## Core features

- Adds a collection to your config where:
  - You can allow / disallow `find`, `create`, `update`, and `delete` operations for each collection
  - You can to allow / disallow capabilities in real time
  - You can define your own Prompts, Tools and Resources available over MCP

## Installation

Install the plugin using any JavaScript package manager like [pnpm](https://pnpm.io), [npm](https://npmjs.com), or [Yarn](https://yarnpkg.com):

```bash
  pnpm add @payloadcms/plugin-mcp
```

## Basic Usage

In the `plugins` array of your [Payload Config](https://payloadcms.com/docs/configuration/overview), call the plugin with [options](#options):

```ts
import { buildConfig } from 'payload'
import { mcpPlugin } from '@payloadcms/plugin-mcp'

const config = buildConfig({
  collections: [
    {
      slug: 'posts',
      fields: [],
    },
  ],
  plugins: [
    mcpPlugin({
      collections: {
        posts: {
          enabled: true,
        },
      },
    }),
  ],
})

export default config
```

### Options

| Option                                 | Type                | Description                                                                                    |
| -------------------------------------- | ------------------- | ---------------------------------------------------------------------------------------------- |
| `collections`                          | `object`            | An object of collection slugs to use for MCP capabilities.                                     |
| `collections[slug]`                    | `object`            | An object of collection slugs to use for MCP capabilities.                                     |
| `collections[slug].description`        | `string`            | A description for the collection.                                                              |
| `collections[slug].overrideResponse`   | `function`          | A function that allows you to override the response from the operation tool call               |
| `collections[slug].enabled`            | `object or boolean` | Determines whether the model can find, create, update, and delete documents in the collection. |
| `collections[slug].enabled.find`       | `boolean`           | Whether to allow the model to find documents in the collection.                                |
| `collections[slug].enabled.create`     | `boolean`           | Whether to allow the model to create documents in the collection.                              |
| `collections[slug].enabled.update`     | `boolean`           | Whether to allow the model to update documents in the collection.                              |
| `collections[slug].enabled.delete`     | `boolean`           | Whether to allow the model to delete documents in the collection.                              |
| `disabled`                             | `boolean`           | Disable the MCP plugin while keeping database schema consistent.                               |
| `overrideApiKeyCollection`             | `function`          | A function that allows you to override the automatically generated API Keys collection.        |
| `mcp`                                  | `object`            | MCP options that allow you to customize the MCP server.                                        |
| `mcp.tools`                            | `array`             | An array of tools to add to the MCP server.                                                    |
| `mcp.tools.name`                       | `string`            | The name of the tool.                                                                          |
| `mcp.tools.description`                | `string`            | The description of the tool.                                                                   |
| `mcp.tools.handler`                    | `function`          | The handler function for the tool.                                                             |
| `mcp.tools.parameters`                 | `object`            | The parameters for the tool (Zod schema).                                                      |
| `mcp.prompts`                          | `array`             | An array of prompts to add to the MCP server.                                                  |
| `mcp.prompts.name`                     | `string`            | The name of the prompt.                                                                        |
| `mcp.prompts.title`                    | `string`            | The title of the prompt (used by models to determine when to use it).                          |
| `mcp.prompts.description`              | `string`            | The description of the prompt.                                                                 |
| `mcp.prompts.handler`                  | `function`          | The handler function for the prompt.                                                           |
| `mcp.prompts.argsSchema`               | `object`            | The arguments schema for the prompt (Zod schema).                                              |
| `mcp.resources`                        | `array`             | An array of resources to add to the MCP server.                                                |
| `mcp.resources.name`                   | `string`            | The name of the resource.                                                                      |
| `mcp.resources.title`                  | `string`            | The title of the resource (used by models to determine when to use it).                        |
| `mcp.resources.description`            | `string`            | The description of the resource.                                                               |
| `mcp.resources.handler`                | `function`          | The handler function for the resource.                                                         |
| `mcp.resources.uri`                    | `string or object`  | The URI of the resource (can be a string or ResourceTemplate for dynamic URIs).                |
| `mcp.resources.mimeType`               | `string`            | The MIME type of the resource.                                                                 |
| `mcp.handlerOptions`                   | `object`            | The handler options for the MCP server.                                                        |
| `mcp.handlerOptions.basePath`          | `string`            | The base path for the MCP server (default: '/api').                                            |
| `mcp.handlerOptions.verboseLogs`       | `boolean`           | Whether to log verbose logs to the console (default: false).                                   |
| `mcp.handlerOptions.maxDuration`       | `number`            | The maximum duration for the MCP server requests (default: 60).                                |
| `mcp.serverOptions`                    | `object`            | The server options for the MCP server.                                                         |
| `mcp.serverOptions.serverInfo`         | `object`            | The server info for the MCP server.                                                            |
| `mcp.serverOptions.serverInfo.name`    | `string`            | The name of the MCP server (default: 'Payload MCP Server').                                    |
| `mcp.serverOptions.serverInfo.version` | `string`            | The version of the MCP server (default: '1.0.0').                                              |

## Connecting to MCP Clients

After installing and configuring the plugin, you can connect apps with MCP client capabilities to Payload.

### Step 1: Create an API Key

1. Start your Payload server
2. Navigate to your admin panel at `http://localhost:3000/admin`
3. Go to the **MCP โ†’ API Keys** collection
4. Click **Create New**
5. Allow or Disallow MCP traffic permissions for each collection (enable find, create, update, delete as needed)
6. Click **Create** and copy the uniquely generated API key

### Step 2: Configure Your MCP Client

MCP Clients can be configured to interact with your MCP server.
These clients require some JSON configuration, or platform configuration in order to know how to reach your MCP server.

<Banner type="warning">
  Caution: the format of these JSON files may change over time. Please check the
  client website for updates.
</Banner>

Our recommended approach to make your server available for most MCP clients is to use the [mcp-remote](https://www.npmjs.com/package/mcp-remote) package via `npx`.

Below are configuration examples for popular MCP clients.

#### [VSCode](https://code.visualstudio.com/docs/copilot/customization/mcp-servers)

```json
{
  "mcp.servers": {
    "Payload": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "http://127.0.0.1:3000/api/mcp",
        "--header",
        "Authorization: Bearer API-KEY-HERE"
      ]
    }
  }
}
```

#### [Cursor](https://cursor.com/docs/context/mcp)

```json
{
  "mcpServers": {
    "Payload": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "http://localhost:3000/api/mcp",
        "--header",
        "Authorization: Bearer API-KEY-HERE"
      ]
    }
  }
}
```

#### Other MCP Clients

For connections without using `mcp-remote` you can use this configuration format:

```json
{
  "mcpServers": {
    "Payload": {
      "type": "http",
      "url": "http://localhost:3000/api/mcp",
      "headers": {
        "Authorization": "Bearer API-KEY-HERE"
      }
    }
  }
}
```

## Customizations

The plugin supports fully custom `prompts`, `tools` and `resources` that can be called or retrieved by MCP clients.
After defining a custom method you can allow / disallow the feature from the admin panel by adjusting the `API Key` MCP Options checklist.

## Prompts

Prompts allow models to generate structured messages for specific tasks. Each prompt defines a schema for arguments and returns formatted messages:

```ts
prompts: [
  {
    name: 'reviewContent',
    title: 'Content Review Prompt',
    description: 'Creates a prompt for reviewing content quality',
    argsSchema: {
      content: z.string().describe('The content to review'),
      criteria: z.array(z.string()).describe('Review criteria'),
    },
    handler: ({ content, criteria }, req) => ({
      messages: [
        {
          content: {
            type: 'text',
            text: `Please review this content based on the following criteria: ${criteria.join(', ')}\n\nContent: ${content}`,
          },
          role: 'user',
        },
      ],
    }),
  },
]
```

## Resources

Resources provide access to data or content that models can read. They can be static or dynamic with parameterized URIs:

```ts
resources: [
  // Static resource
  {
    name: 'guidelines',
    title: 'Content Guidelines',
    description: 'Company content creation guidelines',
    uri: 'guidelines://company',
    mimeType: 'text/markdown',
    handler: (uri, req) => ({
    handler: (uri, req) => ({
      contents: [
        {
          uri: uri.href,
          text: '# Content Guidelines\n\n1. Keep it concise\n2. Use clear language',
        },
      ],
    }),
  },

  // Dynamic resource with template
  {
    name: 'userProfile',
    title: 'User Profile',
    description: 'Access user profile information',
    uri: new ResourceTemplate('users://profile/{userId}', { list: undefined }),
    mimeType: 'application/json',
    handler: async (uri, { userId }, req) => {
      // Fetch user data from your system
      const userData = await getUserById(userId)
      return {
        contents: [
          {
            uri: uri.href,
            text: JSON.stringify(userData, null, 2),
          },
        ],
      }
    },
  },
]
```

## Tools

Tools allow you to extend MCP capabilities beyond basic CRUD operations. Use them when you need to perform complex queries, aggregations, or business logic that isn't covered by the standard collection operations.

```ts
tools: [
  {
    name: 'getPostScores',
    description: 'Get useful scores about content in posts',
    handler: async (args, req) => {
      const { payload } = req
      const stats = await payload.find({
        collection: 'posts',
        where: {
          createdAt: {
            greater_than: args.since,
          },
        },
        req,
        overrideAccess: false,
        user: req.user,
      })

      return {
        content: [
          {
            type: 'text',
            text: `Found ${stats.totalDocs} posts created since ${args.since}`,
          },
        ],
      }
    },
    parameters: z.object({
      since: z.string().describe('ISO date string for filtering posts'),
    }).shape,
  },
]
```

## API Key access to MCP

Payload adds an API key collection that allows admins to manage MCP capabilities. Admins can:

- Create user associated API keys for MCP clients
- `Allow` or `disallow` endpoint traffic in real-time
- `Allow` or `disallow` tools, resources, and prompts

You can customize the API Key collection using the `overrideApiKeyCollection` option:

```ts
mcpPlugin({
  overrideApiKeyCollection: (collection) => {
    // Add fields to the API Keys collection
    collection.fields.push({
      name: 'department',
      type: 'select',
      options: [
        { label: 'Development', value: 'dev' },
        { label: 'Marketing', value: 'marketing' },
      ],
    })

    // You can also add hooks
    collection.hooks?.beforeRead?.push(({ doc, req }) => {
      req.payload.logger.info('Before Read MCP hook!')
      return doc
    })
    return collection
  },
  // ... other options
})
```

You can create an MCP access strategy using the `overrideAuth` option:

```ts
import { type MCPAccessSettings, mcpPlugin } from '@payloadcms/plugin-mcp'

// ... other config

mcpPlugin({
  overrideAuth: (req, getDefaultMcpAccessSettings) => {
    const { payload } = req

    // This will return the default MCPAccessSettings
    // getDefaultMcpAccessSettings()

    payload.logger.info('Custom access Settings for all MCP traffic')
    return {
      posts: {
        find: true,
      },
      products: {
        find: true,
      },
    } as MCPAccessSettings
  },
  // ... other options
})
```

If you want the default `MCPAccessSettings`, you can use the addtional argument `getDefaultMcpAccessSettings`.
This will use the Bearer token found in the headers on the req to return the `MCPAccessSettings` related to the user assigned to the API key.

## Hooks

To understand or modify data returned by models at runtime use a collection [Hook](https://payloadcms.com/docs/hooks/collections). Within a hook you can look up the API context. If the context is `MCP` that collection was triggered by the MCP Plugin. This does not apply to custom tools or resources that have their own context, and can make unrelated database calls.

In this example, Post titles are modified to include '(MCP Hook Override)' when they are read using MCP.

```ts
import type { CollectionConfig } from 'payload'

export const Posts: CollectionConfig = {
  slug: 'posts',
  fields: [
    {
      name: 'title',
      type: 'text',
      admin: {
        description: 'The title of the post',
      },
      required: true,
    },

    // ... other fields
  ],
  hooks: {
    beforeRead: [
      ({ doc, req }) => {
        if (req.payloadAPI === 'MCP') {
          doc.title = `${doc.title} (MCP Hook Override)`
        }
        return doc
      },
    ],
  },
}
```

## Performance

The description you choose to use for your collection greatly impacts the way a model will decide to use it.

The description in this example is more difficult for a model to understand it's purpose.

```ts
// Weak
const config = buildConfig({
  // ...
  plugins: [
    mcpPlugin({
      collections: {
        posts: {
          enabled: true,
          description: 'My posts',
        },
      },
    }),
  ],
})
```

The description in this example gives a model a stronger ability to know when to use this collection.

```ts
// Strong
const config = buildConfig({
  // ...
  plugins: [
    mcpPlugin({
      collections: {
        posts: {
          enabled: true,
          description: 'Posts with content about science and nature',
        },
      },
    }),
  ],
})
```