Simplify your stack and build anything. Or everything.
Build tomorrow’s web with a modern solution you truly own.
Code-based nature means you can build on top of it to power anything.
It’s time to take back your content infrastructure.

MCP Plugin

https://www.npmjs.com/package/@payloadcms/plugin-mcp

This plugin adds Model Context Protocol capabilities.

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, npm, or Yarn:

1
pnpm add @payloadcms/plugin-mcp

Basic Usage

In the plugins array of your Payload Config, call the plugin with options:

1
import { buildConfig } from 'payload'
2
import { mcpPlugin } from '@payloadcms/plugin-mcp'
3
4
const config = buildConfig({
5
collections: [
6
{
7
slug: 'posts',
8
fields: [],
9
},
10
],
11
plugins: [
12
mcpPlugin({
13
collections: {
14
posts: {
15
enabled: true,
16
},
17
},
18
}),
19
],
20
})
21
22
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].override

function

A function that allows you to override the data generated by the LLM before it is used in an operation.

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 LLM can find, create, update, and delete documents in the collection.

collections[slug].enabled.find

boolean

Whether to allow the LLM to find documents in the collection.

collections[slug].enabled.create

boolean

Whether to allow the LLM to create documents in the collection.

collections[slug].enabled.update

boolean

Whether to allow the LLM to update documents in the collection.

collections[slug].enabled.delete

boolean

Whether to allow the LLM 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 custom 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 custom 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 LLMs 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 custom 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 LLMs 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').

Override API Keys Collection

The plugin automatically creates an API Keys collection that provides high-resolution control over MCP capabilities. This collection allows admins to:

  • Create API keys for MCP clients
  • Allow or disallow specific MCP capabilities in real-time
  • Control which collections can be accessed via MCP
  • Enable or disable custom tools

You can customize this collection using the overrideApiKeyCollection option:

1
mcpPlugin({
2
overrideApiKeyCollection: (collection) => {
3
// Add custom fields to the API Keys collection
4
collection.fields.push({
5
name: 'department',
6
type: 'select',
7
options: [
8
{ label: 'Development', value: 'dev' },
9
{ label: 'Marketing', value: 'marketing' },
10
],
11
})
12
return collection
13
},
14
// ... other options
15
})

Custom Prompts

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

1
prompts: [
2
{
3
name: 'reviewContent',
4
title: 'Content Review Prompt',
5
description: 'Creates a prompt for reviewing content quality',
6
argsSchema: {
7
content: z.string().describe('The content to review'),
8
criteria: z.array(z.string()).describe('Review criteria'),
9
},
10
handler: ({ content, criteria }) => ({
11
messages: [
12
{
13
content: {
14
type: 'text',
15
text: `Please review this content based on the following criteria: ${criteria.join(', ')}\n\nContent: ${content}`,
16
},
17
role: 'user',
18
},
19
],
20
}),
21
},
22
]

Custom Resources

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

1
resources: [
2
// Static resource
3
{
4
name: 'guidelines',
5
title: 'Content Guidelines',
6
description: 'Company content creation guidelines',
7
uri: 'guidelines://company',
8
mimeType: 'text/markdown',
9
handler: (uri) => ({
10
contents: [
11
{
12
uri: uri.href,
13
text: '# Content Guidelines\n\n1. Keep it concise\n2. Use clear language',
14
},
15
],
16
}),
17
},
18
19
// Dynamic resource with template
20
{
21
name: 'userProfile',
22
title: 'User Profile',
23
description: 'Access user profile information',
24
uri: new ResourceTemplate('users://profile/{userId}', { list: undefined }),
25
mimeType: 'application/json',
26
handler: async (uri, { userId }) => {
27
// Fetch user data from your system
28
const userData = await getUserById(userId)
29
return {
30
contents: [
31
{
32
uri: uri.href,
33
text: JSON.stringify(userData, null, 2),
34
},
35
],
36
}
37
},
38
},
39
]

Data Override Example

Use override functions to modify data before it's processed:

1
collections: {
2
posts: {
3
enabled: true,
4
override: (original, req) => {
5
// Log the operation
6
req.payload.logger.info('MCP operation on posts:', original)
7
8
// Sanitize or validate data
9
const sanitized = {
10
...original,
11
title: sanitizeTitle(original.title),
12
publishedAt: original.publishedAt || new Date().toISOString(),
13
}
14
15
return sanitized
16
},
17
},
18
}

Use overrideResponse to modify response data:

1
collections: {
2
posts: {
3
enabled: true,
4
overrideResponse: (response, doc, req) => {
5
response.content.push({
6
type: 'text',
7
text: 'Additional response for Posts!',
8
})
9
return response
10
},
11
},
12
}

Custom Tool with Database Access

Custom 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.

1
tools: [
2
{
3
name: 'getPostStats',
4
description: 'Get statistics about posts in the system',
5
handler: async (args, { payload }) => {
6
const stats = await payload.find({
7
collection: 'posts',
8
where: {
9
createdAt: {
10
greater_than: args.since,
11
},
12
},
13
})
14
15
return {
16
content: [
17
{
18
type: 'text',
19
text: `Found ${stats.totalDocs} posts created since ${args.since}`,
20
},
21
],
22
}
23
},
24
parameters: z.object({
25
since: z.string().describe('ISO date string for filtering posts'),
26
}).shape,
27
},
28
]

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.

1
// Weak
2
const config = buildConfig({
3
// ...
4
plugins: [
5
mcpPlugin({
6
collections: {
7
posts: {
8
enabled: true,
9
description: 'My posts',
10
},
11
},
12
}),
13
],
14
})

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

1
// Strong
2
const config = buildConfig({
3
// ...
4
plugins: [
5
mcpPlugin({
6
collections: {
7
posts: {
8
enabled: true,
9
description: 'My posts',
10
},
11
},
12
}),
13
],
14
})
Next

Ecommerce Overview