返回 文章 apply CMS 文章

Cloudflare 如何检测 MCP 流量并保障其安全

了解 Cloudflare 如何利用协议信号识别 MCP 流量,并通过 Gateway、MCP 门户和策略控制来保护 AI 代理的工具调用。

CloudflareMCPAI安全零信任
成长分 / 100 69 综合收获、行动、留存与影响

Cloudflare 如何检测 MCP 流量并保障其安全
为什么值得读AI 代理的引入改变了安全风险模型,错误决策可能以人类无法企及的速度传播,需要新的防护手段。

MCP 流量难以通过 URL 识别,Cloudflare 提供了基于协议头的检测方法,为安全团队提供了可操作的信号。

关键洞察
  1. MCP 请求在客户端、网络和服务器三个位置可被控制,网络层具有最广泛的覆盖范围。
  2. Cloudflare Gateway 通过检查 MCP-Protocol-Version 头来识别 MCP 流量,并提供 experimental.is_mcp 选择器供策略使用。
  3. MCP 流量仪表板可显示服务器、用户和入口类型,帮助管理员发现影子 MCP 和门户绕过。
转成行动

深入阅读

正文与原文对照

原文保真覆盖:全文原文字符:25717

大多数公司在设计资源权限时,心里想的都是人类用户。一位资深工程师也许可以部署到生产环境、查询敏感数据库,或撤销其他用户的访问权限。这些特权伴随着风险,但这种风险历来受到两个假设的约束:工程师会运用人的判断力,并且工程师只能以人的速度行动。

工程师看到意料之外的结果时,通常会停下来重新考虑自己的操作。任何一个人,一天之内能点击、输入和审阅的内容都是有限的。AI 智能体的出现同时改变了这两道门槛。它们的决策具有非确定性,而且能无限次地重复同一个动作(或调用同一个工具),既不会疲倦,也不用停下来吃午饭。一个看似合理、实则错误的决策,可能在人类察觉之前就演变成成千上万次错误操作。

今天,我们宣布推出 Cloudflare One 的新功能:识别经过检查的 MCP 流量,显示是哪些用户和服务器产生了这些流量,并控制受管网络路径上的直接连接。结合 MCP Server Portals,这些控制能帮助管理员看清智能体用的是已批准的路径,还是以某种方式绕过了它。

Model Context Protocol(MCP)服务器为智能体提供了一种通用方式,用来发现并调用由第三方 SaaS 产品、内部应用和 API 支撑的工具。底层的权限机制想必并不陌生;变化的是由谁来做每一个决策,以及一个糟糕的决策能以多快的速度扩散。

把智能体接入这类工具,可能只需要一行配置。员工可以把 Claude Code、Codex、Cursor、OpenCode、VS Code 或任何 AI harness 指向某个 MCP 服务器,而无需确认它是否已获批准。由此产生的流量没有明显的特征。Model Context Protocol 并不使用固定的主机名,也不要求路径中包含 /mcp,所以直接连接看起来可能和任何其他 HTTPS API 调用没有区别。

为了说明这些控制手段如何配合,我们先从一次工具调用的结构及其暴露的信息讲起。接着对比安全团队可以采取行动的三个位置:客户端内部、网络上,以及 MCP 服务器端。然后,我们将展示 Cloudflare Gateway 如何利用协议信号来发现影子 MCP 流量,并强制要求仅通过 MCP Portal 访问受信任的 MCP 服务器。

MCP 工具调用的剖析

同一次 MCP 工具调用,在系统中流转时有三种形态。在客户端内部,它是一个以一组参数调用某个工具的决定。在网络上,它是一次携带 JSON-RPC 消息的 HTTP 事务。到了服务器端,它变成对某个工具处理程序的调用,该处理程序可能读取数据、更改状态,或完成其他操作。

设想一个想知道奥斯汀天气的智能体。一个远程 MCP 请求可能是这样的:

POST /mcp HTTP/1.1
Host: tools.example.com
Authorization: Bearer <access-token>
Content-Type: application/json
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: get_weather

{
  "jsonrpc": "2.0",
  "id": 42,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": {
      "city": "Austin"
    }
  }
}

这个请求中包含了几个有用的信号。主机名和路径标明了目的地。authorization 请求头携带的是服务器要求认证时用于验证调用方身份的凭据。请求头:MCP-Protocol-Version 标识协议版本,而 Mcp-Method 和 Mcp-Name 则在新的无状态协议中暴露了操作和工具。JSON-RPC 信封重复了该方法,为请求提供一个客户端可与响应匹配的 id,并在 params 中携带工具参数。

参数是最敏感的部分。它们可能包含搜索查询、源代码、客户数据,或创建工单、变更基础设施之类操作的指令。工具名称说明智能体打算调用什么;参数则说明它将发送什么数据,以及它希望服务器执行什么操作。

如果调用成功,服务器会返回一个带有相同 ID 的 JSON-RPC 响应以及工具结果。该响应也可能包含敏感数据。请求检查可以在执行前阻止不安全的操作,而响应检查和日志则能显示工具向智能体返回了什么。

控制 MCP 请求的三个位置

这个请求为安全团队提供了三个观察或控制调用的位置。

在 MCP 客户端内部

客户端钩子(client hook)可以在模型选定工具之后、客户端序列化请求之前运行。在这里,它可以看到目标服务器、工具名称和参数,而无需解密网络流量。

这是请求链路中最早可以施加控制的阶段。客户端可以拒绝不在允许列表上的服务器,要求用户确认敏感操作,或在数据离开设备之前从参数中移除数据。它还能覆盖本地 stdio(即本地)MCP 服务器,这类服务器从不产生网络流量。

这带来了标准化的挑战。安全团队要从中受益,就得在员工使用的每一种客户端上重复实现自己的控制措施。客户端控制在组织同时管理客户端和设备时效果最好,但来自某一个客户端的遥测数据永远无法构成 MCP 使用情况的完整清单。

在设备的网络边界

安全 Web 网关(secure web gateway)可以在 HTTP 请求离开客户端之后对其进行观察。借助 TLS 解密,它可以把请求与用户和设备关联起来,检查目的地和协议头,并在不依赖特定 MCP 客户端的情况下应用策略。

在受管路径上,网络层拥有检测远程 MCP 流量的最广视野。它能识别通往已批准 Portal 之外服务器的直接连接,并在请求到达目的地之前将其阻断。在支持数据防泄漏(DLP)扫描的情况下,代理还可以检查 JSON-RPC 方法和参数中是否含有敏感数据。不过,代理无法看到本地 stdio 调用或网络之外的流量。

在 MCP 服务器调用工具之前

服务器拥有最丰富的执行上下文。它已经对调用方完成了身份认证,解析了 MCP 消息,把 get_weather 解析到某个处理程序,并依据工具的输入 schema 校验了传入的参数。这是工具运行之前,请求还能被拒绝的最后一个节点。

Agents SDK 的处理程序或类似的服务器中间件,可以针对具体的工具对调用方授权、应用速率限制、检查参数并记录结果。服务器应当在调用处理程序之前执行这些检查,对写入数据或触发外部操作的工具尤其如此。只在执行之后记录日志,可以解释发生了什么,却无法阻止它发生。

Cloudflare 的 WriteGuard 在我们内部的 MCP 服务器上采用了这种模式。每个工具都有一个风险等级以及启用或禁用状态。WriteGuard 可以让读操作原样通过,为被允许的写操作添加智能体归属和审计事件,或在处理程序运行之前拦截关键操作。由于控制位于服务器端,终端用户无法通过切换客户端或禁用本地钩子来绕过它。

服务器端控制只能保护实现了它们的服务器,但客户端和服务器拥有最深的请求洞察,而网络则能看到最广泛的远程连接。三者结合使用,可以在敏感数据离开设备之前将其拦住,发现不受管的 MCP 流量,并在工具执行之前拒绝未经授权的操作。

网络控制点的覆盖面最广,但它首先得把 MCP 与普通 HTTPS 流量区分开来,用户必须在运行代理,而且 MCP 服务器(或 Portal)必须验证该连接确实经过了代理。

Cloudflare One 提供了这条链路中的网络部分。Cloudflare One Client 把受管设备的流量送入 Gateway。Gateway 可以在协议层对 MCP 请求进行分类,并区分流量是从 MCP Portal 发起的,还是正在绕开已批准的控制措施。管理员随后可以对不遵循批准路径的连接进行报告或阻断。这一过程始于可靠地识别请求。

仅凭 URL 无法判断请求是否使用了 MCP

我们最初查找 MCP 流量的方法,是用 GraphQL Analytics API 在 Gateway HTTP 日志中搜索主机名含有 mcp、路径为 /mcp 或 /sse 等常见值的记录。查询语句见我们的 MCP 流量检测教程。教程还介绍了如何为请求体中的 initialize、tools/call, 和 resources/read 等 MCP JSON-RPC 方法创建数据防泄漏模式。

这些信号对于发现来自较旧客户端的流量、提供历史可见性仍然有用,但它们非常初级。如果 MCP 服务器位于 https://tools.example.com/api 这样的普通 URL,它们就会漏掉,而这并不罕见。

它们还可能误匹配到恰好在主机名或路径中使用了 mcp 的无关服务(可能性不大,但我们确实见过)。对于符合规范的 Streamable HTTP 客户端,协议头是更具体的信号。MCP 2025-11-25 规范规定,客户端在初始化之后的每个 HTTP 请求中必须(MUST)包含 MCP-Protocol-Version。MCP 2026-07-28 规范更进一步,要求每个 POST 请求都包含它。

但这并不意味着该请求头就是一个完整的检测手段。传统客户端的初始请求可能不带它,早于 2025-06-18 的协议版本没有定义它,本地的 stdio、自定义传输或不合规的流量也可能始终不携带它。它的出现是 MCP 的有力正向信号;它的缺席并不能证明某个请求不是 MCP。

协议在网络层面正变得更容易识别

传统的 MCP 流程以一个不含 MCP-Protocol-Version HTTP 请求头的 initialize 请求开头,因此网络控制手段可能无法仅凭请求头对发往某个此前未知端点的第一个请求进行分类。该信号要等客户端与服务器完成初始化之后才会出现。

后续的一次工具调用如下所示:

POST /api HTTP/1.1
Host: tools.example.com
Content-Type: application/json
MCP-Protocol-Version: 2025-11-25

{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"get_weather"}}

MCP 2026-07-28 规范大幅改变了这一模型。核心协议是无状态的:它彻底移除了 initialize 握手,并把协议版本和操作放在每个请求上:

POST /mcp HTTP/1.1
Host: tools.example.com
Content-Type: application/json
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: get_weather

{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_weather"}}

Mcp-Method 和 Mcp-Name 请求头让普通的 HTTP 基础设施无需解析请求体就能识别操作。负载均衡器可以据此路由请求,限流器可以区分 tools/list 与 tools/call,安全产品也能从每个请求中获得更多信息。

这些协议信号让 Cloudflare Gateway 有了可以具体评估的依据,而不必依赖一份“看起来像 MCP 的 URL”清单。

影子 MCP 与绕过审批路径是两个不同的问题

一旦 Gateway 能够识别 MCP 流量,你就可以评估某个连接对你的安全态势意味着什么。

影子 MCP(Shadow MCP)是指连接到组织未批准的服务器。员工在某个代码仓库、产品指南或同事的消息里发现了这个服务器,就直接把它添加到自己的 MCP 客户端中。安全团队完全不知道它暴露了哪些工具,也不知道员工向它发送了什么数据。

Portal 绕过则有所不同:它始于一个已获批准、组织已将其放入 MCP Portal 的服务器,但员工直接连接其上游 URL,从而跳过了 Portal 的 Access 策略、精选工具目录、数据防泄漏以及工具级审计轨迹。

对于受管网络路径上的影子 MCP,Gateway 是主要的控制手段:它能识别经过 TLS 检查的 MCP 流量,显示目的地和用户,并可应用策略。Portal 绕过则除了这一网络控制之外,还需要源站能够拒绝直接请求,无论采用的是 Access 策略、源 IP 限制,还是由 MCP 服务器自身发起的企业授权机制。

在 Gateway 中检测 MCP 流量

对于已经采用 Cloudflare Gateway 并启用 TLS 检查的客户,我们正在加入一种检测启发式方法,针对每个被检查的请求回答一个简单的问题:这是 MCP 流量吗?

对于基于会话的 Streamable HTTP 连接,MCP 客户端会在初始化之后发送 MCP-Protocol-Version 请求头。Gateway 会在每个经过 TLS 检查的请求上检查该请求头并据此对流量分类,所用的检测基于我们在每天穿越 Cloudflare 网络的数百万个请求中观察到的模式。这一分类无需事先知道具体的主机或 URL,就能识别出发往某个主机名的 MCP 协商与代理流量。

从今天起,所有 Cloudflare Zero Trust 客户都能在其 Gateway HTTP 日志中看到 MCP 流量的迹象,并可通过一个新的 Gateway 选择器明确阻止或允许此类流量:

experimental.is_mcp == true

该选择器是一个布尔值。如果 Gateway 在某个经过 TLS 检查的请求上检测到 MCP-Protocol-Version 请求头,其值即为 true,管理员可以在 Allow 或 Block 策略中使用它,而无需自行维护一份“看起来像 MCP 的域名”清单。

直接的加密流量必须先经过 TLS 解密,Gateway 才能检查这些请求头;本地的 stdio 服务器、网络之外的连接、Do Not Inspect 流量,以及从未经过 Gateway 的请求,仍然不在这一视图的范围内。

全网络范围内的 MCP 流量可见性

今天,我们推出一个专用的 MCP 流量仪表板,显示网络中有哪些主机在提供 MCP 流量、哪些用户在产生这些流量,以及请求是经由你的 Cloudflare MCP Portal 发出,还是完全绕过了它们。

image4.png

仪表板显示:

  • 在可配置的时间窗口内的 MCP 请求总数、独立用户数和独立服务器数
  • MCP 服务器随时间的变化,以及每台服务器的请求数
  • 按接入方式(on-ramp)划分的流量拆分,把 MCP Portal 流量与设备客户端直连区分开
  • Portal 之外出现的 MCP 服务器排名靠前者,也就是最需要关注的影子 MCP 流量
  • 按 MCP 请求量排名靠前的用户

image2.png

管理员可以按特定服务器、用户或接入方式类型进行筛选,并直接跳转到按相应主机或用户过滤的 Gateway HTTP 日志,以便深入调查。

image1.png

把发现的服务器纳入 MCP Portal

MCP 发现把未知流量变成一份管理员可以调查的清单。当组织批准其中某台服务器后,可以把它放到 Cloudflare MCP 服务器 Portal 之后。Portal 为员工提供一个统一的受管端点,并在上游服务器之前加上 Access 身份验证、精选工具目录和日志记录。管理员可以让兼容的上游调用经由 Gateway 路由,以获得 HTTP 策略、可预测的出口以及数据防泄漏能力,可以作用于整个 Portal,也可以只针对单台服务器。工具活动还可以通过 Logpush 导出。发现仪表板随后便能区分使用 Portal 的请求与直连同一服务器的请求。

这就形成了一条从发现到治理的路径:找到服务器,决定是否批准,把获批的使用迁移到 Portal 之后,并调查仍然绕过 Portal 的流量。最后一步很重要,因为未获批准的服务器和对已批准服务器的绕过是两个不同的问题。

强制仅通过 Portal 访问

我们正在向 Gateway Network 和 HTTP 策略中加入 Traffic Source(流量来源)选择器,让管理员能够精细地编写规则,根据 MCP 流量是否来自你的 MCP Portal 来加以控制。

当 MCP Portal 流量经由 Gateway 路由时,它会带上 mcp_portal 流量来源,使策略能够区分经 Portal 代理的请求与员工的直接连接。一条基线强制规则如下所示:

experimental.is_mcp == true and not traffic.onramp in ("mcp_portal")
Action: Block

image3.png

任何未经由 Portal 到达的已检测 MCP 流量都会被阻止;经由 Portal 的流量不受影响。对于希望先观察再强制执行的组织,流量来源和 MCP 检测现在已出现在已解密流量的 HTTP 日志中,因此无需策略就可以监控被代理流量的行为。

更多 MCP 服务器现在可以使用受治理的路径

一条获批的路径,只有能连接到员工真正需要的大部分服务器,才有价值。

早期的 MCP 规范推荐使用动态客户端注册(Dynamic Client Registration),即客户端无需 OAuth 应用就向授权服务器自行注册。许多常见的 OAuth 提供方采用的是另一种模型:要求管理员用固定的客户端 ID、客户端密钥、回调 URL 和一组作用域来注册应用。MCP 2026-07-28 最近也已弃用动态注册。

为缓解这一问题,MCP Portal 现在支持预注册的 OAuth 客户端。管理员可以配置手动 OAuth 凭据,在上游提供方处注册仪表板中显示的回调 URL,并填入客户端凭据。Portal 会在可用时发现标准的 OAuth 元数据;在无法发现时,管理员可以自行提供授权、令牌、撤销和颁发者端点。

每位用户仍然各自授权访问自己的上游数据源,而存储的客户端密钥只用于获取更新后的工具和提示词列表。

手动 OAuth 支持现在有助于覆盖形形色色的 OAuth 实现。有些提供方要求自定义请求头、个人访问令牌或明确的客户端允许列表,这些属于另外的兼容性问题。未来几个月,我们将继续扩展 MCP Portal 的 OAuth 支持。

把私有 MCP 服务器纳入同一个 Portal

公共 SaaS 工具只是企业 MCP 目录的一部分。企业所依赖的大多数敏感信息无法从公共互联网获取;它们位于公有云或私有云基础设施中,或托管在本地机房,只能通过与私有网络的连接才能访问。

目前,MCP Portal 必须能够通过公共互联网解析并访问上游服务器。这意味着,只在私有网络上可用的服务器(通过私有 DNS 或位于私有 IP 空间内)无法被 Portal 访问。我们正在努力让 MCP Portal 通过 Cloudflare Gateway 路由以及已用于其他私有应用的同一 Cloudflare One 网络连接到私有服务器。

私有服务器保留其私有主机名;Portal 通过 Cloudflare 的私有路由访问它,并把它的工具与公共上游服务器的工具并列呈现;Access 策略、Portal 日志和工具控制则继续在同一个入口生效。

把 Portal 流量路由经过 Gateway 还会给它打上 mcp_portal 流量来源标记,使 Gateway 策略能够区分 Portal 请求与员工的直接连接。面向 MCP 服务器的私有连接正在积极开发中;请关注 Changelog 获取更多信息。

Agents SDK 支持新的无状态模型

几周前,MCP 项目发布了 2026-07-28 规范,这是一次重大修订,用无状态的、按请求处理的模型取代了以连接为范围的初始化。我们在 The next generation of MCP 中介绍了协议变化与迁移路径。

Cloudflare Agents SDK v0.20.0 同时支持以客户端和服务器身份使用 MCP 2026-07-28。对于每个连接,客户端会先用 server/discover 探测新的无状态协议;如果服务器不支持,客户端会在同一连接上继续使用传统的 initialize 握手。现有的 addMcpServer 调用不需要单独的协议设置或单独的客户端。

在服务器端,createMcpHandler 可以在 Worker 中提供无状态的工具、提示词、资源和征询(elicitation)功能,而无需创建传输会话或 Durable Object:

import { McpServer } from "@modelcontextprotocol/server";
import { createMcpHandler } from "agents/mcp/server";

function createServer() {
  return new McpServer({ name: "example", version: "1.0.0" });
}

export default {
  fetch(request, env, ctx) {
    return createMcpHandler(createServer)(request, env, ctx);
  },
} satisfies ExportedHandler;

这种回退机制很重要,因为协议迁移很少一次性完成。新客户端仍然需要连接现有服务器,新服务器也仍然需要处理尚未迁移的客户端。在生态系统过渡期间,Agents SDK 同时支持这两条路径。

从可见性入手,再封堵本不该存在的路径

一套可行的 MCP 安全方案,始于了解用户的流量特征和 MCP 使用情况,并就一组获批的工具和访问方式达成一致。

首先,检查经过 Gateway 的 MCP 流量,把它的目的地与组织已批准的服务器进行对比。把更多获批的服务器迁移到 MCP Portal 之后。

然后,对你能够控制的边界实施强制。组合使用 MCP 检测条件以及流量来源和目的地条件来编写 Gateway 策略,阻止来自受管设备和站点的 MCP 直连,并尽可能把自托管的上游服务器限制为仅接受 Portal 流量。

我们很快将加入更细粒度的 MCP 流量可见性与控制功能,包括对特定工具使用的控制,以及针对你环境中所有 MCP 服务器(无论安全团队是否知晓)的工具使用情况的新报告。

我们的 MCP 流量检测教程介绍了目前可用于 Gateway 日志的主机名、路径和 JSON-RPC 启发式方法。待新的信号正式发布(GA)后,我们会更新文档,补充协议选择器的详细信息。