The previous lesson covered local, stdio-transport servers, where the spec explicitly says to skip OAuth and just pull credentials from the environment. A "business bot" is usually the opposite case: an MCP server running on shared infrastructure, reachable over HTTP by multiple people or downstream systems. That's the case MCP's authorization specification actually targets, and it's built entirely on existing, well-audited standards rather than a custom scheme — primarily OAuth 2.1, plus a handful of supporting RFCs for metadata discovery and resource binding.
The roles
MCP maps cleanly onto standard OAuth roles: the MCP server is the resource server (it accepts requests with an access token and decides whether to honor them), the MCP client is the OAuth client (it obtains tokens on behalf of a user), and a separate authorization server issues the tokens — it can be run by the same team as the MCP server or be a third party entirely. A client that gets a 401 Unauthorized from an MCP server is expected to discover where that authorization server lives (via a WWW-Authenticate header or a well-known metadata URL), then run a standard OAuth 2.1 authorization-code flow with PKCE to get a token.
Why tokens have to be audience-bound
The part of this that actually matters for security — more than the flow itself — is what the spec calls audience binding. Every access token has to be requested and issued for one specific MCP server (its canonical URI, e.g. https://mcp.example.com), and that server must reject any token that wasn't issued for it. Without this, a token stolen from or leaked by one internal tool could be replayed against a completely different one. The spec is equally strict about the reverse direction: if your MCP server calls out to some other upstream API on the user's behalf, it must get its own separate token for that upstream call — it must never just forward the token it received from the client. Doing so creates what the spec calls a "confused deputy" — the upstream service ends up trusting a token it never actually validated came from a legitimate request.
| Transport | Auth approach per spec | Why |
|---|---|---|
| Stdio (local process) | Credentials from the environment; no OAuth | You already trust the process enough to have spawned it locally |
| HTTP (remote/shared server) | OAuth 2.1, with PKCE and audience-bound tokens | Multiple untrusted clients may reach the same server over a network |
For a business deployment specifically, this means: don't invent your own API-key header scheme for an internal MCP server that multiple teams or bots will call. Stand up (or reuse) a real OAuth 2.1 authorization server, issue short-lived tokens scoped to what each caller actually needs, and make sure your MCP server validates the audience claim on every request — the spec treats skipping that validation as the primary way these deployments get compromised.
Practical Challenge
Sketch the 401 response your MCP server would return for an unauthenticated request, including a WWW-Authenticate header pointing to a resource_metadata URL — then trace what a compliant client would fetch next.
Concept Check
Sources & Further Reading
- MCP Specification — Authorization — the official spec defining OAuth 2.1-based auth for HTTP-transport MCP servers, including audience binding (RFC 8707), PKCE requirements, and the token-passthrough / confused-deputy prohibition.
AI