← Blog

How Authorization Works Across the Model Context Protocol

The Model Context Protocol gives a remote MCP server one job in OAuth terms: validate access tokens issued for it and reject the rest. That leaves the harder question, whether a given caller may reach a given tool, to a layer the spec does not define. This is an overview of how authorization works across MCP, where the OAuth 2.1 resource-server model helps, and why the HTTP path needs identity-aware enforcement and an independent audit record.

ByParminder Singh· Founder & CEO, DeepInspect Inc.
Problem-Awareagentic-aiai-securityidentity-and-authorizationllm-securitypolicy-enforcementzero-trust
How Authorization Works Across the Model Context Protocol

The Model Context Protocol's authorization specification, in its 2025-11-25 revision, gives a remote MCP server a single job in OAuth terms: act as a resource server that validates access tokens issued for it and rejects everything else. That one sentence hides most of the security surface. MCP connects an LLM or an agent to tools and data through MCP servers, and the protocol made authorization optional, so the question of who is allowed to reach which tool depends on choices each deployer makes. I want to walk through how authorization works across MCP and where the gaps sit.

What the Model Context Protocol connects

Anthropic published MCP in November 2024 as an open standard for wiring language models to external capability. An MCP host, such as Claude Desktop or an IDE assistant, runs one or more MCP clients, and each client connects to an MCP server that exposes tools, resources, and prompts. A filesystem server exposes read and write tools. A GitHub server exposes issue and pull-request tools. The model asks to call one, and the server executes it against the real system behind it.

Two transports carry that traffic, and the difference decides everything downstream. Local servers run over STDIO, launched as a child process on the same machine as the host. Remote servers run over Streamable HTTP, reachable across the network. The transport a server uses decides which authorization rules apply, and that split is the first thing to get straight before reasoning about MCP security.

The MCP authorization model

For HTTP transport, the spec treats the MCP server as an OAuth 2.1 resource server. It holds no login screen of its own. An external authorization server issues an access token, the client presents it on every request in a bearer header, and the server validates it before running anything.

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Discovery follows RFC 9728, so a client that calls without a token gets a 401 Unauthorized pointing at the server's protected-resource metadata, which names the authorization server the client should use. The token then rides an OAuth 2.1 authorization-code flow with mandatory PKCE, the tightening that the 2025-06-18 revision introduced over the earlier scheme. The OAuth mechanics deserve their own walkthrough, and I keep that separate from this overview.

Scopes carry the permissions, and a scope like files:read gates a class of operations. They are coarse and fixed at the moment the token is issued, while the sensitivity of an individual call shifts request by request. That mismatch is where authorization strain shows up.

Two authorization risks the spec names directly

The MCP authorization spec calls out two failure modes by name, and both are authorization problems wearing OAuth clothing.

The confused-deputy problem appears when an MCP server sits between a client and a third-party API. An attacker who obtains a stolen authorization code can, through a proxy server using static client IDs, get an access token issued without fresh user consent, then drive the server to act on data the end user never approved. The spec requires proxy servers to obtain user consent for each dynamically registered client to close that hole.

Token passthrough is the second. If an MCP server accepts a token minted for a different service, or forwards the token it received straight to a downstream API, the downstream system trusts a credential no one validated for it. The spec forbids this outright: a server "MUST NOT pass through the token it received from the MCP client," and MUST validate that a token names it in the audience claim, the binding RFC 8707 provides through the resource parameter. Both risks trace back to a server trusting a valid-looking token instead of deciding whether this specific caller may make this specific call.

HTTP servers and local STDIO servers split the enforcement problem

The spec draws a sharp transport line. HTTP-based servers SHOULD conform to the authorization specification. STDIO servers SHOULD NOT follow it, and instead retrieve credentials from the environment, because a local child process already inherits the trust of the user session that spawned it.

That split matters for anyone reasoning about MCP security posture. A remote HTTP MCP server exposes an authorization decision on inspectable network traffic. A local STDIO server runs as a process on the developer's laptop, its tool calls never crossing a network boundary an external control could read. The confused-deputy and token-passthrough risks above live on the HTTP path, since they turn on tokens moving between network parties. A poisoned local server is a process-execution and supply-chain problem on the host machine, handled by code review, sandboxing, and package trust, and it sits outside anything an HTTP proxy can see. Keeping those two worlds separate stops teams from buying a network control expecting it to fix a local-process risk, or the reverse.

Identity-aware authorization and audit belong on the HTTP path

On the remote path, token validation answers "is this a real token for this server." It leaves "is this authenticated caller, in this role, permitted to invoke this tool with these arguments right now" unanswered. Authentication is not authorization, and MCP's OAuth model is built to authenticate the client while delegating the permit decision. The per-tool-call invocation check is its own detailed subject, covered in the tool-call authorization breakdown; the broader point across MCP is that the decision has to happen somewhere on the HTTP path, evaluated per request against the acting agent identity.

The record matters as much as the ruling. An MCP server that logs its own authorization decisions is attesting to its own behavior, the self-attestation problem that fails under selective logging and crash-loss. A regulated deployment needs a per-decision record produced independently of the server. EU AI Act Article 12 requires automatic event logging over a high-risk system's lifetime, with timestamps, inputs, and the identities involved. An eval score or a server's own debug log falls short of that. My honest read is that most teams shipping MCP-connected agents this year have wired up the OAuth flow and skipped the independent record entirely, and the record is the part a market surveillance authority actually asks to see.

DeepInspect

This is the layer DeepInspect operates on. DeepInspect is a stateless proxy on the HTTP path between your authenticated agents and the remote MCP servers and model endpoints they call. It sits after OAuth has issued a token and evaluates the call the token is being used for: it resolves the acting identity, checks the specific tool and arguments against per-role policy, and returns a permit or deny decision before the request reaches the server. Enforcement runs under 50 milliseconds in internal testing, invisible against the network round trip and server-side execution a tool call already spends. It is model-agnostic and server-agnostic, applying one policy across many HTTP MCP servers.

Its boundary is worth stating plainly. DeepInspect authorizes and audits HTTP AI traffic to remote MCP servers and LLM endpoints. It does not secure local STDIO servers, local process execution, or a tool's own internal logic, because none of that crosses the HTTP path it inspects. What it adds on the traffic it does see is an identity-aware decision point and a signed per-decision audit record, committed ahead of the call on a write path neither the agent nor the server controls, independent of whether each server's own OAuth was configured correctly. For teams tracking how fast this surface is moving, I keep notes in the agentic AI news roundup. Book a demo today.

Frequently asked questions

What is the Model Context Protocol in one line?

MCP is an open standard Anthropic published in November 2024 that connects language models and agents to external tools, data, and prompts through MCP servers. A host application runs MCP clients, each client connects to a server, and the server exposes callable tools that act on real systems like a filesystem, a database, or a SaaS API. The protocol standardizes how the model discovers and invokes those tools so a single agent can reach many capabilities through one interface. Authorization is defined separately, and the spec makes it optional, which is why security posture varies widely across deployments.

How does MCP handle authorization?

For remote servers over HTTP, MCP treats the server as an OAuth 2.1 resource server. An external authorization server issues an access token, the client presents it as a bearer credential on every request, and the server validates that the token was issued for it before executing. Discovery uses RFC 9728 protected-resource metadata, the flow uses authorization-code with mandatory PKCE, and RFC 8707 resource indicators bind the token to its intended server, and scopes express coarse permissions. Local STDIO servers skip this entirely and read credentials from the environment, since a local process already runs under the user's session trust.

What are the main authorization security gaps in MCP?

The spec names two directly. The confused-deputy problem lets an attacker with a stolen authorization code obtain a token through a proxy server without fresh consent, then drive actions the user never approved. Token passthrough happens when a server accepts a token minted for another service or forwards a received token unmodified downstream, breaking the audience boundary. Underneath both sits a broader gap: a valid token proves the client was granted something, while whether this caller may make this specific call at this moment is a policy decision the token cannot express.

Does DeepInspect secure local MCP servers?

DeepInspect does not secure local MCP servers. It operates on HTTP AI traffic to remote MCP servers and model endpoints, where it authorizes each call against the acting identity and records the decision independently. A local STDIO server runs as a child process on the same machine as the host, and its tool calls never cross a network boundary DeepInspect can read. Securing local servers is a host-side concern handled through code review, sandboxing, dependency trust, and least-privilege on the machine. DeepInspect's contribution is the identity-aware enforcement point and audit trail on the remote HTTP path, independent of whether each server's own OAuth is configured correctly.

Why is OAuth token validation not enough for MCP authorization?

Token validation confirms the token is real and issued for this server. It does not decide whether the authenticated caller, in a given role, may invoke a given tool with given arguments at that moment. Scopes are coarse and fixed at issuance, so one valid token can front a harmless read and a destructive delete in the same session. Closing that requires a policy decision point that reads the token plus the acting identity context and evaluates the specific call per request. For a regulated program, that decision also needs a per-decision audit record produced independently of the server to satisfy Article 12-style logging obligations.