Auth
One declaration at the top level of the manifest secures both the manifest fetch and every tool call by default.
A tool may set its own auth to override the server-level default — needed when a tool’s url points at a different domain than the manifest — but the common case declares it once. Three modes, the same tiers MCP itself supports.
{ "type": "none" }
No auth. The manifest is fetched with a plain GET; tool calls carry no injected header.
{ "type": "header", "header": "Authorization", "scheme": "Bearer" }
A static shared secret, attached as <header>: <scheme> <secret> (or just <header>: <secret> if scheme is omitted). The manifest never contains the secret itself — only its shape. The literal value is something the client operator configures when they register the server.
const client = createRcpClient({
auth: { type: 'header', secret: process.env.SERVER_TOKEN! },
});{ "type": "oauth2", "resource": "https://api.example.com" }
Full OAuth 2.1, specified as the same RFC set MCP’s own authorization spec uses: Protected Resource Metadata (RFC 9728), Authorization Server metadata (RFC 8414), Dynamic Client Registration (RFC 7591), PKCE (RFC 7636), and Resource Indicators (RFC 8707) so a token is scoped to this server specifically.
oauth2 is not implemented by the reference client yet — it throws immediately at createRcpClient(). Use 'none' or 'header' for now.Client-injected headers
Separate from auth and resolvers, a client can attach headers to any outgoing request that don’t correspond to any declared param at all — a correlation id, a protocol-version echo, anything the client’s own tracing needs.
const client = createRcpClient({
headers: {
'X-Request-Id': () => crypto.randomUUID(),
'X-RCP-Version': () => '0.1',
},
});A server must ignore headers it doesn’t recognize rather than rejecting the request — a client is always free to add more later without that being a breaking change.