Skip to content
By MCP

The MCP Security Implementation Playbook: Enterprise Authorization Patterns That Actually Work

MCP's July 2026 spec rewrite went stateless and made Client ID Metadata Documents the standard, not audience-bound tokens, which have been mandatory since mid-2025. What actually changed since December 2025, and the checklist that replaces the old one.

The MCP Security Implementation Playbook: Enterprise Authorization Patterns That Actually Work, by Deepak Gupta on guptadeepak.com

The Model Context Protocol shipped its largest specification revision since launch on July 28, 2026. The protocol core went stateless. Dynamic Client Registration (DCR, the old way an MCP client obtained an OAuth client ID without a human registering it by hand) was formally deprecated in favor of Client ID Metadata Documents (CIMD). Authorization responses now carry a validated issuer claim. What didn't change: MCP servers have had to publish OAuth 2.0 Protected Resource Metadata (PRM) under RFC 9728 since the 2025-06-18 revision, more than a year before this one. MCP clients have had to bind every access token to a single resource server using RFC 8707 resource indicators for that same stretch. Those two requirements already retired most of the confused-deputy patchwork enterprise teams wrote in application code back then. What's new in July is what happens on top of that foundation now that the protocol core has no session state left to lean on.

I spent thirteen years building LoginRadius into a CIAM platform serving more than a billion identities. Most of that time was spent arguing with engineering teams about exactly this class of bug: a proxy server forwarding someone else's OAuth token because nobody checked who it was actually issued for. MCP reintroduced that bug at the exact moment enterprises started wiring AI agents into production systems. At GrackerAI, the company I run now, our agents call a growing stack of tools every day, many of them through MCP. So I read spec updates like this one the way I used to read SAML errata: line by line, checking what changes in the code already shipped.

The pattern most December 2025 MCP security writeups describe, per-client consent registries, hardened OAuth state parameters, cookie attributes locked to an exact callback path, was defense in depth. It layered on top of an audience-binding requirement the spec had already mandated six months earlier. Most teams just hadn't finished implementing RFC 8707 correctly yet. Some of that application-layer pattern is still correct and still required. Part of it describes a workaround for a hole the spec had already closed by the time the writeups were published. At least one common pattern, a stateful session cookie keyed to a client_id, now actively conflicts with where the protocol went next.

What shipped on July 28

The 2026-07-28 release candidate, published May 21, 2026, was described by the steering committee as the largest revision of the protocol since it launched in November 2024. The final specification that shipped on July 28 kept that framing. Three changes matter for anyone running MCP servers or clients in an enterprise environment. A fourth item enterprise teams keep citing as new, audience-bound tokens, isn't one, and getting that date wrong changes what a security team should actually prioritize this quarter.

First, authorization responses now carry a validated issuer claim under RFC 9207. When the authorization server includes an iss parameter in the redirect back to the client, the client has to compare it against the issuer it recorded before the redirect and refuse to proceed on a mismatch. That closes a mix-up attack: a malicious or compromised authorization server tricking a client into redeeming a code at the wrong issuer. The requirement is a SHOULD for authorization servers and a MUST for clients that receive the parameter; the steering committee has flagged a future revision that upgrades server-side inclusion to MUST as well.

Second, Dynamic Client Registration under RFC 7591 is formally deprecated in favor of Client ID Metadata Documents. I covered CIMD in detail when the pattern first appeared in the November 2025 draft. The July spec makes CIMD the intended path rather than an option, while keeping DCR alive for backward compatibility through a twelve-month minimum deprecation window.

Third, the protocol core went stateless. The Mcp-Session-Id header and the initialize and initialized handshake are gone. Every request now has to be self-describing, which means any server instance can answer any request, and MCP servers can sit behind a plain round-robin load balancer with no sticky routing and no shared session store. That's good news for anyone running MCP at scale. It's a mixed blessing for security, which I get to further down.

What didn't change: MCP servers have had to implement OAuth 2.0 Protected Resource Metadata under RFC 9728 since the 2025-06-18 revision, more than a year before this one. MCP clients have had to implement OAuth 2.0 Resource Indicators under RFC 8707 for that same stretch. Every authorization request and every token request has carried a resource parameter naming the canonical URI of the target MCP server since then. The authorization server writes that URI into the token's aud claim. An MCP server that receives a token with the wrong aud value has had to reject it for that same year-plus, even if the signature is valid and the token hasn't expired. A team only implementing audience binding now is thirteen months behind the spec, not reacting to something that just shipped.

The confused deputy fix already lives in the protocol

The confused deputy attack is the one MCP-specific vulnerability worth understanding in identity terms, because it's a client-impersonation bug with a fifty-year lineage, not a new category of AI risk. An MCP proxy server sits between a client and an upstream OAuth provider. A malicious client registers with the proxy, a victim approves what looks like a legitimate consent screen, and the proxy, confused about which client it's actually acting for, hands over the victim's authorization to the attacker's client instead. The proxy is deputized to fetch a token on the user's behalf, and the attack tricks the deputy into fetching the wrong one.

The December 2025 fix for this, and it's the fix most MCP security writeups still describe, was entirely at the application layer. Build a consent registry keyed to client_id and user_id, and check it before starting any OAuth flow. Generate the state parameter only after consent is granted rather than before, and lock the consent cookie's Path, SameSite, and Secure attributes to an exact callback path. All of that is still correct practice. None of it is optional now either, because RFC 8707 doesn't replace user consent. It stops a different failure mode.

What RFC 8707 and RFC 9728 add is a structural backstop for the failure mode consent screens don't catch: a token minted for server A getting replayed against server B. That's been a required claim comparison every conformant MCP server has had to run on every request since the 2025-06-18 revision, not a discretionary recommendation buried in a best-practices page. What's changed since then is enforcement discipline, not the rule: the CVE data below shows plenty of shipped MCP servers still skip the check.

def enforce_audience(token_claims: dict, this_server_uri: str) -> None:
    """Reject any token not explicitly issued for this MCP server."""
    aud = token_claims.get("aud")
    audiences = [aud] if isinstance(aud, str) else (aud or [])
    if this_server_uri not in audiences:
        raise TokenRejected(
            f"token audience {audiences} does not include {this_server_uri}"
        )

That's five lines doing the job that used to take a stateful consent registry, a signed state parameter, and a page of cookie attributes to approximate. Keep the consent registry. Add the audience check. They defend against different attackers.

The CVE count caught up

While the spec was closing the authorization gap, the implementation gap kept widening. Security researchers catalogued more than 40 CVEs against MCP SDKs and servers across Python, TypeScript, Java, and Rust between January and April 2026 alone, roughly one every four days. CVE-2026-33032, tracked informally as MCPwn, hit nginx-ui's MCP integration. A missing authentication check on the wrong endpoint let unauthenticated attackers take full administrative control of managed Nginx servers, CVSS 9.8, confirmed under active exploitation before a patch shipped in March 2026. CVE-2026-26118 is a server-side request forgery flaw in Microsoft's Azure MCP Server that let an attacker who could reach the MCP tool coerce it into leaking its managed-identity token to an attacker-controlled URL, CVSS 8.8, patched March 10, 2026. CVE-2025-6514, in the widely used mcp-remote package, was a CVSS 9.6 OS command injection affecting every version from 0.0.5 through 0.1.15, fixed in 0.1.16.

The common thread across most of these isn't authorization. It's the stdio transport, which most local MCP servers use to talk to their host application, executing operating-system commands without sanitizing what an agent or a tool response puts into them. A 2026 scan of more than 2,600 live MCP implementations found 82% of the ones handling file operations vulnerable to path traversal, and 67% carrying some form of code injection risk. OWASP fast-tracked a dedicated MCP Top 10, currently in beta, alongside the broader OWASP Top 10 for Agentic Applications it published in December 2025. Command injection sits at MCP05. Insufficient authentication and authorization sits at MCP07. I broke down the specific vulnerability classes behind those numbers in a separate piece on the MCP vulnerability landscape; this post stays focused on what to build, not what to fear.

Tool poisoning is a supply chain problem

Authorization gets the attention because it maps to problems identity engineers already know how to reason about. Tool poisoning doesn't, and it deserves more attention than a checklist item. OWASP's MCP Top 10 codifies it as MCP03, split into three sub-patterns. Schema poisoning is a compromised or malicious server sending a tool definition that misrepresents what the tool does. Tool shadowing is a second server registering a tool with a name and description close enough to a trusted one that the agent picks the wrong one. Rug pulls are a tool an agent already trusts changing its description or behavior after the user approved it once.

The rug pull variant breaks the mental model most security teams bring from API management. An API contract doesn't usually change silently between calls. An MCP tool definition can, because nothing in the base protocol requires a server to keep serving the same schema it advertised five minutes ago. If your agent approved a send_email tool on Monday, nothing stops the same tool from redefining itself to also accept a bcc parameter on Tuesday. Most standard integrations never re-check that the tool being called is still the tool that was originally approved.

The fix is unglamorous, and it's the one CIAM teams already apply to third-party SDKs: pin tool definitions by hash, re-verify the hash on every fetch, and treat a mismatch as a hard failure, not a warning. Run the same threat model you'd run for any dependency you didn't write, because that's what an MCP tool is. Delegation and just-in-time scoping patterns for agent workflows help here too, since an agent that only holds narrow, short-lived permissions can't do much damage even when a tool it calls turns out to be poisoned.

Migrating off Dynamic Client Registration

CIMD is straightforward in concept. Your client's client_id becomes an HTTPS URL you control, pointing to a JSON document the authorization server fetches and validates instead of storing a registration record for. There's no pre-registration step, no per-authorization-server client ID to manage, and no way for an attacker to impersonate your client by registering a lookalike, because the identity check happens against a URL you host, not a string anyone can submit.

What the July spec changed is urgency, not mechanics. CIMD support was optional in the November 2025 draft. As of 2026-07-28 it's the direction the spec formally endorses, with DCR kept only for the authorization servers that haven't caught up yet. If you run an MCP client today, publish your CIMD document at a stable URL and keep your DCR fallback working for authorization servers that don't yet resolve CIMD. Put a real date on migrating fully before the twelve-month backward-compatibility window narrows further. If you run an MCP authorization server, resolving CIMD documents is table stakes now, not a nice-to-have on next quarter's roadmap.

What stateless MCP does to your threat model

Removing the Mcp-Session-Id header closes one class of attack outright. There's no session identifier to predict, steal, or fixate, because there's no protocol-level session. That's a real security win, not just an operations one.

It also removes a crutch a lot of implementations were leaning on without realizing it. Teams that used the session as an implicit authorization boundary, checking who's allowed to do what once at session start and coasting on that decision for every request after, now have nothing to coast on. Every request has to carry and prove its own authorization independently. Security researchers at Akamai flagged the predictable failure mode already: implementers reintroducing state at the application layer through tracking cookies or headers with guessable values, recreating the exact session-fixation risk the protocol just removed, one layer up the stack.

Treat every MCP request as a fresh authorization decision. Don't assume request N+1 lands on the same server instance as request N, because under the stateless core it usually won't. Bind authorization to the audience-scoped token on the request itself, not to anything inferred from a prior request in the same conversation. The same discipline applies to multi-agent systems where one agent calls another: verify the delegation chain on every hop, not once at the start of it.

The implementation checklist for August 2026

The December 2025 version of this playbook had a 47-point audit checklist. Most of those points were true then and are still true now. A handful actively conflict with where the spec went. Here's the shorter list that reflects the protocol as it stands in August 2026.

ControlSpec status (Aug 2026)What to actually do
Protected Resource MetadataRequired since 2025-06-18, RFC 9728, unchanged in this revisionPublish PRM at your MCP server's well-known endpoint so clients can find the correct authorization server automatically.
Resource indicatorsRequired since 2025-06-18, RFC 8707, unchanged in this revisionReject any token whose aud claim doesn't include your server's canonical URI, even if the signature checks out.
Issuer validationNew in 2026-07-28, RFC 9207: SHOULD for authorization servers, MUST for clients that receive issRecord the expected issuer before redirecting. Reject any authorization response whose iss doesn't match.
Token exchangeBest practice, RFC 8693Never forward an upstream token downstream. Exchange it for a new, audience-scoped credential at every hop.
Client identityDCR deprecated, CIMD is the successorPublish a Client ID Metadata Document at a stable URL. Keep DCR running only for authorization servers that haven't adopted CIMD.
Session stateRemoved from the protocol coreAuthenticate every request independently. Don't assume request N+1 lands on the same server instance as request N.
Consent UIStill requiredKeep per-client, per-scope consent screens. Audience binding stops token replay, not scope creep.
Tool definitionsNo protocol-level integrity checkPin tool schemas by hash and re-verify on every fetch. Treat a mismatch as a hard failure.
stdio transportLargest source of 2026 CVEsSanitize every argument passed to a local process. Never pass raw agent or tool output straight into a shell call.
File-system toolsMajority of scanned deployments vulnerable to path traversalCanonicalize and allow-list paths before any file operation a tool exposes.
Shadow MCP serversCodified as OWASP MCP09Inventory every MCP server an agent can reach, including ones a developer's IDE plugin added without review.

Frequently asked questions

What is the current MCP specification version?

2026-07-28, released July 28, 2026. It's the largest revision since the protocol launched in November 2024, and it's the version enterprise teams should build against. The immediately prior revision, 2025-11-25, is now legacy, though the audience-binding requirements enterprise teams most need to get right (RFC 9728 and RFC 8707) go back further, to the 2025-06-18 revision.

Is December 2025 MCP authorization guidance still valid?

Partly. Per-client consent registries, hardened OAuth state parameters, and strict cookie attributes are still correct practice and still required, because RFC 8707 audience binding solves token replay, not consent. What's obsolete is any guidance that treats Dynamic Client Registration as the default client-identity model, or that assumes a persistent server-side session, since neither assumption holds under the 2026-07-28 spec.

Do I have to migrate to Client ID Metadata Documents immediately?

Not immediately. DCR keeps working for backward compatibility for a minimum of twelve months from deprecation. Build new MCP clients on CIMD now, and put a real date on migrating existing ones, because DCR's core weakness, nothing verifies the registering client is who it claims to be, doesn't get safer with time.

What's the biggest MCP security risk in August 2026?

Unsanitized stdio transport, not authorization. The confused deputy problem gets the conference talks because it's conceptually interesting to identity people. The CVE data through 2026 is mostly command injection and path traversal in local MCP servers that trust agent-supplied or tool-supplied input without checking it. Fix your audience binding, then go look at every subprocess call your MCP servers make.

Every page on guptadeepak.com is hand-curated by Deepak Gupta. Pick a thread:

Get the newsletter

New writing on identity, AI security, and building software, delivered when it ships. No tracking pixels, no funnels, unsubscribe with one click.