MCP OAuth: how remote-server auth works
Local servers skip auth entirely. The moment you go remote, OAuth 2.1 shows up — here's exactly what it's doing and why the flow looks the way it does.

MCP OAuth is how a remote MCP server proves you authorized the agent to act on your behalf — using OAuth 2.1, a redirect to the service's login page, and a scoped access token the client attaches to every request. If you only run local servers, you have never seen it: about 90% of MCP servers run locally over stdio and need no auth at all. OAuth is the price of going remote.
This matters because the ecosystem is drifting toward hosted servers, and the auth story is genuinely different from a static API key. Below is what the flow actually does, what the 2.1 spec makes mandatory, and where clients still trip.
When you actually hit OAuth (and when you don't)
You hit OAuth only with remote MCP servers that choose it. Local stdio servers borrow your machine's existing trust and skip auth entirely.
Three servers from our catalogue show the whole spectrum. The Filesystem reference server is stdio with authType: none — it's confined to directories you pass as arguments, so there's nothing to log into. Context7 has a hosted endpoint at https://mcp.context7.com/mcp but uses an optional API key, not OAuth — a static-key remote. The GitHub MCP Server is the OAuth case: run it locally via Docker with a personal access token, or connect to GitHub's hosted server at https://api.githubcopilot.com/mcp/ over OAuth.
That GitHub split is the whole argument for OAuth in one server. A PAT is a long-lived credential sitting in your config; the hosted variant hands you a short-lived, scoped token and never stores a standing secret on disk.
What the OAuth 2.1 flow does, step by step
The flow is authorization-code-with-PKCE — the same pattern a well-built mobile app uses, adapted so the client is your MCP host (Claude, Cursor, VS Code) rather than a browser SPA. Here's the sequence:
- Discovery. The client hits the server, gets a
401with aWWW-Authenticateheader pointing at the authorization server, then reads its metadata (/.well-known/oauth-authorization-server) to learn the authorize and token endpoints. - Registration. If the client isn't pre-registered, it can register itself via Dynamic Client Registration — no manual client-ID copy-paste.
- Authorize. The client opens the service's login page in your browser. You approve the requested scopes. This is the only human step.
- Callback + token exchange. The service redirects back with an authorization code; the client exchanges it (plus its PKCE verifier) for an access token and usually a refresh token.
- Call. Every MCP request now carries
Authorization: Bearer <token>. When it expires, the client silently refreshes.
The part people miss: the MCP server is the resource server, and it may not be the authorization server. GitHub's login is separate from the MCP endpoint you're calling. That separation is exactly what the 2.1 spec formalizes.
What the spec makes mandatory
MCP's auth spec is built on OAuth 2.1, and 2.1 removes the footguns that made classic OAuth 2.0 easy to get wrong. Three requirements matter to anyone shipping or debugging a server:
| Requirement | What it means | Why it's mandatory |
|---|---|---|
| PKCE on every flow | Client sends a hashed code_challenge, proves it later with the code_verifier | Stops a stolen authorization code from being redeemed by anyone else |
| Exact redirect-URI match | No wildcard or prefix matching on the callback URL | Closes open-redirect token theft |
| Resource indicators (RFC 8707) | Client names the target MCP server as the resource when asking for a token | The token is bound to that server, so a malicious server can't replay it elsewhere |
The resource-indicator rule is the one most specific to MCP. Because a host may talk to many servers, a token minted for server A must not be usable against server B. RFC 8707 audience-binding is how the spec prevents a confused-deputy attack between servers. If you're evaluating a remote server, this is the box to check.
Implied-grant and password-grant flows are gone in 2.1. If a server asks for your username and password directly instead of redirecting you to the real login page, that's not MCP OAuth — treat it as a red flag.
What clients handle for you — and where they don't
Good news: for the whole flow above, the client does the work. You click "connect," a browser tab opens, you approve, and the token lifecycle (storage, refresh, attaching the header) is invisible. Adding a remote server is usually a URL plus a one-time login — see how to add an MCP server for the mechanics per client.
Where it still breaks in mid-2026:
- Uneven client support. Not every host implements Dynamic Client Registration or metadata discovery. A server that assumes them will fail in a client that doesn't, with an opaque
401. - Localhost callbacks. Desktop clients listen on a loopback port for the redirect; a firewall or a hijacked port produces a hang, not an error.
- Scope surprises. You approve broad scopes at login and forget. OAuth's advantage over a PAT is scoping, but only if you read the consent screen.
OAuth also doesn't make a server trustworthy — it only proves who's calling. What the server does with your authorized access is a separate question, and MCP security is where the real risk lives. A scoped token in front of a tool that will read arbitrary URLs is still a prompt-injection surface.
Should you prefer OAuth servers?
For anything that acts on your behalf against a real account — GitHub, a calendar, a CRM — yes, prefer the OAuth remote over pasting a long-lived token. You get short-lived credentials, real scopes, and revocation from the provider's dashboard, and nothing sensitive sits in a config file. That's why OAuth is disproportionately the auth model on official vendor servers: the vendor is the one who can host the authorization server correctly.
But don't go remote just to get OAuth. If a local stdio server already does the job with your existing CLI credentials, that's the more private default — no third party sees your traffic. Reserve remote-plus-OAuth for the cases where a hosted server earns it: team sharing, no local runtime, or a token you'd rather not store. Weigh it the same way you'd weigh any local vs remote MCP decision, and browse the best MCP servers for OAuth-capable options before you commit.