## Summary
- Versions (without drafts, capped at 100 per document/global) are now
**enabled by default** for all collections and globals, removing the
need to opt in
- `versions: false` must be set explicitly to opt out; a codemod is
provided to automate the migration with zero schema changes
- A second codemod strips the now-redundant bare `versions: true` from
existing configs
## What changed
**Core behaviour**
- `packages/payload/src/collections/config/defaults.ts` — `versions`
default changed from `false` to `true`
- `packages/payload/src/globals/config/sanitize.ts` — added
`global.versions = global.versions ?? true` so globals follow the same
default
**System collections/globals that must not accumulate version history**
— `versions: false` added to each:
- Built-in users collection (`auth/defaultUser.ts`)
- `payload-migrations`, `payload-preferences`,
`payload-locked-documents`, `payload-kv`, `payload-jobs`,
`payload-jobs-stats`, `payload-query-presets`
**Templates** — `versions: false` added to all Users collections and all
globals (Header/Footer across ecommerce, website, with-vercel-website
templates)
**Codemods** (`packages/codemod/`)
- New `migrate-versions-default` transform — adds `versions: false` to
every `CollectionConfig` and `GlobalConfig` that does not already have a
`versions` property; covers `: Type`, `satisfies Type`, and `as Type`
annotation forms
- New `remove-versions-true` transform — removes the now-redundant bare
`versions: true` boolean from `CollectionConfig` and `GlobalConfig`
objects (object-form configs such as `versions: { drafts: true }` are
left untouched)
- Both transforms registered in `registry.ts` and documented in
`README.md`
**Docs**
- `docs/versions/overview.mdx` — updated banner and collection/global
config sections to reflect the opt-out model; added code examples for
both
- `docs/migration-guide/v4.mdx` — new breaking-change entry covering
both collections and globals, explaining the schema impact, and
documenting both codemod commands
This plugin adds support for MCP (Model Context Protocol) so you can use
Payload as an MCP server.
[Getting Started docs to
MCP](https://modelcontextprotocol.io/docs/getting-started/intro)
## Background
MCP Allows you to interact with with models via a streamlined protocol.
Developers can define allow retrieval on collections, create tools,
create resources, and create prompts that models can interact with.
This plugin uses:
[@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk),
[mcp-adapter](https://github.com/vercel/mcp-adapter)
## 🚀 Basic Setup
```typescript
import { buildConfig } from 'payload'
import { mcpPlugin } from '@payloadcms/plugin-mcp'
export default buildConfig({
// ... your existing config
plugins: [
mcpPlugin({
collections: {
posts: true,
},
}),
],
})
```
### With custom server options
```typescript
import { z } from 'zod'
import { mcpPlugin } from '@payloadcms/plugin-mcp'
export default buildConfig({
// ... your existing config
plugins: [
mcpPlugin({
collections: {
posts: true,
},
// Custom server options
mcp: {
handlerOptions: {
verboseLogs: true,
maxDuration: 60,
},
serverOptions: {
serverInfo: {
name: 'My Custom MCP Server',
version: '1.0.0',
},
},
},
}),
],
})
```
## Tools
These are the Payload tools you control through the Admin or Payload
config that LLMs use to interact with collection documents.
### Resources
| Tool | Description |
| ---------------------------------------------------- |
-------------------------------------- |
| `findResources`| Find documents in a collection |
| `createResource` | Create a new document |
| `updateResource` | Update documents by ID or where clause |
| `deleteResource`| Delete documents by ID or where clause |
### Custom Tools
You can include your own custom MCP tools as well.
```ts
import { z } from 'zod'
import { mcpPlugin } from '@payloadcms/plugin-mcp'
export default buildConfig({
// ... your existing config
plugins: [
mcpPlugin({
collections: {
posts: true,
},
mcp: {
// Add your own custom tools
tools: [
{
name: 'diceRoll',
description: 'Rolls a virtual dice with a specified number of sides',
handler: (args: Record<string, unknown>) => {
const sides = (args.sides as number) || 6
const result = Math.floor(Math.random() * sides) + 1
return Promise.resolve({
content: [
{
type: 'text' as const,
text: `# Dice Roll Result\n\n**Sides:** ${sides}\n**Result:** ${result}\n\n🎲 You rolled a **${result}** on a ${sides}-sided die!`,
},
],
})
},
parameters: z.object({
sides: z
.number()
.int()
.min(2)
.max(1000)
.optional()
.default(6)
.describe('Number of sides on the dice (default: 6)'),
}).shape,
},
],
},
}),
],
})
```
## Connectors
To connect to the MCP server as a connector via a client like VS Code,
Claude or Cursor:
```json
{
"mcpServers": {
"My Payload App": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"http://localhost:300/api/mcp",
"--header",
"Authorization: Bearer API_KEY_GOES_HERE"
]
},
}
}
```
## Testing your MCP endpoint
I highly recommend using `npx @modelcontextprotocol/inspector` to test
your MCP server.
Your default MCP endpoint is: `http://localhost:3000/api/mcp`
```bash
npx @modelcontextprotocol/inspector
```