MCP Plugin
The Model Context Protocol (MCP) plugin exposes a subset of Payload operations to MCP-capable agent clients (Claude Code, Claude Desktop, etc.) on top of the same service layer the CLI and REST API use.
What’s enabled
// src/domains/cms/payload/plugins/plugin-mcp.ts
mcpPlugin({
collections: {
pages: { enabled: true },
tenants: { enabled: true },
},
})pages—create,update,deletevia generic collection tools, plus custom toolspage_list,page_get,page_get_blockfor read access. Genericfindis intentionally disabled because full-page reads can blow MCP context.tenants— fully enabled (find / create / update / delete).
Other collections will be added as their corresponding services land.
How agents connect
ShipMore’s MCP server runs in-process on the deployed box. Point your MCP client at:
https://<your-shipmore-box>/api/mcpAuthentication uses the same Payload API key as the CLI — pass it as a bearer token.
For Claude Desktop, add to your config:
{
"mcpServers": {
"shipmore": {
"url": "https://your-shipmore-box/api/mcp",
"headers": { "Authorization": "Bearer YOUR_PAYLOAD_API_KEY" }
}
}
}Adapter rule
MCP tool handlers, REST handlers, CLI scripts, and webhook handlers are all adapters — they translate inputs, call a service method, and return the result. No business logic in handlers.
// ✅ correct — adapter calls service
server.registerTool('add_block_to_page', schema,
async (input) => PageService.addBlock({
pageId: input.page_id,
block: input.block,
position: input.position,
tenantId: input.tenant_id,
})
)
// ❌ wrong — logic in the adapter (will be duplicated in REST and CLI)
server.registerTool('add_block_to_page', schema,
async (input) => {
const payload = await getPayload({ config })
const page = await payload.findByID({ collection: 'pages', id: input.page_id })
// ... 30 more lines of logic
}
)Enabling more collections
To add a collection to the MCP plugin:
- Build the corresponding service in
src/domains/.../services/. Tests first. - Add custom MCP tools (or generic CRUD) in
src/domains/cms/payload/plugins/plugin-mcp.tsthat thinly call the service. - Update
SKILL.mdso agents know the new operations exist. - Run
pnpm generate:typesif you added fields.
When to add custom MCP tools vs. generic CRUD
| Add a custom MCP tool when… | Use generic CRUD when… |
|---|---|
| The operation has business logic (composition, multi-step orchestration, validation beyond field-level) | Plain create/update/delete is enough and access control is sufficient |
Generic find would return too much context (e.g. full pages with all blocks) | Reads are small and well-bounded |
| There’s a CLI counterpart that already encapsulates the operation | The collection is simple and admin-managed |
Reference
- Plugin source:
src/domains/cms/payload/plugins/plugin-mcp.ts - Plugin docs:
refs/plugin-mcp/README.md(in the repo) - Patterns: Agents → Patterns