warmplane 0.7.1

Local control plane that keeps MCP sessions warm with compact capability/resource/prompt facades.
# Complete Implementation Reference for Model Context Protocol (MCP) Authorization

## The Architectural Evolution of MCP Authorization

The Model Context Protocol (MCP) has fundamentally reshaped the integration landscape between Large Language Model (LLM) applications and external computational tools or disparate data silos. Conceived as a standard heavily inspired by the Language Server Protocol (LSP), MCP establishes a ubiquitous framework allowing diverse AI systems—acting as hosts—to seamlessly request context and trigger actions across distributed systems1. As the protocol matured, reaching its milestone November 2025 specification release, a critical paradigm shift occurred: the transport layer transitioned from a stateful connection architecture to a completely stateless model. This evolution, standardized under Specification Enhancement Proposal (SEP) 2575, removed protocol-level sessions and required every request to carry its own protocol version, client identity, and capability declarations2.

In this stateless, highly distributed environment, securing the interactions between an autonomous agent and a protected backend resource became the paramount engineering challenge. The MCP authorization specification was designed specifically to address this complexity at the transport layer, specifically targeting HTTP-based transports such as Streamable HTTP and HTTP with Server-Sent Events (SSE)4. Implementations utilizing standard input/output (STDIO) channels are explicitly excluded from this specification, as they rely on local environmental credential provisioning or operating system boundaries rather than network-level authorization flows5.

Rather than attempting to invent a novel cryptographic identity framework, the MCP architectural committee anchored the authorization standard deeply within the existing Internet Engineering Task Force (IETF) OAuth 2.1 ecosystem4. This foundational design choice ensures that implementers can leverage battle-tested security paradigms while minimizing the friction of integrating with massive enterprise Identity Providers (IdPs) such as Microsoft Entra ID, Auth0, AWS Cognito, and Okta7. However, recognizing the unique challenges of agentic workflows—where clients may iterate through loops hundreds of times or interact with previously unknown servers dynamically—the MCP specification enforces a highly specific subset of these standards, heavily augmenting them with modern mitigations against confused deputy scenarios, authorization mix-up attacks, and token leakage9.

## Normative Standards and Ecosystem Roles

To architect a compliant MCP authorization flow, implementers must build upon a constellation of specific normative standards4. The integration of these specifications forms the structural backbone of the security model.

|   |   |   |
|---|---|---|
|Standard Designation|Specification Title|Functional Role within MCP Authorization|
|OAuth 2.1 (Draft)|The OAuth 2.1 Authorization Framework|Governs the baseline authorization code flow, token issuance, and bearer token usage, functioning as the underlying transport security mechanism.|
|RFC 9728|OAuth 2.0 Protected Resource Metadata|Allows an MCP server to advertise the location of its trusted Authorization Servers to a connecting client via initial connection challenges.|
|RFC 8414|OAuth 2.0 Authorization Server Metadata|Provides the precise mechanism for clients to discover the specific endpoints (e.g., token, registration) supported by a chosen Authorization Server.|
|RFC 8707|Resource Indicators for OAuth 2.0|Mandates the inclusion of a resource parameter to strictly bind access tokens to specific target resources, preventing cross-service token replay.|
|RFC 9207|OAuth 2.0 Authorization Server Issuer Identification|Mitigates authorization mix-up attacks by requiring the validation of an explicit issuer claim during the authorization callback phase.|
|IETF Draft|OAuth Client ID Metadata Documents (CIMD)|Introduces a decentralized, domain-backed attestation approach for client identity, replacing legacy centralized registration databases.|
|RFC 7591|OAuth 2.0 Dynamic Client Registration Protocol|A legacy, but optionally supported, protocol enabling clients to programmatically register with an Authorization Server to obtain credentials.|

Within this interconnected ecosystem, the MCP specification defines three strict operational roles4.

The Protected MCP Server assumes the role of the OAuth 2.1 Resource Server. It does not authenticate users directly; rather, it intercepts incoming requests, validates the cryptographic integrity and audience binding of presented access tokens, and enforces granular access control policies before executing a tool or returning context5.

The MCP Client assumes the role of the OAuth 2.1 Client. This entity acts on behalf of the resource owner (the user), detects when authorization is required, securely orchestrates the user-facing authorization flow, and manages the lifecycle of the resulting access and refresh tokens. Examples include desktop IDEs, CLI agents like Claude Code, or web-based chat interfaces4.

The Authorization Server (AS) manages the identity lifecycle. It is solely responsible for authenticating the end-user, presenting a consent interface detailing the requested scopes, and subsequently minting the OAuth tokens. The AS may be tightly coupled and hosted alongside the MCP server, or it may operate as a wholly independent, centralized entity managed by an enterprise IT department4.

## Phase 1: Dynamic Authorization Server Discovery

The foremost operational challenge in the MCP ecosystem occurs when a client attempts to connect to a protected server for the first time. The client possesses no prior knowledge of the server's security topology and must dynamically discover the correct Authorization Server to interact with4. This bootstrapping phase is handled through a highly deterministic sequence governed by RFC 9728 and RFC 84144.

### The Initial Handshake and Protected Resource Metadata

When an unauthenticated MCP client initiates an HTTP request against a protected MCP server, the server must reject the attempt by returning an HTTP 401 Unauthorized status code13. Under the core MCP specification, this 401 response must contain a WWW-Authenticate header conforming to RFC 6750, extended to include a resource_metadata parameter. This parameter explicitly dictates the Uniform Resource Identifier (URI) where the client can retrieve the server's Protected Resource Metadata (PRM) document13.

The engineering implementation of this mechanism frequently causes friction, particularly in multi-tenant or path-routed infrastructures. According to RFC 9728 Section 3.1, the location of the PRM document is not universally static; it depends entirely on the specific resource identifier of the MCP server. If the MCP server's base URL contains a path component, the .well-known/oauth-protected-resource suffix must be systematically inserted precisely between the host component and the path15.

|   |   |
|---|---|
|Resource Server Identifier|Compliant RFC 9728 Metadata URL Construction|
|https://api.example.com|https://api.example.com/.well-known/oauth-protected-resource|
|https://api.example.com/mcp|https://api.example.com/.well-known/oauth-protected-resource/mcp|
|https://tenant.example.com/v1/agents|https://tenant.example.com/.well-known/oauth-protected-resource/v1/agents|

Failure to execute this path insertion correctly results in catastrophic discovery failures. Historical implementations in early SDKs, such as issues logged in the Python SDK (Issue #1400), demonstrated that appending the well-known suffix to the end of a path-based URL resulted in clients receiving HTTP 404 Not Found errors, as the server attempted to host the metadata at the root while instructing the client to fetch it from the path suffix15.

Furthermore, as standardized in SEP-985, the requirement for the server to emit the WWW-Authenticate header was relaxed from a MUST to a SHOULD. This strategic deviation recognized that in massive enterprise environments utilizing centralized API gateways, dynamically injecting headers from downstream backend services introduces profound architectural complexity3. Consequently, if a client receives a 401 Unauthorized response lacking the resource_metadata parameter, the client implementation is mandated to independently probe for the PRM document at the constructed .well-known location as a fallback mechanism3.

Client SDKs must be meticulously engineered to persist this discovered PRM URL. A critical bug identified in the TypeScript SDK (Issue #1450) revealed that the client correctly parsed the WWW-Authenticate header during the initial 401 challenge but failed to persist the extracted resource_metadata URL in the transport state7. When the user completed the authorization flow and the client invoked its finishAuth() routine to exchange the code for a token, the variable was undefined. The SDK then erroneously fell back to using the MCP server's base URL as the token endpoint, sending sensitive authorization codes directly to the resource server instead of the IdP (like AWS Cognito), resulting in immediate failure7.

### Authorization Server Endpoint Discovery

Once the PRM document is successfully fetched, the client parses the JSON payload to extract the authorization_servers array13. If multiple servers are listed, the client executes selection logic to choose one. The client must then ascertain the precise capabilities and endpoints of that specific Authorization Server utilizing RFC 84145.

To ensure robust interoperability across diverse IdP architectures, the MCP specification requires clients to attempt discovery against multiple well-known endpoints in a rigid priority sequence. The client first attempts RFC 8414 discovery with path insertion (https://auth.example.com/.well-known/oauth-authorization-server/tenant1). If that fails, it must fall back to OpenID Connect Discovery 1.0 utilizing path appending (https://auth.example.com/tenant1/.well-known/openid-configuration). Finally, it must attempt the root RFC 8414 location14.

A critical edge case arises when reverse proxies intercept these discovery probes. If a client queries an endpoint and the infrastructure returns an HTTP 200 OK status but serves a non-JSON payload, such as a static HTML catch-all page, the client must structurally treat this as an endpoint failure and gracefully proceed to the next priority URL in the sequence17. The final validation step requires the client to examine the JSON response and ensure that the issuer claim perfectly matches the base URL utilized to construct the discovery probe; a mismatch indicates potential spoofing, and the metadata must be immediately discarded14.

## Phase 2: Client Identity and Decentralized Registration Paradigms

Following successful discovery of the Authorization Server, the MCP client must identify itself to initiate the user consent flow. In traditional OAuth ecosystems, this requires the client to possess a client_id provisioned by the IdP. The dynamic nature of MCP, where users continually connect local agents to previously undiscovered enterprise servers, renders manual provisioning highly impractical. To resolve this, the specification supports three distinct registration paradigms, prioritizing decentralized trust models4.

|   |   |   |   |
|---|---|---|---|
|Registration Mechanism|Technical Implementation|Primary Application Scenario|Ecosystem Status|
|Client ID Metadata Documents (CIMD)|The client identifier is a self-hosted HTTPS URL pointing to a static JSON metadata file.|Dynamic discovery where no prior relationship exists between the client and server.|Recommended (SHOULD support). Resolves operational IdP bloat.|
|Pre-registration|The client identifier is manually provisioned by an administrator within the IdP dashboard.|Rigid enterprise environments utilizing platforms like Entra ID or Okta.|Required fallback when decentralized trust is prohibited by organizational policy.|
|Dynamic Client Registration (DCR)|The client programmatically POSTs its metadata to a /register endpoint to receive an identifier.|Legacy programmatic systems requiring backward compatibility.|Deprecated (MAY support). Susceptible to unbounded database attacks.|

The ascendancy of Client ID Metadata Documents (CIMD) addresses profound operational flaws associated with Dynamic Client Registration (DCR). In a DCR model, every unique instance of an MCP client (such as every individual user's installation of an IDE) hitting the /register endpoint forces the IdP to generate and store a new database record10. Because these programmatic endpoints often lack authentication requirements, they are highly susceptible to malicious actors generating unbounded database growth. Furthermore, DCR provides no standardized mechanism for credential expiration or lifecycle management, leaving IdPs littered with orphaned records10.

CIMD elegantly sidesteps these issues by shifting the trust paradigm from an active database to a domain-backed attestation10. Under this draft IETF specification, the client_id itself is an HTTPS URL (e.g., https://agent.example.com/oauth.json). When the AS receives an authorization request featuring a URL-formatted client identifier, it dynamically fetches the document via a standard HTTP GET request10.

The metadata document must be a strictly formatted JSON object containing the exact client_id URL, a human-readable client_name for the consent screen, and an array of valid redirect_uris18. This approach provides a profound security advantage: it cryptographically binds the requested redirect URIs to the client identity via the TLS certificate of the hosting domain19. The AS can inherently trust that the callback URIs are controlled by the entity owning the domain, significantly mitigating redirect manipulation attacks common in self-asserted registration schemas19.

Despite its architectural superiority, CIMD is not universally supported by legacy enterprise IdPs. For example, environments secured by Microsoft Entra ID currently support neither CIMD nor unauthenticated DCR. Consequently, if a user attempts to connect a dynamically generated agent, such as Claude Code, to an Entra-protected MCP server, the flow inherently fails because the agent lacks an application registration and cannot dynamically provision one8. In these rigid deployments, administrators must fall back to Pre-registration, manually configuring the application and distributing the static client_id to the end-users10.

Regardless of the registration methodology, MCP clients must rigorously enforce Authorization Server binding. If an MCP server updates its Protected Resource Metadata to indicate a transition to a completely new Identity Provider, the client must instantaneously detect this change based on the updated issuer identifier. The client must never attempt to reuse client credentials or tokens provisioned by the previous AS; it must flush its localized state and re-execute the registration protocol with the newly designated provider18.

## Phase 3: Executing the Cryptographically Bound Authorization Flow

With the client identity established, the system transitions to the execution of the OAuth 2.1 Authorization Code flow. Because MCP clients are frequently installed locally and rely on loopback interfaces, they operate in highly hostile threat environments. The specification mandates a sequence of structural extensions to the baseline OAuth flow to cryptographically bind the request, the response, and the resulting tokens, preventing interception and replay attacks11.

### Code Interception and Proof Key for Code Exchange (PKCE)

All MCP clients, without exception, are strictly categorized as public clients requiring the implementation of the Proof Key for Code Exchange (PKCE) protocol, utilizing the S256 hashing algorithm6. During the initial authorization request, the client generates a high-entropy secret known as the code_verifier and transmits its cryptographic hash, the code_challenge, to the AS11.

When the user grants consent, the AS returns the authorization code to the client's redirect_uri. If an attacker has compromised the local machine and intercepts this code by binding to an overlapping localhost port, they remain powerless; exchanging the code for an access token requires presenting the original, unhashed code_verifier directly to the token endpoint11. Without the original secret, the intercepted code is rendered useless, neutralizing a massive class of credential theft vulnerabilities.

### Enforcing Token Audience via Resource Indicators

A severe vulnerability prevalent in highly distributed, multi-agent architectures is the "Confused Deputy" problem. In this scenario, an attacker tricks a legitimate client into acquiring a token for an insecure resource, intercepts that token, and subsequently replays it against a highly sensitive resource11. To eradicate this attack vector, the MCP protocol mandates the strict implementation of Resource Indicators for OAuth 2.0 (RFC 8707)20.

MCP clients must explicitly include the resource parameter in both the initial authorization request and the subsequent token exchange request4. This parameter must be populated with the exact canonical URI of the MCP server, perfectly matching the resource identifier provided during the PRM discovery phase20. The URI must strictly include the scheme (e.g., https://) and host components; omitting the scheme renders the parameter functionally invalid4.

By asserting the resource indicator, the client explicitly forces the Authorization Server to encode the MCP server's URI directly into the resulting access token, typically within the aud (audience) claim5. This cryptographic binding ensures that the minted token is completely unique to the target environment and structurally useless if replayed against any other API or MCP deployment. Clients must supply this parameter unconditionally, irrespective of whether the AS discovery metadata explicitly advertises support for RFC 870720.

### Mitigating Mix-Up Attacks via Issuer Identification (SEP-2468)

In complex enterprise environments, a single MCP client might concurrently maintain connections with dozens of distinct servers, each backed by a different Identity Provider. This topology introduces the risk of Authorization Mix-Up attacks, where an attacker intercepts the flow and tricks the client into transmitting an authorization code minted by a legitimate IdP directly to an attacker-controlled token endpoint22.

To neutralize this threat, the MCP specification integrates RFC 9207 (Authorization Server Issuer Identification), detailed under Specification Enhancement Proposal (SEP) 24682. This integration introduces highly specific state validation requirements during the callback phase.

Before redirecting the user's browser to the Authorization Server, the MCP client must extract and securely record the expected issuer from the validated RFC 8414 metadata document, associating it intimately with the PKCE state21. The AS, in turn, is heavily encouraged (SHOULD) to append the iss parameter alongside the authorization code when redirecting the user back to the client22.

Upon receiving the callback, the MCP client must rigorously validate the presence and integrity of the iss parameter22. The client extracts the value and performs an exact string comparison against the locally recorded issuer. Crucially, the protocol forbids any form of normalization during this comparison; the client must not execute scheme case folding, default-port elision, trailing-slash removal, or percent-encoding resolution21.

If the AS advertised support for the issuer parameter in its metadata but failed to include it in the response, or if the exact string comparison fails, the client must instantaneously abort the flow22. Furthermore, if this mismatch occurs within an authorization error response, the client must silently drop the payload and must not surface the error_description or error_uri to the user interface, as these fields are presumed to be attacker-controlled phishing vectors21.

## Phase 4: Granular Consent and Step-Up Authorization

The vast capabilities of an MCP server—ranging from executing read-only database queries to autonomously modifying local filesystem roots—necessitate highly granular access controls. Forcing a user to consent to the absolute maximum potential permissions during the initial connection violates the fundamental security principle of least privilege21. Consequently, the MCP protocol relies heavily on dynamic, just-in-time scope negotiation, broadly categorized as Step-Up Authorization21.

### Initial Scope Negotiation

During the initial client connection, if the MCP server's 401 Unauthorized response includes a scope parameter within its WWW-Authenticate header, the client must treat this directive as authoritative. The client is obligated to request these exact scopes during the primary authorization flow to satisfy the baseline operational requirements of the server21. If the server omits this specific guidance, the client is expected to fall back to requesting the comprehensive set of capabilities listed within the scopes_supported array of the PRM document5.

### Handling Insufficient Scope Challenges (SEP-2350)

As an autonomous agent interacts with the server, it may eventually attempt to invoke a highly sensitive tool for which its current access token lacks the requisite permissions. In this scenario, the MCP server must halt the operation and return an HTTP 403 Forbidden status code24.

This 403 response must be accompanied by a WWW-Authenticate header featuring the error="insufficient_scope" parameter, alongside a scope parameter detailing the precise new permissions required to execute the blocked tool21.

Historically, this step-up process caused significant engineering friction due to a failure in client-side state management. If an MCP client merely intercepts the 403 response, blindly extracts the new scopes, and redirects the user to the IdP requesting only those new capabilities, the Authorization Server will issue a replacement token containing only the newly requested scopes25. This behavior permanently destroys the previously granted permissions, immediately breaking the client's ability to perform the baseline operations it relied upon moments before25.

To eradicate this destructive behavior, Specification Enhancement Proposal (SEP) 2350 formalized the requirement for strict client-side scope accumulation. When an MCP client encounters an insufficient_scope challenge, it must dynamically compute the mathematical union of its previously granted scope set and the newly challenged scope set5. The client then re-initiates the authorization flow requesting this combined superset, ensuring that historical permissions are preserved during the step-up event.

Client SDK implementers must ensure that their error-handling logic precisely evaluates the error string. A severe flaw discovered in early iterations of the Python SDK (Issue #1602) revealed that the HTTP transport was unconditionally retrying the authorization flow upon receiving any 403 Forbidden response, regardless of the underlying cause24. This resulted in doomed network retries and infinite loops when dealing with generic invalid_token rejections. Compliant clients must explicitly check that error="insufficient_scope" before initiating the step-up accumulation flow24.

To optimize the user experience, server architects should strive to evaluate all authorization prerequisites holistically. When an operation requires multiple disparate capabilities, the server should return a single, comprehensive scope challenge rather than emitting piecemeal challenges that force the user through multiple, repetitive consent screens26.

## Phase 5: Managing the Token Lifecycle and Silent Refresh

In sophisticated enterprise deployments, MCP agents frequently operate autonomously for extended durations, executing complex multi-step reasoning loops that may span several hours. Access tokens, by cryptographic design, are highly ephemeral and routinely expire27. Interrupting an agent's reasoning loop to demand manual user re-authentication due to token expiry drastically degrades operational continuity and breaks the promise of autonomous automation27. To circumvent this, MCP heavily leverages standardized refresh token mechanics, governed by SEP-220728.

### The OIDC Offline Access Convention

A fundamental limitation of the pure OAuth 2.1 specification is the absence of a standardized parameter allowing a client to explicitly request a refresh token29. To resolve this, MCP adopts the OpenID Connect (OIDC) convention surrounding the offline_access scope29.

If an MCP client possesses secure cryptographic storage capabilities (such as an OS-level keychain) and desires seamless session continuity, it must explicitly advertise the refresh_token grant type during its initial registration phase29. Subsequently, during the discovery phase, the client examines the Authorization Server's metadata. If the AS lists offline_access within its scopes_supported array, the client explicitly appends this scope to its authorization request28.

The Authorization Server evaluates the client's capabilities, the requested scopes, and organizational security policies. If approved, the AS mints both a short-lived access token and a long-lived refresh token. Crucially, SEP-2207 explicitly dictates that the MCP Resource Server must remain entirely abstracted from this negotiation. Because refresh tokens govern the relationship between the client and the IdP, the resource server must never advertise offline_access in its PRM document or include it within WWW-Authenticate scope challenges29.

### Orchestrating the Silent Refresh

When an access token inevitably expires, the MCP server will reject the subsequent API payload with an HTTP 401 Unauthorized response containing WWW-Authenticate: Bearer error="invalid_token"27.

To ensure seamless operational continuity, an appropriately engineered MCP client HTTP transport must meticulously intercept this specific network state. The silent refresh sequence unfolds through the following precise steps:

1. State Evaluation: The client parses the header. Upon confirming error="invalid_token", it queries its secure storage to determine if a valid refresh token exists for this specific issuer27.
    
2. Queue Interruption: The client immediately pauses all outgoing RPC traffic for that specific connection, holding pending payloads in a local buffer27.
    
3. Token Exchange: The client executes an asynchronous POST request to the IdP's token_endpoint, asserting grant_type=refresh_token alongside the securely stored credential27.
    
4. Credential Substitution: Upon a successful HTTP 200 OK response from the IdP, the client strips the expired access token from its memory, replacing it with the newly minted token. If the IdP employs refresh token rotation—a standard security posture for public clients—the client must simultaneously replace its stored refresh token6.
    
5. Re-execution: The client seamlessly re-injects the new access token into the Authorization header of the original, paused request and resumes the execution pipeline.
    

This entire orchestration occurs transparently, completely hiding the expiry event from both the user interface and the upstream LLM reasoning logic. If the IdP returns an HTTP 4xx error during the exchange (indicating the refresh token was manually revoked by an administrator or has fundamentally expired), the silent refresh fails. Only at this juncture must the client break execution and surface a structured needs_reauth error, triggering an interactive UI prompt27.

## Phase 6: Hardening the Server-Side Security Posture

While MCP clients shoulder the heavy burden of dynamic discovery, cryptographic state management, and user orchestration, the protected MCP server remains the ultimate arbiter of system access. A flawlessly executed client protocol is entirely negated if the resource server fails to strictly enforce environmental boundaries. Implementers of MCP servers must adhere to uncompromising validation standards to prevent enterprise compromise.

### Uncompromising Audience Validation

When an HTTP request arrives bearing an Authorization header, the MCP server must execute a rigorous sequence of cryptographic and semantic validations. Beyond verifying the token's signature against the IdP's public keys and ensuring the exp (expiration) claim remains valid in the future, the server must mathematically enforce audience binding11.

The server must parse the aud (audience) claim within the token and guarantee it explicitly matches the server's canonical resource identifier. Failure to implement strict audience validation exposes the server to devastating cross-service token replay attacks5. In an environment devoid of audience checks, an attacker could legitimately acquire a token intended for an inconsequential, read-only MCP server, and maliciously replay that exact token against a highly sensitive database-execution agent. The sensitive server, seeing a valid signature from a trusted IdP, would improperly authorize the devastating request5.

### The Strict Prohibition of Token Passthrough

A cornerstone of the MCP security philosophy is the explicit, non-negotiable prohibition of Token Passthrough architectures5.

In complex deployments, an MCP server frequently serves as an intermediary, requiring data from downstream backend APIs (such as internal HR systems or cloud infrastructure managers) to fulfill the LLM's query. In this scenario, the MCP server must operate as a distinct, independent OAuth client to those downstream services. It must never extract the access token presented by the connecting MCP client and blindly forward it as the bearer token to the backend API11.

Violating this architecture creates a systemic "Confused Deputy" vulnerability. If a client's token is passed directly through, the downstream API assumes the request originated directly from the user's endpoint, entirely bypassing any application-layer rate limits, semantic payload validation, or auditing controls established by the intermediary MCP server20. Furthermore, passing a token to a downstream API forces that API to accept a token lacking the correct audience binding, corrupting the entire zero-trust architecture11.

### Eradicating Server-Side Request Forgery (SSRF)

Because Authorization Servers and gateway proxies must dynamically fetch external HTTP resources—such as resolving decentralized Client ID Metadata Documents or pulling remote PRM payloads—they introduce profound Server-Side Request Forgery (SSRF) risks into the infrastructure11.

To neutralize this threat, all outbound HTTP clients utilized by the MCP server or IdP for discovery operations must be configured with rigorous network egress filtering. Fetching logic must be strictly restricted from resolving private, reserved, or loopback IPv4 and IPv6 address spaces30. Specifically, network boundaries must explicitly drop outbound connections targeting the 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16 corporate subnets, the 127.0.0.0/8 loopback space, and the highly critical 169.254.0.0/16 link-local range. This link-local range is universally utilized across cloud providers to expose instance metadata services (IMDS), and permitting SSRF access to this range routinely results in total infrastructure compromise via credential exfiltration30.

### Mitigating Loopback Exploitation and Redirect Manipulation

The decentralized nature of the MCP ecosystem frequently results in agents taking the form of locally installed desktop applications, such as IDE plugins or terminal clients. These applications intrinsically rely on loopback interfaces (e.g., http://127.0.0.1:<port>) to capture the OAuth redirect callback after user consent4.

This reliance introduces a distinct phishing and impersonation vector. An attacker can engineer a malicious local application that attempts to hijack the authorization flow by binding to the exact same localhost port utilized by a legitimate desktop client4. To defend against this, the Authorization Server must enforce exact string matching when validating requested redirect_uris against the client's metadata document. The use of wildcards, regular expression pattern matching, or partial string validation is strictly forbidden30.

Furthermore, IdPs operating in MCP environments are heavily encouraged to deploy domain-based trust policies. This includes implementing reputation checks against unknown metadata hosting domains and enforcing strict age restrictions on TLS certificates. If a client requests a redirect to a localhost address, the Authorization Server must fundamentally alter its consent interface, displaying prominent, unavoidable warnings to the user, ensuring they are explicitly aware that a local process—rather than a remote web application—is requesting access to their data4.

## Phase 7: Client-Side Environmental Hardening

The final layer of defense rests upon the operational environment of the MCP client itself. Because the client frequently acts as a bridge between an unpredictable LLM reasoning engine and the host operating system, it must sanitize its interactions with the outside world.

When an authorization flow is triggered, the client must display the authorization URL to the user. The client must never utilize raw shell execution commands (such as cmd.exe, sh, or PowerShell) to open these URLs in the user's default browser30. Doing so opens the door to devastating command injection vulnerabilities if a malicious MCP server provides a crafted URL containing shell-escaped payloads30. Clients must exclusively rely on platform-specific, non-shell APIs for URL execution.

Additionally, clients must sanitize all incoming URLs, rigorously rejecting payloads containing special characters or attempting to redirect the browser to internal network ranges or non-HTTPS destinations11. By coupling strict URL sanitization with the cryptographic rigor of PKCE and SEP-2468, the MCP client ensures the integrity of the authorization boundary remains uncompromised.

#### Works cited

1. Specification - Model Context Protocol, [https://modelcontextprotocol.io/specification/2025-11-25](https://modelcontextprotocol.io/specification/2025-11-25)
    
2. Key Changes - Model Context Protocol, [https://modelcontextprotocol.io/specification/draft/changelog](https://modelcontextprotocol.io/specification/draft/changelog)
    
3. SEP-985: Align OAuth 2.0 Protected Resource Metadata with RFC 9728, [https://modelcontextprotocol.io/seps/985-align-oauth-20-protected-resource-metadata-with-rf](https://modelcontextprotocol.io/seps/985-align-oauth-20-protected-resource-metadata-with-rf)
    
4. Authorization - Model Context Protocol, [https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization)
    
5. modelcontextprotocol/docs/specification/draft/basic/authorization.mdx at main - GitHub, [https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/draft/basic/authorization.mdx](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/draft/basic/authorization.mdx)
    
6. Authorization - Model Context Protocol (MCP), [https://modelcontextprotocol.info/specification/draft/basic/authorization/](https://modelcontextprotocol.info/specification/draft/basic/authorization/)
    
7. OAuth Token Exchange Fails with Separate Authorization Servers #1450 - GitHub, [https://github.com/modelcontextprotocol/typescript-sdk/issues/1450](https://github.com/modelcontextprotocol/typescript-sdk/issues/1450)
    
8. [Auth] OAuth proxy / DCR facade for non-DCR providers (e.g. Entra ID + Claude Code) · Issue #1446 · modelcontextprotocol/csharp-sdk - GitHub, [https://github.com/modelcontextprotocol/csharp-sdk/issues/1446](https://github.com/modelcontextprotocol/csharp-sdk/issues/1446)
    
9. What Is MCP Authorization? Key Concepts & Best Practices - Truefoundry, [https://www.truefoundry.com/blog/what-is-mcp-authorization](https://www.truefoundry.com/blog/what-is-mcp-authorization)
    
10. Evolving OAuth Client Registration in the Model Context Protocol, [https://blog.modelcontextprotocol.io/posts/client_registration/](https://blog.modelcontextprotocol.io/posts/client_registration/)
    
11. Authorization Security Considerations - Model Context Protocol, [https://modelcontextprotocol.io/specification/draft/basic/authorization/security-considerations](https://modelcontextprotocol.io/specification/draft/basic/authorization/security-considerations)
    
12. Is that allowed? Authentication and authorization in Model Context Protocol - Stack Overflow, [https://stackoverflow.blog/2026/01/21/is-that-allowed-authentication-and-authorization-in-model-context-protocol/](https://stackoverflow.blog/2026/01/21/is-that-allowed-authentication-and-authorization-in-model-context-protocol/)
    
13. Understanding Authorization in MCP - Model Context Protocol, [https://modelcontextprotocol.io/docs/tutorials/security/authorization](https://modelcontextprotocol.io/docs/tutorials/security/authorization)
    
14. Authorization Server Discovery - Model Context Protocol, [https://modelcontextprotocol.io/specification/draft/basic/authorization/authorization-server-discovery](https://modelcontextprotocol.io/specification/draft/basic/authorization/authorization-server-discovery)
    
15. The resource URL path is ignored when building the protected resource metadata URL · Issue #1052 · modelcontextprotocol/python-sdk - GitHub, [https://github.com/modelcontextprotocol/python-sdk/issues/1052](https://github.com/modelcontextprotocol/python-sdk/issues/1052)
    
16. RFC 9728 compliance: protected resource metadata URL mismatches when resource identifier has a path · Issue #1400 · modelcontextprotocol/python-sdk - GitHub, [https://github.com/modelcontextprotocol/python-sdk/issues/1400](https://github.com/modelcontextprotocol/python-sdk/issues/1400)
    
17. OAuth AS metadata discovery crashes on 200 OK + non-JSON response instead of falling back to OIDC #2126 - GitHub, [https://github.com/modelcontextprotocol/typescript-sdk/issues/2126](https://github.com/modelcontextprotocol/typescript-sdk/issues/2126)
    
18. Client Registration - Model Context Protocol, [https://modelcontextprotocol.io/specification/draft/basic/authorization/client-registration](https://modelcontextprotocol.io/specification/draft/basic/authorization/client-registration)
    
19. SEP-991: Enable URL-based Client Registration using OAuth Client ID Metadata Documents · Issue #991 - GitHub, [https://github.com/modelcontextprotocol/modelcontextprotocol/issues/991](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/991)
    
20. Authorization - Model Context Protocol, [https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization)
    
21. Authorization - Model Context Protocol, [https://modelcontextprotocol.io/specification/draft/basic/authorization](https://modelcontextprotocol.io/specification/draft/basic/authorization)
    
22. SEP-2468: Recommend Issuer (iss) Parameter in MCP Auth Responses, [https://modelcontextprotocol.io/seps/2468-recommend-issuer-claim-for-auth](https://modelcontextprotocol.io/seps/2468-recommend-issuer-claim-for-auth)
    
23. Implement SEP-2468: Recommend Issuer (iss) Parameter in MCP Auth Responses · Issue #2197 · modelcontextprotocol/typescript-sdk - GitHub, [https://github.com/modelcontextprotocol/typescript-sdk/issues/2197](https://github.com/modelcontextprotocol/typescript-sdk/issues/2197)
    
24. OAuth: 403 responses without insufficient_scope incorrectly retry with same token · Issue #1602 · modelcontextprotocol/python-sdk - GitHub, [https://github.com/modelcontextprotocol/python-sdk/issues/1602](https://github.com/modelcontextprotocol/python-sdk/issues/1602)
    
25. Step-up authorization (403 insufficient_scope) dead-ends with SdkHttpError when a refresh_token is present · Issue #2255 · modelcontextprotocol/typescript-sdk - GitHub, [https://github.com/modelcontextprotocol/typescript-sdk/issues/2255](https://github.com/modelcontextprotocol/typescript-sdk/issues/2255)
    
26. Implement SEP-2350: Clarify client-side scope accumulation in step-up authorization #2200, [https://github.com/modelcontextprotocol/typescript-sdk/issues/2200](https://github.com/modelcontextprotocol/typescript-sdk/issues/2200)
    
27. Client should silently refresh access tokens on 401 when a refresh token is available #2031, [https://github.com/modelcontextprotocol/typescript-sdk/issues/2031](https://github.com/modelcontextprotocol/typescript-sdk/issues/2031)
    
28. Implement SEP-2207: OIDC-flavored refresh token guidance #2199 - GitHub, [https://github.com/modelcontextprotocol/typescript-sdk/issues/2199](https://github.com/modelcontextprotocol/typescript-sdk/issues/2199)
    
29. SEP-2207: OIDC-Flavored Refresh Token Guidance - Model Context Protocol, [https://modelcontextprotocol.io/seps/2207-oidc-refresh-token-guidance](https://modelcontextprotocol.io/seps/2207-oidc-refresh-token-guidance)
    
30. Security Best Practices - Model Context Protocol, [https://modelcontextprotocol.io/docs/tutorials/security/security_best_practices](https://modelcontextprotocol.io/docs/tutorials/security/security_best_practices)