Skip to content
sign in

==> read the decisions

ADR-0020: The API issues its own tokens; MCP clients register by metadata document, never dynamically

Status: Accepted (2026-10-15). Amends ADR-0005: the MCP door it deferred is specified here; personal access tokens stand. Partly implemented 2026-10-15: a new personal access token asks for a fresh sign-in; the authorization server (MCP, the docs' try-it) is not built yet.

Three kinds of program call the API: scripts and tools with a personal access token (cs_pat_…, ADR-0005), MCP clients (which the MCP specification requires to obtain OAuth 2.1 access tokens), and the documentation host's "try it" calls (ADR-0022). Sign-in moves to an identity provider (ADR-0019), so the question is which server issues the tokens these programs carry.

The MCP authorization specification (2026-07-28 revision) asks the authorization server for: Client ID Metadata Documents (SHOULD) or pre-registered clients; dynamic client registration (RFC 7591) only as a deprecated fallback; PKCE; tokens bound to the MCP server named in the resource parameter (RFC 8707), with the audience checked; protected resource metadata (RFC 9728) and server metadata (RFC 8414). Of the Postgres-backed identity providers evaluated, none supports metadata documents, and Authentik has no client registration of any kind.

  • Identity and authorization are separate. The identity provider answers "who is this"; the API is the authorization server for its own tokens and delegates every sign-in to the provider.
  • Personal access tokens are unchanged: one kind, no scopes, issued, hashed, listed and revoked by the API. Creating one requires a fresh confirmation with a passkey or TOTP at the provider, so a token cannot be minted from a session that only ever saw a weaker factor.
  • MCP clients obtain tokens from the API's OAuth endpoints:
    • registration by Client ID Metadata Document or by pre-registration only. There is no dynamic client registration endpoint, now or later;
    • authorization code with PKCE (S256 only), exact redirect-URI matching, iss in the response;
    • access tokens are short-lived, bound to the MCP server's URI from resource and checked for that audience; refresh tokens rotate on use;
    • the MCP server publishes protected resource metadata; the API publishes server metadata.
  • The metadata fetch is hardened. Fetching a client's metadata document is a request the server makes to a URL the client chose, from a host that can reach internal networks. It is limited to https, to public addresses checked after resolution, with no redirects, a size limit and a timeout.
  • The consent screen shows where a client comes from: the metadata document's host, prominently, not only the name the document claims.
  • The documentation host is a pre-registered client. Its "try it" obtains a short-lived token for api.<domain> the same way, without a prompt when the visitor is signed in (ADR-0022).
  • A vetted OAuth server library implements the protocol; the platform writes the policy around it, not the protocol.
  • The identity provider can be chosen for sign-in alone; MCP does not constrain it.
  • MCP clients that only support dynamic registration cannot connect. That is accepted: it is the deprecated path.
  • The API owns a small, security-critical OAuth server: its tests cover the metadata fetch limits, redirect matching, PKCE, audience checks and refresh rotation.
  • A later device flow for command-line tools fits the same endpoints.
  • The identity provider as the MCP authorization server. None of the candidates supports metadata documents; one that offers open dynamic registration ignores resource, so every registered client shares one audience.
  • Dynamic client registration. Deprecated by the specification, and an open endpoint anyone may call.
  • Scoped personal access tokens. Kept simple on purpose: one kind of token, full reach, revocable.