feat(plugin-mcp)!: remove MCP API key collection and use Payload API keys directly#17041
feat(plugin-mcp)!: remove MCP API key collection and use Payload API keys directly#17041AlessioGr wants to merge 6 commits into
Conversation
📦 esbuild Bundle Analysis for payloadThis analysis was generated by esbuild-bundle-analyzer. 🤖
Largest pathsThese visualization shows top 20 largest paths in the bundle.Meta file: packages/next/meta_index.json, Out file: esbuild/index.js
Meta file: packages/payload/meta_index.json, Out file: esbuild/index.js
Meta file: packages/payload/meta_shared.json, Out file: esbuild/exports/shared.js
Meta file: packages/richtext-lexical/meta_client.json, Out file: esbuild/exports/client_optimized/index.js
Meta file: packages/ui/meta_client.json, Out file: esbuild/exports/client_optimized/index.js
Meta file: packages/ui/meta_shared.json, Out file: esbuild/exports/shared_optimized/index.js
DetailsNext to the size is how much the size has increased or decreased compared with the base branch of this PR.
|
|
We should be careful about mentioning Fixes #16572 when this is going to be done in v4 and I don't think we can carry the change back to Worth commenting on the issue when we close it unless you can think of a workaround. |
DanRibbens
left a comment
There was a problem hiding this comment.
I might just be too tired to review this, but I don't understand why there are different functions with same name having different arguments.
| const authHeader = req.headers.get('Authorization') | ||
| const hasBearerToken = authHeader?.startsWith('Bearer ') | ||
| }): Promise<TypedUser> => { | ||
| const user = headers ? (await req.payload.auth({ headers: new Headers(headers) })).user : req.user |
There was a problem hiding this comment.
is there a reason we don't pass req here?
| }) => { | ||
| export const getAuthorizedMCP: (args: { | ||
| req: PayloadRequest | ||
| skipAuth?: boolean |
There was a problem hiding this comment.
Here getAuthorizedMCP has skipAuth but the type MCPPluginConfig['overrideAuth']'s param of getAuthorizedMCP https://github.com/payloadcms/payload/pull/17041/changes#diff-45be06686d7e43f07662ff5d02b35c9e0c583bc9526b5d5000b10dbed9caedb7R240 doesn't.
Why does this function have a different signature than whats in the config?
This PR removes MCP-specific API key management and makes MCP use Payload API keys directly. While this is a UX downgrade in the short term, it will be beneficial in the long run because
MCP API key collection removed
The
payload-mcp-api-keyscollection is gone, along with its admin UI, settings-menu entry, access field, custom API-key field, empty state, and plugin-specific translations.There is no separate MCP key document anymore. MCP requests now authenticate as the Payload user attached to the API key.
Payload API key auth
HTTP MCP requests now use Payload's normal API-key header:
MCP accepts any Payload user authenticated through API-key auth. The old
userCollectionoption was removed, and the plugin no longer adds a default users collection implicitly. Fixes #16572Tool access
Tool visibility now comes from code instead of per-key admin settings.
Built-in collection and global tools follow Payload access control, so callers only see operation tools they can use. Tools, prompts, resources, and built-in tool overrides can also define a new
accesscallback for MCP-item-specific rules. This should be used instead of the previous API key collection, and can be used to build your own RBAC, which is how normal payload access control works.Migration
Enable
auth.useAPIKeyon the auth collection whose users should call MCP, then use those user API keys for/api/mcp.Existing
payload-mcp-api-keysdocuments no longer authenticate. The collection config has been removed and will need a database migration.overrideApiKeyCollectionanduserCollectionwere removed.