MCP clients
Let Claude Code, Claude, ChatGPT, VS Code and Cursor sign in to your MCP server with your users' own accounts.
The MCP authorization spec
is OAuth 2.1: the client discovers your authorization server, registers itself (RFC 7591), sends the
user to your login with PKCE, and gets a token bound to your MCP server (RFC 8707). With mcp: true
AuthKit is that authorization server, with nothing else to wire:
defineConfig({
// ...
mcp: true,
})claude mcp add --transport http acme https://acme.com/mcpClaude Code opens the browser, the user signs in to your app, sees a consent screen naming the client and what it asks for, and is connected.
What mcp: true turns on
- Dynamic registration, open but restricted to the redirects of the known MCP clients: loopback
(Claude Code and other CLIs),
https://claude.ai/api/mcp/auth_callback,https://claude.com/api/mcp/auth_callback,https://chatgpt.com/connector_platform_oauth_redirect,https://vscode.dev/redirect(and insiders), and thecursor/vscodeapp schemes. AdynamicRegistrationyou declare yourself takes precedence. - Refresh tokens for those clients. A client registered with the
refresh_tokengrant getsoffline_accessandprompt=consenton its authorize, so the user consents once and stays connected. Static clients and clients created in the console or CLI are untouched — only clients registered through/regcarryclient_id_issued_at. - Tokens bound to your MCP server. The
resourcea client names must be one of yours, and the token carries it asaud. Your servers come frommcp.resourcesand from runtime registration: the MCP server of@adonis-agora/agentregisters itself at boot, so its URL is never repeated here. - RFC 8414 metadata at the root: with the issuer at
https://acme.com/oidc, the document is also served athttps://acme.com/.well-known/oauth-authorization-server/oidc, where MCP clients look first.
The consent screen shows the client_name the client registered (escaped — registration is open)
and the scopes it asked for, and the account's Connected apps page lists clients by that name,
each revocable.
Options
mcp: {
// extra redirects, added to the known clients
redirectUris: { exact: ['https://my-client.example/callback'], appSchemes: ['zed'] },
// MCP servers that do not register themselves (another app, another process)
resources: ['https://tools.acme.com/mcp'],
}Your own MCP server
A server that is not @adonis-agora/agent's registers its URL the same way, then serves the RFC 9728
protected-resource metadata and checks the token's aud:
import { registerOAuthResource } from '@adonis-agora/authkit-server'
registerOAuthResource({ url: 'https://acme.com/mcp' })
// or, when the public URL is only known per request, a path on the issuer's origin:
registerOAuthResource({ path: '/mcp' })