The Model Context Protocol (MCP) specification delegates transport security to OAuth 2.1, giving servers a standard way to verify caller identity. What the specification does not cover is what happens next: which tools the caller can invoke, which resources those tools can access, and how permissions are enforced at execution time.
This article examines the gaps that remain after a spec-compliant OAuth deployment, from API gateways that cannot evaluate tool payloads to native metadata fields that look like security controls but are not.
TL;DR
-
The MCP authorization spec secures the transport boundary with OAuth but deliberately omits application-level permission models.
-
Native metadata properties like
destructiveHintandreadOnlyHintare UI risk vocabulary, not security enforcement. -
Forwarding client tokens directly to downstream APIs violates the spec and creates confused deputy vulnerabilities.
-
Securing multi-step agent workflows requires centralized authorization checks mapped to specific tool capabilities before execution begins.
Why API gateways fall short for agent workflows
Many security architects place MCP servers behind OAuth 2.1 API gateways and map RBAC scopes to network routes. Gateways work for static services because they evaluate known paths against predictable requests. They fall short for autonomous agents because proxies cannot compute execution-time permissions for unpredictable read-and-write chains.
AI models formulate unique execution pathways based on prompt conditions and environmental feedback. An API gateway evaluating an inbound request cannot determine whether a specific agent, acting on behalf of a specific human, has clearance to invoke a high-risk tool against a specific database row. The proxy sees a valid token requesting broad access to a top-level endpoint. It lacks the context to separate a safe retrieval from a destructive deletion nested within the payload.
Some organizations try to mitigate proxy blindness by registering agent sessions dynamically in the identity provider. Many enterprise identity providers do not support Dynamic Client Registration for machine identities because unbounded automated registration creates identity blind spots and audit complications. Gateway frameworks cannot evaluate the contextual risk of autonomous database actions, which raises the question: what does the authorization protocol actually provide, and what does it leave undefined?
The zero-trust gap in the authorization specification
MCP provides authorization at the transport layer for HTTP-based environments, relying on the OAuth 2.1 framework to manage caller identity.
The spec mandates PKCE to prevent authorization code interception and requires clients to use Protected Resource Metadata (RFC 9728) for automatic authorization endpoint discovery. The MCP server acts strictly as a Resource Server, delegating all identity validation to an external authorization provider.
This hardens the transport and establishes strong authentication plumbing. But it intentionally ignores internal application models, tool-level boundaries, and execution-time access control. The OAuth flow verifies that the caller has a valid identity. It provides no answer about what that caller is allowed to do. Developers in zero-trust architectures frequently misinterpret this boundary and map backend permission models to generic metadata labels.
The falsifiability of native tool annotations
Developers frequently mistake UX metadata for security constraints. The protocol includes native property fields to categorize tools, tempting engineers to build backend logic around those string labels.
Using native properties as security barriers creates privilege escalation flaws. The MCP maintainers explicitly warn that properties like readOnlyHint and destructiveHint function as risk vocabulary to trigger human approval dialogs on the client. They are not authorization enforcement.
Building backend defenses around client-side hints allows a compromised agent to bypass the UI check and submit destructive payloads directly. Early enterprise integrations suffered privilege escalation because custom properties lacked backend enforcement. The server must compute its own source of truth about who can invoke which tools, independent of self-reported metadata from the client. Trusting fabricated annotations leads to unauthorized data access, and forwarding those assumed privileges to third-party endpoints compounds the problem.
The token passthrough trap and the confused deputy
Connecting an agent to remote services requires bridging the authorization gap between local resources and external service boundaries. Engineers frequently attempt this by extracting the inbound client token and passing it directly to the downstream system.
Passing a user's token directly to an external service violates the spec and creates a confused deputy vulnerability. The specification forbids credential forwarding because placing the user's primary credential in an agent payload obscures the true identity chain. If an attacker compromises the agent, the forwarded token lets the attacker act as the delegating human across connected platforms. Mapping broad scopes to unpredictable agents strips away the ability to distinguish between human operators and automated components.
The spec requires audience binding via Resource Indicators (RFC 8707). Servers must reject any token minted for a different downstream resource. For external access, the architecture requires URL-mode elicitation flows, where the server maintains a distinct client flow isolated from the original connection to prevent credential propagation across service boundaries.
Binding agent identity with execution-time enforcement
Preventing caller identity confusion requires mapping permissions to invocation parameters and running authorization checks before the tool executes. Architectures that chain multiple tools on behalf of a single user carry significant authorization risks.
The National Institute of Standards and Technology identifies the challenges involved in binding autonomous agent provenance to an originating human identity across zero-trust workloads. Operators consistently fail to isolate permissions when delegation chains extend beyond single calls. Recent academic research confirms that MCP servers suffer caller identity confusion during chained transactions because persistent authorization states allow tool invocations without re-authentication regardless of the caller.
Engineers should add per-tool authorization checks inside the application code. Before invoking a protected function, the backend queries a dedicated permissions system to verify that the authenticated user has access to the specific resource the tool targets. This check runs at execution time, not at session establishment, so permissions stay current even as agents chain through multiple operations.
Relationship-based access control (ReBAC) fits this pattern because it models permissions as a graph connecting users, roles, and resources. Instead of checking a flat scope string, the authorization layer traverses relationships: does this user belong to a team that owns this project, and does that project grant read access to this database table? The graph evaluates per-resource and per-action, so a single compromised tool invocation cannot escalate into broad data access.
Google's internal authorization system, Zanzibar, pioneered this model for managing permissions across billions of users and resources. AuthZed implements the Zanzibar model as an infrastructure layer, where the application sends a permission check paired with the user identity and target resource at each tool invocation. The check returns a decision in milliseconds, keeping authorization off the critical path for real-time agent coordination.
Moving authorization upstream of execution
Correct network authorization gets callers through the firewall edge but leaves agent payloads unchecked inside the application boundary. Because agent workflows trigger dynamic chains of operations, engineers must decouple initial identity establishment from runtime permission evaluation.
Extracting authorization decisions out of application code into a dedicated system means every tool invocation carries an enforceable boundary, regardless of how many agents or services participate in the chain. The transport layer proves identity. The authorization layer determines what that identity is allowed to do. Teams building MCP servers need both layers in place before agents reach production.
FAQs
Can I use an API gateway to secure my server implementations?
Gateways restrict broad access using coarse scopes, but they cannot evaluate contextual permissions for specific chained execution paths. Static services follow predictable request patterns; autonomous agents do not. A proxy cannot determine whether a specific tool invocation on a specific row is authorized for a specific user.
Why does the specification forbid token passthrough?
Forwarding a user's token to an external service obscures who is actually making the request and creates a confused deputy vulnerability. The spec mandates resource indicators (RFC 8707) to bind tokens to specific audiences and prevent cross-service credential reuse.
What is URL-mode elicitation?
URL-mode elicitation is the approved pattern where the MCP server orchestrates a separate authentication flow for downstream services, independent of the original client connection. This prevents session credentials from propagating across service boundaries.
Can read-only hints prevent destructive database operations?
No. Tool annotations like readOnlyHint and destructiveHint trigger confirmation dialogs in the client UI. They do not enforce anything on the server. A compromised agent can bypass the UI and submit destructive requests directly.
Why do security teams object to dynamic registration for machine identities?
Allowing automated agents to self-register creates uncontrolled scaling of client identities that are difficult to audit. Many enterprise security teams disable dynamic registration because the resulting identity sprawl degrades their ability to track and attribute agent actions.