@arevo/payload-mcp
v1.0.1
Published
A Payload CMS plugin that exposes a site-local MCP server over streamable HTTP.
Readme
payloadcms-mcp-server
A Payload CMS plugin that exposes a site-local MCP server over streamable HTTP.
Install the plugin in any Payload app, give it a shared bearer token, and connect your MCP client directly to that Payload instance. There is no browser auth flow. The MCP client talks to https://your-site.com/api/mcp and the plugin uses Payload's Local API to read and mutate content.
What it does
- Exposes a streamable HTTP MCP endpoint from the Payload app itself
- Secures the endpoint with a shared bearer token
- Lets MCP clients inspect the Payload schema before making changes
- Supports generic collection CRUD, global CRUD, duplication, counts, and uploads
- Runs entirely inside the Payload server, so there is no separate MCP process to host
Security model
This plugin is designed for direct server-to-client MCP connections.
- The endpoint is protected by a static bearer token that you configure in Payload.
- By default, the plugin runs Local API operations with
overrideAccess: true. - That means the MCP connection acts like a trusted service account with full access to the exposed collections and globals.
- If you want stricter scope, limit the exposed collections/globals and set
overrideAccess: false.
If you expose this on a public site, use a strong random token and keep it in environment variables on both sides.
Installation
pnpm add payloadcms-mcp-serverThen add it to your payload.config.ts:
import { buildConfig } from 'payload'
import { payloadMCP } from 'payloadcms-mcp-server'
export default buildConfig({
collections: [
// your collections
],
globals: [
// your globals
],
plugins: [
payloadMCP({
endpoint: '/mcp',
serverName: 'my-payload-site',
token: process.env.PAYLOAD_MCP_TOKEN,
}),
],
})Required environment variables
Add a shared token to your Payload app:
PAYLOAD_MCP_TOKEN=replace-this-with-a-long-random-secretYour MCP client should use the same token as a bearer token.
Connecting from an MCP client
Use these settings in clients that support remote streamable HTTP MCP servers:
- Name: anything you want
- Transport:
Streamable HTTP - URL:
https://your-site.com/api/mcp - Bearer token env var: whatever env var your client uses locally, for example
PAYLOAD_MCP_TOKEN
Example local client env:
export PAYLOAD_MCP_TOKEN=replace-this-with-a-long-random-secretPlugin options
type PayloadMCPPluginConfig = {
allowUnauthenticated?: boolean
collections?: true | string[]
corsOrigins?: '*' | string[]
defaultDepth?: number
enabled?: boolean
endpoint?: `/${string}`
globals?: true | string[]
maxBase64UploadSizeMB?: number
maxFindLimit?: number
overrideAccess?: boolean
serverName?: string
token?: string
tokens?: string[]
}Common options
token: the shared bearer token for the MCP endpointtokens: multiple valid bearer tokens if you want rotation or per-client tokensendpoint: endpoint path relative to Payload's API route, defaults to/mcpserverName: the MCP server name reported to clientscollections:truefor all collections or an allowlist like['pages', 'posts', 'media']globals:truefor all globals or an allowlistoverrideAccess: defaults totrueallowUnauthenticated: only use this if you explicitly want an open MCP endpointcorsOrigins: optional CORS allowlist for browser-based callers
Recommended production config
payloadMCP({
collections: ['pages', 'posts', 'media'],
endpoint: '/mcp',
globals: ['site-settings'],
maxBase64UploadSizeMB: 5,
maxFindLimit: 25,
overrideAccess: true,
serverName: 'marketing-site',
token: process.env.PAYLOAD_MCP_TOKEN,
})Exposed tools
The plugin currently registers these MCP tools:
payload_server_infopayload_schemapayload_findpayload_find_by_idpayload_countpayload_createpayload_updatepayload_deletepayload_duplicatepayload_get_globalpayload_update_globalpayload_create_upload_from_urlpayload_create_upload_from_base64
It also exposes:
- Resource:
payload://schema - Prompt:
payload-editor-guide
Typical workflow
Most MCP clients will work best if the model follows this order:
- Call
payload_schema - Inspect available collections, globals, and fields
- Read the target document with
payload_findorpayload_find_by_id - Apply changes with
payload_create,payload_update, orpayload_update_global
Uploads
Two upload helpers are included:
payload_create_upload_from_url: download a remote file and create an upload documentpayload_create_upload_from_base64: create an upload document from base64 file contents
Base64 uploads are limited by maxBase64UploadSizeMB, which defaults to 10.
Development
This repo includes a working Payload app in dev that uses the plugin locally.
Start the dev app
pnpm install
pnpm devDefault local credentials:
- Email:
[email protected] - Password:
test
Default local MCP token:
payload-mcp-dev-token
Local MCP URL:
http://localhost:3000/api/mcp
Run tests
pnpm test:int
pnpm buildPublishing to npm
Before publishing:
- Update
package.jsonmetadata if you want a different package name, author, or repository URL. - Run
pnpm test:int - Run
pnpm build - Publish with your preferred registry workflow
Example:
npm publish --access publicNotes
- The plugin uses Payload's custom endpoints, so the final URL is your Payload API route plus the configured
endpoint. - With a standard Payload setup,
/mcpbecomes/api/mcp. - The plugin intentionally does not implement an OAuth or browser auth flow.
- The current design is best for trusted internal tooling and direct editor/agent connections.
License
MIT
