Skip to content

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

  1. 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)

  2. 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.

  3. Client, network, and server each cover a different gap.

  4. Client hook (e.g. a Claude Code hook): earliest control, sees destination + tool + arguments without decrypting traffic, and can cover local stdio servers 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."
  5. 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 stdio or off-network traffic.
  6. 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."

  7. 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.

  8. 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 mcp and paths like /mcp or /sse — remains useful for older clients + history but is "very basic": it misses an MCP server at an ordinary URL like https://tools.example.com/api and can false-match an unrelated service that merely uses mcp in a host/path.

  9. The protocol header is a strong positive signal (but not a complete detector). Conforming Streamable HTTP clients send MCP-Protocol-Version on 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 initial initialize request may omit it, protocol versions before 2025-06-18 didn't define it, and local stdio / 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.

  10. The 2026-07-28 stateless model makes MCP even easier to identify on the wire. Removing the initialize handshake and putting the protocol version

  11. operation on every request via Mcp-Method / Mcp-Name headers "let ordinary HTTP infrastructure identify the operation without parsing the body" — load balancers can route, rate limiters can separate tools/list from tools/call, and security products get more per-request signal. (See the sibling next-generation-of-MCP post and protocol-metadata-in-http-headers.)

  12. Gateway ships a detection heuristic + a boolean selector. For customers already on Gateway with TLS inspection, Cloudflare inspects MCP-Protocol-Version on 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 selector experimental.is_mcp == true. Out of view: local stdio, off-network connections, Do Not Inspect traffic, and anything that never traverses Gateway. Canonical protocol-header-traffic-classification instance.

  13. 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).

  14. Portal-only enforcement uses a Traffic Source selector. When Portal traffic routes through Gateway it carries an mcp_portal Traffic Source, so a baseline rule experimental.is_mcp == true and not traffic.onramp in ("mcp_portal") → Block blocks 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.

  15. 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.

  16. 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-28 deprecated 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; the mcp_portal Traffic 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_portal Traffic 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 repeating method, an id, and params.
  • 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, true when MCP-Protocol-Version is 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-Version MUST after init), MCP 2026-07-28 (required on every POST; stateless; DCR deprecated), RFC 7591 (Dynamic Client Registration).

Caveats

  • The experimental.is_mcp selector is experimental (name carries the experimental. prefix); detection-selector details will be documented as the signal reaches general availability.
  • Detection is coverage-bounded: local stdio servers, off-network / non- Gateway traffic, Do Not Inspect traffic, and legacy/custom transports that omit MCP-Protocol-Version are 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

  • 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_portal Traffic 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.
Last updated · 766 distilled / 2,225 read