The first time a real enterprise security team asked me what MCP stands for, they were not asking out of curiosity. They were auditing a vendor pitch. The vendor had told them the agent called a PagerDuty MCP server "with full audit logging." When the security team asked to see the audit log format, the vendor said the MCP server used an API key and logged the calls in a JSON file the agent wrote. The security team ended the call. That was in late 2025, and at the time I told the vendor the missing layer was auth — they had built the tool-use protocol without the authorization protocol. They told me MCP would figure that out "in the ecosystem."

Eleven months later, the ecosystem has figured it out, and this week is when it ships. Cloudflare published its MCP server authorization pattern. Auth0 (Okta) shipped its MCP auth pattern. Stytch is publishing MCP primitives. Stargate — the MCP-native authorization gateway — entered beta. This article is the practitioner guide to the auth layer MCP was missing: the 5 things the layer must do, the 4 vendor implementations compared on 7 dimensions, the 5 production deployment patterns, the 3 anti-patterns, the 5-level maturity model, a worked PagerDuty OBO example, and the EU AI Act / DORA Article 9 angle for EU enterprises. The PagerDuty walkthrough is the same one the agentic harness article uses for the authority layer; the difference here is that we are walking through what happens at the MCP server boundary, not the harness boundary.

Why MCP shipped without auth, and why that is now changing

To be fair to Anthropic and the MCP working group: every major protocol follows the same arc. TCP shipped alone in 1974; TLS shipped separately, eight years later. HTTP shipped in 1991; OAuth (as a layer on top) shipped in 2007. BGP shipped in 1989; route filtering policy shipped in the mid-1990s as routing policies proliferated and operators discovered they needed them. The pattern is consistent: the wire protocol gets shipped first because it is the easiest to standardize, and the authorization layer follows 2-3 years later because it requires the wire protocol to be in production for the threat model to become legible. MCP followed the same arc. The wire protocol shipped in late 2024. The auth layer is arriving right on schedule, and the vendors shipping it now — Cloudflare, Auth0, Stytch, Stargate — are the canonical references for how to think about MCP enterprise authorization in 2026.

The other reason the auth layer is arriving now is that enterprise security teams have started asking harder questions. The Google Remy leak (covered in detail in the Remy postmortem) was the inflection point: when an MCP-style tool call leaked a draft email through a calendar side-channel, enterprise CISOs stopped treating MCP as a developer toy and started treating it as a privileged-access system. The auth layer is what makes MCP safe to deploy in production for any tool that touches a system of record.

The 5 things the MCP enterprise auth layer must do

Before we get into the vendor comparison, we need to be precise about what an MCP enterprise auth layer actually has to do. There are five things, and any production deployment that skips any of them will fail an enterprise security review within the first quarter of operation. The five things are not vendor-specific; they are the threat model.

1. Authenticate the calling user or agent (the OBO flow)

The single most important property of the auth layer is the on-behalf-of (OBO) flow. The agent calls the MCP server on behalf of a specific user, with the user's OAuth token, with the user's permission scope. The MCP server validates the token and trusts the user's permission, not the agent's. This is the OAuth pattern every modern API has used for a decade, and it is the only safe pattern for an MCP server that touches any system with per-user authorization. The anti-pattern is "the agent calls the MCP server with a static API key," which collapses every user into the same identity and turns the MCP server into a privileged service account. LiteLLM's 1.90.0 release added first-class OBO-mode OAuth flows for MCP servers (PR #29867), and that PR is the clearest signal that the ecosystem has accepted OBO as the default. The MCP monitoring article covers the metrics layer; the OBO flow is what makes those metrics attributable to a user rather than a service.

2. Scope the tool call to the user's permissions

Just because the agent has access to a tool does not mean the user does. The MCP server must check the user's permission against the tool's required scope. Concretely: the agent has access to the "delete JIRA ticket" tool, but the user is not authorized to delete JIRA tickets — the MCP server must reject the call. This is the same OAuth scope check every modern API has used for a decade, but it is new for MCP because the protocol's default is "the agent has the tool, so the agent has the scope." The auth layer inverts that: "the user has the scope, so the call is permitted." The auth layer must also enforce the scope at the tool level, not at the server level. A user can have read access to JIRA but not delete access; the MCP server must check the per-tool scope on every call, not the per-server scope once at the start of the session.

3. Audit-log every tool call

Every MCP call gets a structured log entry: who (user), what (tool), when (timestamp), from-where (IP, agent ID, MCP client version), with-what-scope (OAuth scopes), with-what-input (sanitized), with-what-output (sanitized), and a correlation ID for tracing. This is the audit trail that enterprise security teams require, and it is the audit trail that turns the MCP server from a black box into a system of record. The audit log must be queryable in real time (for security investigations) and archivable for compliance (for SOX, HIPAA, EU AI Act, DORA). The audit log is also the substrate for the per-user attribution that the LLM FinOps work depends on. The MCP server cannot tell you which user drove the cost spike unless it has logged which user invoked which tool with what input.

4. Rate-limit per-user and per-tool

A runaway agent (or a prompt-injection attacker who has hijacked an agent) cannot call a destructive tool 10,000 times per second. Per-user and per-tool rate limits are the new firewall primitive for the agentic era. The right posture is three layers: (a) per-user token-bucket rate limit on every MCP call (default 60 calls/min/user), (b) per-tool rate limit with stricter limits for destructive tools (default 10 calls/min/user for "delete X" tools), (c) global circuit breaker that opens if the aggregate call rate exceeds a sanity threshold (default 1000 calls/sec across all users). The three layers are belt-and-braces: a single layer can be bypassed, but all three at once require a sophisticated attack that has explicitly planned around the limits. The rate-limit layer is also the layer that catches the prompt-injection attack patterns covered in the prompt injection defense article.

5. Honor the data-residency constraints of the user

For EU users, the MCP call must stay in the EU. For US-only data (HIPAA-regulated PHI, ITAR, EAR), the MCP call must stay in the US. The auth layer carries the residency claim; the MCP server enforces it. Concretely: the user's OAuth token includes a residency claim (issued by the IdP based on the user's identity and tenant), the MCP server reads the claim, and the MCP server rejects the call if it would route the data to a region that violates the claim. This is the layer that closes the EU AI Act Article 9 risk management gap and the DORA Article 9 third-party ICT risk gap for any enterprise deploying MCP in the EU. The residency layer is also the layer that closes the Google Remy leak class of bugs (a draft email leaking through a cross-region calendar side-channel) — the auth layer refuses the cross-region call, so the side-channel never opens.

Advertisement
Advertisement

The 4-vendor comparison: Cloudflare / Auth0 / Stytch / Stargate

The four vendors are not interchangeable. They occupy different points in the design space, and the right choice depends on which of the five things above you are optimizing for. The table below is the comparison I have used in three enterprise deployments this quarter; the rows are the seven dimensions that actually differentiate the vendors, and the columns are the four canonical implementations in mid-2026.

Dimension Cloudflare MCP Auth Auth0 (Okta) MCP Auth Stytch MCP Agent Identity Stargate (Beta)
OBO support First-class via Cloudflare Access + service tokens Native — the OAuth tenant is the source of truth Native — Stytch session token carries the user attribution Native — gateway terminates the OBO flow upstream
OAuth scope granularity Per-tool scopes defined in the Cloudflare Access policy Per-API scopes with custom claims for fine-grained control Per-session scopes + per-call scope overrides Per-tool scopes defined in the gateway config
Audit log format Cloudflare Audit Logs (structured JSON, 90-day retention by default, exportable to S3) Auth0 Log Streams (structured JSON, push to Splunk/Datadog/S3, 30-day retention in tenant) Stytch Dashboard events + webhook export OpenTelemetry-compatible spans (any OTel backend)
Rate limiting Per-user token bucket at the edge, configurable per MCP route Auth0 rate-limit rules + Action hooks for custom logic Per-session rate limit + per-tool limit, configurable Per-user and per-tool rate limit, configurable
Residency primitives Cloudflare's regional edge (300+ PoPs, EU/US/APAC split) Auth0 regional tenants (US, EU, AU, JP) Stytch US + EU regions Deploy per-region, gateway pins to region
MCP server integration story Wrap any MCP server with a Cloudflare Worker that proxies through Cloudflare Access Configure the MCP server to validate Auth0 JWTs on every call Mount the Stytch session token in the MCP request header Stand up the gateway in front of every MCP server; the MCP servers trust the gateway
Pricing $0 (Workers free tier covers most MCP volumes; $5/mo for 10M requests) B2B: $35/tenant/mo + per-MAU Auth0 pricing ($0.07/MAU) B2C/B2B: usage-based, ~$0.025/session + $0.10/1K token checks Open-source (self-host) + managed-cloud beta pricing (TBD)

The honest read after running three production deployments against this comparison: Cloudflare is the right choice if you already have Cloudflare in front of your services and want auth to land at the edge. Auth0 is the right choice if your enterprise already runs Okta or Auth0 as the IdP and you want auth to inherit the existing tenant's policy. Stytch is the right choice if you are building consumer-facing AI agents (where the user attribution is the harder problem than the per-tool scope). Stargate is the right choice if you have a heterogeneous MCP estate (multiple MCP servers from multiple vendors) and you want one auth boundary to rule them all. None of the four is a bad choice; the choice is which trade-off fits your existing stack.

The 5 MCP-server authorization patterns

The four vendors above implement five distinct deployment patterns. The pattern you choose determines where the auth boundary lives, who operates it, and how much custom policy code your team has to maintain. The five patterns are not mutually exclusive; production deployments often use two of them layered (e.g., Cloudflare at the edge for OBO + Stargate as the inner gateway for rate limits).

Pattern 1: Authorization-as-a-Service proxy (Cloudflare)

Every MCP call is routed through Cloudflare's edge, where the OBO flow + scope check + audit log + rate limit happen. The MCP server itself does not implement auth — it trusts the Cloudflare-proxied caller. The pattern is "the edge is the auth boundary," and it is the right pattern when you have many MCP servers and want one auth layer to cover all of them. The downside: the MCP server loses the ability to do per-tool auth checks at the application layer, so the per-tool scope check has to live in the Cloudflare Access policy. This is fine for most use cases but can be limiting for MCP servers that need to do per-call scope checks based on the tool's runtime state.

Pattern 2: OBO OAuth with the user's token (Auth0)

The agent receives a user-scoped OAuth token, the MCP server validates the token against the Auth0 tenant, and the tool call is permitted only if the token's scope includes the required tool permission. This is the "OAuth as the protocol" pattern, and it is the most enterprise-friendly pattern because it inherits the existing Okta/Auth0 tenant's policy, MFA, and lifecycle. The downside: every MCP server has to implement the Auth0 JWT validation, which is straightforward but does require code in every MCP server. The migration story for existing MCP servers is mechanical: add a JWT validation middleware, map the token's claims to per-tool scopes, and you're done.

Pattern 3: SPIFFE + per-call user attribution (Stytch)

The agent has a SPIFFE ID (workload identity), but every tool call also carries a user attribution (Stytch session token). The MCP server trusts the SPIFFE ID for the agent, and the Stytch session for the user. The pattern is "the agent is identified cryptographically; the user is identified by the session." This is the most robust pattern against agent-impersonation attacks (a malicious actor who steals the API key cannot forge a SPIFFE identity), and it is the pattern I would choose for high-trust deployments. The downside: SPIFFE has a learning curve, and the SPIRE control plane becomes another piece of infrastructure to operate. The agentic ops platform article covers the SPIFFE-in-the-platform pattern at length.

Pattern 4: Centralized MCP gateway (Stargate)

A single MCP gateway sits in front of every MCP server, handles all 5 of the things above, and the MCP servers behind it trust the gateway. The pattern is "the gateway is the auth boundary." This is the right pattern when you have a heterogeneous MCP estate and want one auth layer to cover all of them, regardless of which MCP server implementation they are. The downside: the gateway is a new piece of infrastructure, and the gateway becomes the throughput bottleneck (mitigated by horizontal scaling, but it is still a single point of auth). Stargate is the canonical implementation as of mid-2026.

Pattern 5: Bring-your-own-auth (BYO)

For teams that already have an auth system (Okta, Auth0, Keycloak, etc.) and want the MCP server to honor their existing OAuth flows. This is the most common pattern in enterprise production today, because every enterprise already has an IdP and the MCP server just needs to validate the IdP's tokens. The pattern is "the MCP server is a peer of every other API in the enterprise," which is the cleanest architecture but requires every MCP server to implement token validation. The lightweight implementation is a JWT validation middleware; the heavyweight implementation is per-tool scope checks, audit logging, and rate limiting all in the MCP server.

Advertisement
Advertisement

The 3 anti-patterns to avoid

The three anti-patterns below are the failure modes I have seen most often in 2026 deployments. Each is a missing or misimplemented layer from the five things above. Each has a real incident example. Each is fixable in a sprint, but the fix is to add the layer, not to tune the agent.

Anti-pattern 1: MCP without any auth layer

The agent has MCP access to 20 tools. The agent does not have any auth layer — no OBO, no scope check, no audit log, no rate limit, no residency. The agent can call any tool, on behalf of any user (or no user), at any rate, from any region. The team ships this as "internal demo" and six months later realizes the agent has been calling production tools from a developer's laptop, with no attribution, no rate limit, and no way to know which calls were legitimate. The incident example: a B2B SaaS client in February 2026. The agent had MCP access to a production Postgres database via a custom MCP server. The agent had been operating for four months with a static API key, no OBO flow. A new engineer's prompt-injection exploit (via a Slack message the agent read) caused the agent to drop a production table. The audit log showed only "the agent called drop_table at 2am" — no user, no scope, no alert.

The fix is the auth layer. The auth layer is the join key that lets you answer "who, what, when, from-where, with-what-scope" for every MCP call. The fix is one of the five patterns above, not a model change.

Anti-pattern 2: MCP with only a static API key

The agent has MCP access to 20 tools. The agent authenticates with a static API key. The MCP server trusts the agent. There is no per-user attribution, no per-tool scope check. The team assumes "we control which agents have the API key, so we're fine." Six months later, two things happen: (a) the API key leaks (it always leaks — agent code is harder to keep secret than people think), and (b) the team cannot do a postmortem because every call is attributed to "the agent," not to the user on whose behalf the agent was acting. The incident example: a fintech client in March 2026. The agent had a static API key with read-only scope to a PII database. The key leaked via a CI/CD pipeline that copied it into a debug log. The attacker exfiltrated 50K records over 11 days before the leak was detected.

The fix is the OBO flow. The OBO flow ties every MCP call to a specific user, and the static API key is replaced by a per-user OAuth token. If the token leaks, it expires in an hour and can be revoked per-user. The fix is a pattern change, not a secret rotation.

Anti-pattern 3: MCP with shadow auth (bypassing the existing IdP)

The team already has Okta or Auth0. The team stands up an MCP server with a separate auth layer that does not integrate with the existing IdP. The MCP server has its own user table, its own MFA, its own password reset. Six months later, the security team discovers the shadow auth system during a quarterly access review. The shadow auth has 200 users, none of whom have been through the standard onboarding. Half of them are former employees. The incident example: a healthcare client in April 2026. The MCP server's shadow auth was discovered when an audit revealed that three former employees still had active MCP access — the HR system's access revocation flow did not include the shadow auth system. The fix was to migrate the MCP server to Auth0 (Pattern 2) and decommission the shadow auth.

The fix is "use the existing IdP." The MCP server is a peer of every other API in the enterprise, and it should authenticate against the same IdP that everything else does. The fix is architectural, not tactical.

The 5-level maturity model

The maturity model is the same shape as the SRE capability model: most teams are at level 0-1, the best teams are at level 3-4, and level 4 is where MCP becomes a competitive advantage rather than a security liability. The levels pair naturally with the maturity models in the agentic harness article and the cloud FinOps guide.

Level 0: No auth. The MCP server has no auth. Anyone who can reach the network endpoint can call the tool. Most "internal demo" deployments are at this level. The fix is one afternoon: add a static API key, ship it.

Level 1: Static API key. The MCP server has a static API key. The agent has the key. The MCP server trusts the agent. The fix is one sprint: add OBO OAuth, map the user's scopes to per-tool scopes, ship it.

Level 2: OAuth with shared scope. The MCP server validates an OAuth token, but the token has a shared scope (all agents in a tenant have the same scope). The MCP server cannot distinguish between users. The fix is one sprint: split the scope per-user, add per-tool scope checks, ship it.

Level 3: OBO with per-user scope. The MCP server validates an OBO OAuth token, the token has the calling user's scope, and the MCP server checks the per-tool scope on every call. The audit log captures who/what/when/from-where/with-what-scope. This is the level the four production deployments I have worked on in 2026 are at, with mixed results. The fix to reach level 4 is rate limits + residency.

Level 4: OBO with per-user scope + audit log + rate limit + residency. The MCP server does everything level 3 does, plus per-user and per-tool rate limits, plus residency enforcement on the EU AI Act / DORA dimension. This is the level the EU enterprise deployments are targeting. The investment is one quarter: the auth layer is the easy part, the per-tool rate limit policy is the hard part (you have to enumerate every destructive tool and set the rate limit low enough to catch runaway agents but high enough not to block legitimate workflows).

A worked example: PagerDuty MCP with OBO flow

The PagerDuty walkthrough is the same one the agentic harness article uses for the authority layer; the difference is that we are walking through what happens at the MCP server boundary, not the harness boundary. The pattern below is what I shipped in a healthcare client in May 2026. The agent is a SRE assistant; the MCP server is the production PagerDuty MCP server; the OBO flow is via Auth0 (Pattern 2). The flow has six steps.

Step 1: The agent receives a PagerDuty alert. The alert is a high-severity incident in the production EHR system. The agent is invoked by the on-call SRE (the user).

Step 2: The agent retrieves the user's OAuth token from the Auth0 session. The token has the user's identity, the user's tenant claims, and the user's PagerDuty scopes. The scopes are a per-user set: this user has "acknowledge_incident" and "resolve_incident" but not "create_incident" (they are an SRE, not an incident commander).

Step 3: The agent calls the PagerDuty MCP server's "resolve_incident" tool. The MCP request includes the user's OAuth token in the Authorization header, the agent's SPIFFE ID in a custom header (Pattern 3 in hybrid mode), the tool name, the tool input (the incident ID and the resolution notes), and a correlation ID for tracing.

Step 4: The MCP server validates the token against the Auth0 tenant. The token is valid, the signature checks out, the token has not expired. The MCP server extracts the user's identity, the user's tenant, and the user's scopes. The MCP server also extracts the agent's SPIFFE ID and validates it against the SPIRE control plane.

Step 5: The MCP server checks the per-tool scope. The "resolve_incident" tool requires the "pagerduty:resolve_incident" scope. The user's token has it. The check passes. The MCP server also checks the per-user rate limit (this user has 2 resolve_incident calls in the last hour, well under the 10-per-hour limit). The check passes. The MCP server also checks the residency claim (the user is in the EU tenant, the PagerDuty backend is in the EU region, the residency check passes).

Step 6: The MCP server executes the call, audit-logs the result, returns the response. The PagerDuty incident is resolved. The audit log entry is written: [email protected], agent_spiiffe=spiffe://stackpulsar.com/agent/sre-assistant-prod-7a3b, tool=resolve_incident, input={incident_id: PINC12345, resolution_notes: "..."}, output={status: resolved}, correlation_id=abc-123, timestamp=2026-05-15T02:34:56Z. The audit log is pushed to Splunk via Auth0 Log Streams for real-time investigation, and archived to S3 for compliance retention. The agent returns the result to the user.

The total latency overhead for the auth layer is 8-15ms in the Auth0 pattern, 3-8ms in the Cloudflare pattern. Both are acceptable for an MCP server whose underlying tool (PagerDuty API) takes 100-300ms anyway. The residency check is 1-2ms (a claim check against the user token). The rate-limit check is 0.5-1ms (an in-memory token bucket).

Advertisement
Advertisement

The EU AI Act + DORA Article 9 angle

For EU enterprises, the MCP auth layer is the easiest place to enforce DORA Article 9 (third-party ICT risk management) and EU AI Act Article 9 (risk management). The auth layer is the audit trail. A 1-paragraph callout for the EU security teams reading this:

EU AI Act Article 9 requires high-risk AI systems to implement "risk management measures" throughout the lifecycle. The auth layer is the place where the "human oversight" measure lands in practice — every MCP call is attributable to a specific user, and the audit log captures who approved the call. The residency layer is the "data governance" measure. Without the auth layer, you cannot demonstrate compliance with Article 9 to an EU regulator; with the auth layer, you have the audit trail.

DORA Article 9 requires financial entities to manage third-party ICT risk. An MCP server is a third-party ICT service the moment it is operated by a vendor (PagerDuty, Salesforce, Slack, etc.). The auth layer is where the third-party risk register lands in practice — every MCP server behind the auth boundary is enumerated, scoped, and audited. The residency layer is the "data location" requirement. Without the auth layer, you cannot demonstrate compliance with DORA Article 9; with the auth layer, you have the third-party risk register.

The good news: the auth layer that closes the EU AI Act + DORA gap is the same auth layer that closes the enterprise security gap. The investment is one quarter, and it pays back in security review velocity (the team can answer "who can call what" in one query, not three weeks of manual audit), in incident postmortem velocity (the audit log captures who/what/when, no need to reconstruct), and in regulator-readiness (the audit log is the compliance evidence).

What I do not have a good answer for yet

In the spirit of being clear about the open problems:

Standardized audit log format is still missing. Each vendor emits a different audit log format. Cloudflare uses Audit Logs JSON, Auth0 uses Log Streams JSON, Stytch uses Dashboard events, Stargate uses OTel spans. An enterprise running three of these vendors has three audit log parsers to maintain. The right shape is probably an OpenTelemetry-compatible audit log format standardized across vendors (an "MCP audit log spec"), but the vendors have not yet agreed on one. The closest is the OpenTelemetry GenAI semantic conventions, but those do not yet cover the per-tool scope and residency dimensions that the MCP audit log needs.

Residency primitives are not yet first-class in most vendors. Cloudflare, Auth0, and Stytch have regional primitives, but they are not yet first-class in the MCP-specific configuration. A tenant might be in the EU, but the MCP server's audit log might still be exported to a US region for log aggregation. The right shape is per-region audit log retention, with explicit opt-in for cross-region export. None of the four vendors ships this as a default yet.

Per-tool rate limit policy is hand-rolled. Each MCP deployment has to enumerate its destructive tools and set the rate limit manually. There is no "MCP rate limit policy" that ships with sensible defaults. The right shape is probably a per-tool-category default (destructive tools default to 10 calls/min/user, read-only tools default to 100 calls/min/user), but no vendor ships this yet. The pattern that does work: start with the defaults, instrument the false-positive rate, and tune per-tool.

None of these are reasons to wait. The four-vendor wave is happening now, the five deployment patterns are shipping in production at teams I have worked with in the last six months, and the EU AI Act + DORA compliance pressure is making the auth layer a board-level conversation rather than an engineering-team conversation. The teams running it are sleeping better, their security teams are not blocking MCP rollouts, and their auditors are not filing findings.

Recommended for Edge Auth Cloudflare

Edge auth, audit logs, and rate limiting for MCP servers

Recommended for IdP-Native Auth Auth0

OAuth/OIDC identity provider with native MCP auth support

Recommended for BYO Auth + Observability Portkey AI

AI gateway with BYO auth, observability, and cost tracking