How Cloudflare detects MCP traffic and helps secure it¶
Summary¶
Cloudflare adds Cloudflare One capabilities to
detect MCP traffic on the wire, attribute
it to users and servers, and enforce that agents reach approved MCP servers
only through a governed path. The security problem AI agents create is not a
new permission model but a speed and volume one: an agent's decisions are
nondeterministic and it can invoke the same tool indefinitely, so "a plausible
— but incorrect — decision can become thousands of incorrect actions before a
human notices." Connecting an agent to a SaaS/internal/API tool via MCP takes
one line of config, and the resulting traffic "has no obvious shape" — MCP
does not require a specific hostname or /mcp path, so a direct connection can
look like any other HTTPS API call. The post frames three places to control a
tool call (inside the client, on the network, at the server), shows how
Cloudflare Gateway classifies MCP at the protocol
layer via the MCP-Protocol-Version header (experimental.is_mcp == true),
distinguishes shadow MCP from Portal
bypass, and enforces Portal-only access with a traffic.onramp selector.
Also covers server-side WriteGuard per-tool
authorization, MCP-Portal pre-registered OAuth support, and private-server
Portal routing.
Key takeaways¶
-
The agent threat is speed × nondeterminism, not a new privilege model. Resource permissions were designed for a human user who "will usually stop and reconsider" and can only act at human speed. AI agents remove both bounds — decisions are nondeterministic and repeatable without fatigue — so the same familiar permissions become dangerous at machine cadence. (Source: sources/2026-08-14-cloudflare-how-cloudflare-detects-mcp-traffic-and-helps-secure-it)
-
An MCP tool call has three forms; each is a control point. The same call is (a) a decision inside the client to invoke a tool with arguments, (b) an HTTP transaction carrying a JSON-RPC message on the network, and (c) a handler invocation at the server that may read data, change state, or act. This is the three-control-points framing — client / network / server — each with a different visibility × coverage × bypass-resistance trade-off.
-
Client, network, and server each cover a different gap.
- Client hook (e.g. a Claude Code hook):
earliest control, sees destination + tool + arguments without decrypting
traffic, and can cover local
stdioservers that never touch the network — but requires reproducing controls across every client an org uses, so "telemetry from one client is never a complete inventory." - Network (a secure web gateway
with TLS decryption): the widest lens for
remote MCP on managed paths — associates a request with user + device,
inspects destination + protocol headers, can block direct connections to
non-approved servers, and (where DLP is supported) inspect JSON-RPC method +
arguments — but cannot see local
stdioor off-network traffic. -
Server (an Agents SDK handler or middleware): the richest execution context — has authenticated the caller, parsed the message, resolved the tool, validated arguments — and is the last point a request can be denied before the tool runs. Only protects servers that implement it, but "an end user cannot bypass it by switching clients or disabling a local hook."
-
The arguments are the most sensitive part of the request. The tool name says what the agent intends to call; the arguments say what data it sends and what action it wants performed (a search query, source code, customer data, an instruction to create a ticket or change infrastructure). Request inspection can stop an unsafe action before execution; response inspection/logging shows what was returned after.
-
A URL does not tell you a request is MCP. Cloudflare's first approach — GraphQL Analytics API searches of Gateway HTTP logs for hostnames containing
mcpand paths like/mcpor/sse— remains useful for older clients + history but is "very basic": it misses an MCP server at an ordinary URL likehttps://tools.example.com/apiand can false-match an unrelated service that merely usesmcpin a host/path. -
The protocol header is a strong positive signal (but not a complete detector). Conforming Streamable HTTP clients send
MCP-Protocol-Versionon requests after initialization: the MCP 2025-11-25 spec says clients MUST include it on every HTTP request after init; the MCP 2026-07-28 spec requires it on every POST. Caveats: a legacy client's initialinitializerequest may omit it, protocol versions before 2025-06-18 didn't define it, and localstdio/ custom transports may never carry it — "its presence is a strong positive indicator of MCP; its absence does not prove that a request is not MCP." Canonical mcp-protocol-version-header instance. -
The 2026-07-28 stateless model makes MCP even easier to identify on the wire. Removing the
initializehandshake and putting the protocol version -
operation on every request via
Mcp-Method/Mcp-Nameheaders "let ordinary HTTP infrastructure identify the operation without parsing the body" — load balancers can route, rate limiters can separatetools/listfromtools/call, and security products get more per-request signal. (See the sibling next-generation-of-MCP post and protocol-metadata-in-http-headers.) -
Gateway ships a detection heuristic + a boolean selector. For customers already on Gateway with TLS inspection, Cloudflare inspects
MCP-Protocol-Versionon every TLS-decrypted request and classifies traffic using "detection built from patterns we observe across the millions of requests that traverse the Cloudflare network every day" — "identifies MCP negotiation and proxying to a hostname without relying on knowing the specific host or URL ahead of time." All Zero Trust customers now see MCP indications in Gateway HTTP logs and can Allow/Block on the new selectorexperimental.is_mcp == true. Out of view: localstdio, off-network connections, Do Not Inspect traffic, and anything that never traverses Gateway. Canonical protocol-header-traffic-classification instance. -
Shadow MCP and Portal bypass are separate problems. Shadow MCP is a connection to a server the org never approved (found in a repo/guide/message, added directly to a client). Portal bypass starts with an approved server placed in an MCP Portal but the employee connects to the upstream URL directly, skipping the Portal's Access policy, curated tool catalog, DLP, and tool-level audit trail. Gateway is the primary control for shadow MCP on managed paths; Portal bypass additionally needs an origin that can reject direct requests (Access policy, source-IP restriction, or an enterprise authorization mechanism the MCP server itself initiates).
-
Portal-only enforcement uses a Traffic Source selector. When Portal traffic routes through Gateway it carries an
mcp_portalTraffic Source, so a baseline ruleexperimental.is_mcp == true and not traffic.onramp in ("mcp_portal") → Blockblocks any detected MCP that didn't arrive through a Portal while leaving Portal-proxied traffic untouched. Observe-before-enforce is supported because both signals exist in HTTP logs for decrypted traffic. Canonical portal-only-egress-enforcement instance. -
WriteGuard is the server-side per-tool gate Cloudflare runs internally. Each tool has a risk tier and an enabled/disabled state; WriteGuard can pass a read through unchanged, add agent attribution + an audit event to an allowed write, or block a critical action before its handler runs. Because the control lives at the server, "an end user cannot bypass it by switching clients or disabling a local hook." Canonical patterns/tool-surface-minimization instance; a productised sibling to intent/tool-level authorization patterns elsewhere in the wiki.
-
Discovery → governance is a workflow, and more servers can now use the governed path. Discovered servers can be brought behind an MCP Portal (one managed endpoint + Access identity + curated tool catalog + logging + optional Gateway routing for HTTP policy/DLP/predictable egress + Logpush). MCP Portals now support pre-registered OAuth clients (fixed client ID/secret/callback/scopes) because many OAuth providers require an admin to register an application rather than use Dynamic Client Registration (RFC 7591) — and MCP
2026-07-28deprecated dynamic registration. Cloudflare is also working to let Portals reach private-network servers via Gateway routing + the Cloudflare One network (private server keeps its private hostname; Access policy + Portal logging + tool controls still apply at the same front door; themcp_portalTraffic Source is stamped on the routed traffic).
Systems / concepts / patterns extracted¶
- Systems: systems/cloudflare-gateway (the secure web gateway doing the
protocol-layer MCP classification + Portal-only enforcement);
systems/cloudflare-one (the Zero Trust suite this ships under);
systems/mcp-server-portal (the governed path — extended here with
pre-registered OAuth + private-server routing + the
mcp_portalTraffic Source); systems/writeguard (server-side per-tool risk-tiered authorization on Cloudflare's internal MCP servers); systems/model-context-protocol (the protocol being detected/governed); systems/cloudflare-access (origin identity that makes Portal bypass rejectable); systems/cloudflare-agents-sdk (the server-side handler altitude for tool authorization). - Concepts: shadow-mcp (unapproved-server connections vs. Portal bypass); mcp-protocol-version-header (the wire detection signal + its false-negative bound); three-control-points-for-agent-tool-calls (client/network/server framing); tls-decryption (the precondition for network-layer header inspection); dynamic-client-registration (the deprecated OAuth path pre-registration replaces); concepts/stateless-compute (why 2026-07-28 headers are wire-visible).
- Patterns: protocol-header-traffic-classification (classify a protocol by a mandatory header instead of URL/host heuristics); portal-only-egress-enforcement (allow protocol traffic only when it carries the governed on-ramp tag); patterns/tool-surface-minimization (risk-tier + enabled-state check at the handler, unbypassable by client choice); patterns/central-proxy-choke-point (the network gateway as the single vantage point for MCP visibility + control).
Operational numbers / concrete signals¶
- Wire example (2026-07-28 stateless remote request):
POST /mcp,MCP-Protocol-Version: 2026-07-28,Mcp-Method: tools/call,Mcp-Name: get_weather, plus a JSON-RPC envelope repeatingmethod, anid, andparams. - Detection heuristic input: "millions of requests that traverse the Cloudflare network every day" (no precise MCP request-volume figure disclosed).
- Gateway selector:
experimental.is_mcp(boolean,truewhenMCP-Protocol-Versionis present on a TLS-inspected request). - Enforcement rule:
experimental.is_mcp == true and not traffic.onramp in ("mcp_portal")→ Block. - DLP-detectable JSON-RPC methods called out:
initialize,tools/call,resources/read. - Standards cited: MCP 2025-11-25 (
MCP-Protocol-VersionMUST after init), MCP 2026-07-28 (required on every POST; stateless; DCR deprecated), RFC 7591 (Dynamic Client Registration).
Caveats¶
- The
experimental.is_mcpselector is experimental (name carries theexperimental.prefix); detection-selector details will be documented as the signal reaches general availability. - Detection is coverage-bounded: local
stdioservers, off-network / non- Gateway traffic, Do Not Inspect traffic, and legacy/custom transports that omitMCP-Protocol-Versionare outside the network view. Header absence does not prove non-MCP. - Network-layer inspection requires TLS decryption; without it Gateway cannot read the header.
- Portal-bypass prevention requires both the network control and an origin that can reject direct requests — the network layer alone cannot force Portal-only access if the upstream accepts direct connections.
- Private-server Portal routing is described as "in active development" — not yet GA. Manual/pre-registered OAuth "now helps cover the many permutations" but Cloudflare notes custom headers / PATs / explicit client allowlists remain separate compatibility problems.
- No latency/throughput numbers for the detection or DLP path are disclosed.
Source¶
- Original: https://blog.cloudflare.com/mcp-security-updates/
- Raw markdown:
raw/cloudflare/2026-08-14-how-cloudflare-detects-mcp-traffic-and-helps-secure-it-7dd5d84b.md
Related¶
- systems/cloudflare-gateway — the secure web gateway that classifies MCP at the protocol layer and enforces Portal-only access.
- systems/mcp-server-portal — the governed MCP path; extended here with
pre-registered OAuth, private-server routing, and the
mcp_portalTraffic Source. - systems/writeguard — server-side risk-tiered per-tool authorization on Cloudflare's internal MCP servers.
- shadow-mcp — unapproved-server connections vs. approved-server Portal bypass.
- mcp-protocol-version-header — the wire signal that distinguishes MCP from ordinary HTTPS.
- three-control-points-for-agent-tool-calls — client / network / server control-point framing.
- protocol-header-traffic-classification — classify a protocol by a mandatory header rather than URL/host heuristics.
- portal-only-egress-enforcement — allow MCP traffic only when it carries the governed on-ramp tag.
- patterns/tool-surface-minimization — unbypassable per-tool authorization at the handler.
- sources/2026-08-06-cloudflare-the-next-generation-of-mcp — the stateless 2026-07-28 protocol change that makes MCP wire-detectable.