Cloudflare 如何检测 MCP 流量并帮助保护其安全

大多数公司在设计资源权限时,考虑的是人类用户。高级工程师可能能够部署到生产环境、查询敏感数据库或撤销其他用户的访问权限。这些特权伴随着风险,但传统上,这种风险受到两个假设的限制:工程师会运用人类判断力,并且工程师只能以人类的速度行动。
看到意外结果的工程师通常会停下来重新考虑他们的行动。任何人在一天内只能点击、键入和审查这么多。AI 代理的引入改变了这两个阈值。它们的决策是非确定性的,并且它们可以无限地采取相同的行动(或调用相同的工具),而不会感到疲倦或停下来吃午饭。一个看似合理但错误的决策,可能在人类注意到之前变成数千个错误行动。
今天,我们宣布新的 Cloudflare One 功能,用于识别已检查的 MCP 流量,显示哪些用户和服务器正在生成它,并控制受管网络路径上的直接连接。结合 MCP 服务器门户,这些控制帮助管理员查看代理是否使用了批准的路径,或者以某种方式绕过了它。
MCP 服务器门户 模型上下文协议(MCP)服务器为代理提供了一种通用方式来发现和调用由第三方 SaaS 产品、内部应用程序和 API 支持的工具。底层权限可能很熟悉;改变的是谁做出每个决策,以及一个错误决策传播的速度有多快。
将代理连接到这些工具之一可能只需要一行配置。员工可以将 Claude Code、Codex、Cursor、OpenCode、VS Code 或任何 AI 工具指向 MCP 服务器,而无需检查它是否被批准。由此产生的流量没有明显的形状。模型上下文协议不保证使用主机名,也不要求在路径中包含 /mcp,因此直接连接看起来就像任何其他 HTTPS API 调用。
为了解释这些控制如何组合在一起,我们将从工具调用的结构及其暴露的信息开始。然后,我们将比较安全团队可以采取行动的三个位置:客户端内部、网络上和 MCP 服务器处。接下来,我们将展示 Cloudflare Gateway 如何使用协议信号来发现影子 MCP 流量,并强制仅通过 MCP 门户访问受信任的 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"
}
}
}
这个请求中包含了几个有用的信号。主机名和路径标识了目的地。授权头携带了在服务器需要时用于验证调用者身份的凭据。头字段:MCP-Protocol-Version
标识协议版本,而 Mcp-Method
和 Mcp-Name
在新的无状态协议中暴露了操作和工具。JSON-RPC 信封重复了方法,给请求一个 id
,客户端可以用它来匹配响应,并在 params
中携带工具参数。
参数是最敏感的部分。它们可以包含搜索查询、源代码、客户数据或操作指令,例如创建工单或更改基础设施。工具名称说明了代理打算调用什么;参数说明了它将发送什么数据以及它希望服务器执行什么操作。
如果调用成功,服务器返回一个具有相同 id 和工具结果的 JSON-RPC 响应。该响应也可能包含敏感数据。请求检查可以在执行前阻止不安全的操作,而响应检查和日志记录则显示工具返回给代理的内容。
控制 MCP 请求的三个位置
该请求为安全团队提供了三个观察或控制调用的位置。
在 MCP 客户端内部
一个客户端钩子可以在模型选择工具之后、客户端序列化请求之前运行。从那里,它可以查看目标服务器、工具名称和参数,无需解密网络流量。
这是请求链中最早可以实施控制的阶段。客户端可以拒绝不在允许列表中的服务器,要求用户确认敏感操作,或在数据离开设备之前从参数中删除数据。它还可以覆盖本地 stdio
(即本地)MCP 服务器,这些服务器从不产生网络流量。
这带来了标准化挑战。为了使安全团队从中受益,他们需要在员工使用的每个客户端上复制他们的控制措施。当组织同时管理客户端和设备时,客户端侧控制效果最好,但来自一个客户端的遥测数据永远不是 MCP 使用的完整清单。
在设备的网络边界
一个安全 Web 网关可以在请求离开客户端后观察 HTTP 请求。通过TLS 解密,它可以将请求与用户和设备关联,检查目的地和协议头,并应用策略,而不依赖于特定的 MCP 客户端。
网络层拥有最宽的视野,可以检测受管路径上的远程 MCP 流量。它可以识别到批准门户之外服务器的直接连接,并在请求到达目的地之前阻止它们。在支持数据丢失防护扫描的地方,代理还可以检查 JSON-RPC 方法和参数中的敏感数据。然而,代理无法看到本地 stdio
调用或网络外流量。
在 MCP 服务器调用工具之前
服务器拥有最丰富的执行上下文。它已经验证了调用者,解析了 MCP 消息,解析了 get_weather
给处理器,并根据工具的输入模式验证提供的参数。这是工具运行前请求可以被拒绝的最后一点。
一个 Agents SDK 处理器或类似的服务器中间件可以授权调用者使用特定工具,应用速率限制,检查参数,并记录结果。服务器应在调用处理器之前执行这些检查,尤其是对于写入数据或触发外部操作的工具。仅在执行后记录日志可以解释发生了什么,但无法阻止它。
Cloudflare 的 WriteGuard 在我们内部的 MCP 服务器中使用了这种模式。每个工具都有风险等级和启用或禁用状态。WriteGuard 可以原样传递读取操作,为允许的写入添加代理归属和审计事件,或者在处理器运行前阻止关键操作。由于控制位于服务器端,最终用户无法通过切换客户端或禁用本地钩子来绕过它。
虽然服务器端控制仅保护实现它们的服务器,但客户端和服务器具有最佳的请求深度。网络可以看到最广泛的远程连接。结合使用这些控制,可以在敏感数据离开设备之前阻止它,发现未管理的 MCP 流量,并在工具执行前拒绝未经授权的操作。
网络控制点具有最广泛的覆盖范围,但首先必须将 MCP 与普通 HTTPS 流量区分开来,用户必须运行代理,并且 MCP 服务器(或门户)必须验证连接中使用了代理。
Cloudflare One 提供了该链路的网络组件。 Cloudflare One Client 将受管理设备的流量通过 Gateway 发送。Gateway 可以在协议层对 MCP 请求进行分类,并区分流量是来自 MCP 门户,还是超出批准的控件。然后,管理员可以报告或阻止不遵循批准路径的连接。该过程始于可靠地识别请求。
URL 并不能告诉你请求是否使用 MCP
我们最初查找 MCP 流量的方法是使用 GraphQL Analytics API 搜索 Gateway HTTP 日志 中包含
mcp
的主机名以及常见的路径,如 /mcp
或 /sse
。我们的包括查询。它还解释了如何创建
MCP 流量检测教程像
数据丢失防护模式,用于 MCP JSON-RPC 方法initialize
、tools/call,
和 resources/read
在请求体中。这些信号对于发现来自旧客户端的流量和提供历史可见性仍然有用,但它们非常基础。它们会漏掉位于普通 URL(如 https://tools.example.com/api)的 MCP 服务器,这并不罕见。
而且它们可能匹配到恰好使用 mcp 的不相关服务
在主机名或路径中(不太可能,但我们见过)。对于符合 Streamable HTTP 的客户端,协议头是更具体的信号。MCP 2025-11-25 规范 说明客户端
必须
在初始化后的每个 HTTP 请求中包含
MCP-Protocol-Version
。该规范 进一步要求在每个 POST 请求中包含它。
MCP 2026-07-28 规范
这并不使该头成为完整的检测器。来自旧版客户端的初始请求可能不包含它,早于 2025-06-18 的协议版本未定义它,本地 stdio、自定义传输或不合规的流量可能永远不会携带它。它的存在是 MCP 的强正向指标;它的缺失并不能证明请求不是 MCP。
协议在网络上变得越来越容易识别
旧版 MCP 流程以 initialize 请求开始,该请求不包含 MCP-Protocol-Version HTTP 头,因此网络控制可能无法仅从头文件对先前未知端点的第一个请求进行分类。信号在客户端和服务器完成初始化后出现。
后续的工具调用如下所示:
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"}}
The 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 是连接到组织未批准的服务器。员工在存储库、产品指南或同事的消息中找到服务器,并将其直接添加到他们的 MCP 客户端。安全团队不知道它暴露了哪些工具,也不知道员工向它发送了哪些数据。
门户绕过则不同:它始于组织已放置在 MCP 门户中的已批准服务器,但员工直接连接到其上游 URL,并跳过门户的访问策略、精选工具目录、数据丢失防护和工具级审计跟踪。
Gateway 是受管网络路径上影子 MCP 的主要控制手段;它识别经过 TLS 检查的 MCP 流量,显示目的地和用户,并可以应用策略。门户绕过需要该网络控制以及能够拒绝直接请求的源站,无论是访问策略、源 IP 限制,还是由 MCP 服务器本身启动的企业授权机制。
## 在 Gateway 中检测 MCP 流量
对于已经采用 Cloudflare Gateway 并启用 TLS 检查的客户,我们正在添加一个检测启发式规则,为每个检查的请求回答一个简单的问题:这是 MCP 流量吗?
对于基于会话的流式 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`
,管理员可以在允许或阻止策略中使用它,而无需维护自己的 MCP 样式域名列表。
直接加密流量必须经过 [TLS 解密](https://developers.cloudflare.com/cloudflare-one/traffic-policies/http-policies/tls-decryption/) 后,Gateway 才能检查这些头,而本地
`stdio`
服务器、网络外连接、[流量以及从未经过 Gateway 的请求仍在此视图之外。](https://developers.cloudflare.com/cloudflare-one/traffic-policies/http-policies/#do-not-inspect)
__不检查__## 跨网络查看 MCP 流量
今天,我们推出一个专门的 MCP 流量仪表板,显示哪些主机在您的网络中提供 MCP 流量,哪些用户产生该流量,以及请求是通过您的 Cloudflare MCP 门户还是完全绕过它们。

仪表板显示:
- 可配置时间窗口内的 MCP 请求总数、唯一用户和唯一服务器
- 随时间变化的 MCP 服务器及每台服务器的请求计数
- 按入口划分的流量细分,将 MCP 门户流量与直接设备客户端连接分开
- 在门户之外看到的热门 MCP 服务器,这是最重要的影子 MCP 流量
- 按 MCP 请求量排名的热门用户

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

## 将发现的服务器引入 MCP 门户
MCP 发现将未知流量转化为管理员可以调查的列表。当组织批准其中一台服务器时,可以将其放在 Cloudflare MCP 服务器门户后面。门户为员工提供一个受管端点,并在上游服务器前放置 [Access](https://developers.cloudflare.com/cloudflare-one/access-controls/) 身份、精选工具目录和日志记录。管理员可以
[为 HTTP 策略、可预测出口和数据丢失防护,跨门户或针对单个服务器。工具活动也可以](https://developers.cloudflare.com/cloudflare-one/access-controls/ai-controls/mcp-portals/#route-portal-traffic-through-gateway)
__通过 Gateway 路由兼容的上游调用__[。然后,发现仪表板可以区分使用门户的请求与直接连接到同一服务器的请求。](https://developers.cloudflare.com/cloudflare-one/access-controls/ai-controls/mcp-portals/#export-logs-with-logpush)
__通过 Logpush 导出__这创建了一条从发现到治理的路径:找到服务器,决定是否批准,将批准的使用移到门户后面,并调查继续绕过它的流量。最后一步很重要,因为未批准的服务器和绕过已批准的服务器是不同的问题。
## 强制仅通过门户访问
我们正在向 [Gateway 网络策略](https://developers.cloudflare.com/cloudflare-one/traffic-policies/network-policies/) 和
[HTTP 策略](https://developers.cloudflare.com/cloudflare-one/traffic-policies/http-policies/) 添加流量来源选择器,
__HTTP 策略__为管理员提供保真度,以根据流量是否来自您的 MCP 门户来编写规则控制 MCP 流量。当 MCP 门户流量通过 Gateway 路由时,它携带 `mcp_portal`
流量来源,使策略能够区分门户代理的请求和直接员工连接。基线强制规则如下所示:
experimental.is_mcp == true and not traffic.onramp in ("mcp_portal")
动作:阻止

任何检测到的未通过Portal到达的MCP流量都会被阻止;通过Portal的流量不受影响。对于希望在强制执行前进行观察的组织,现在在已解密的流量的HTTP日志中提供了流量来源和MCP检测,因此您可以在无需策略的情况下监控代理流量的行为。
## 更多MCP服务器现在可以使用受治理的路径
批准的路径只有在能够连接到员工实际需要的关键服务器时才有用。
早期的MCP规范推荐了[动态客户端注册](https://datatracker.ietf.org/doc/html/rfc7591),即客户端在没有OAuth应用程序的情况下向授权服务器注册自身。许多常见的OAuth提供商使用不同的模型:它们要求管理员注册一个具有固定客户端ID、客户端密钥、回调URL和作用域集的应用程序。MCP
`2026-07-28`
最近也弃用了动态注册。为帮助缓解这一问题,MCP Portal现在支持预注册的OAuth客户端。管理员可以[配置手动OAuth凭据](https://developers.cloudflare.com/cloudflare-one/access-controls/ai-controls/mcp-portals/#configure-manual-oauth-credentials),在仪表板中显示的回调URL注册到上游提供商,并输入客户端凭据。Portal在可用时发现标准OAuth元数据,当无法发现时,管理员可以提供授权、令牌、撤销和颁发者端点。
每个用户仍然授权访问自己的上游数据源,存储的客户端密钥仅用于获取更新的工具和提示列表。
手动OAuth支持现在有助于覆盖OAuth实现的多种变体。一些提供商需要自定义标头、个人访问令牌或显式客户端允许列表,这些是单独的兼容性问题。我们将在未来几个月继续扩展MCP Portal的OAuth支持。
## 将私有MCP服务器纳入同一Portal
公共SaaS工具只是企业MCP目录的一部分。企业依赖的大多数安全信息无法从公共互联网获得;它们存在于公共或私有云基础设施中,或托管在本地,并且只能通过连接到私有网络来访问。
目前,MCP Portal必须能够通过公共互联网解析并到达上游服务器。这意味着仅可在私有网络上使用的服务器——通过[私有DNS](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/private-net/cloudflared/private-dns/)或位于私有IP空间内——无法被Portal访问。我们正在努力让MCP Portal通过
[Cloudflare Gateway路由和已经用于其他私有应用程序的同一Cloudflare One网络连接到私有服务器。](https://developers.cloudflare.com/workers-vpc/)
私有服务器保留其私有主机名;Portal通过Cloudflare的私有路由到达它,并将其工具与公共上游服务器一起呈现;Access策略、Portal日志记录和工具控制继续在同一前门应用。
通过Gateway路由Portal流量还会为其标记`mcp_portal`
流量来源,因此Gateway策略可以区分Portal请求和直接员工连接。MCP服务器的私有连接正在积极开发中;请关注[Changelog](https://developers.cloudflare.com/changelog/)以获取更多信息。
## Agents SDK支持新的无状态模型
几周前,MCP项目发布了`2026-07-28`
规范,这是一次重大修订,用无状态的、每请求模型取代了连接范围的初始化。我们在[下一代MCP](https://blog.cloudflare.com/mcp-v2)中介绍了协议变更和迁移路径。
[Cloudflare Agents SDK](https://developers.cloudflare.com/agents/model-context-protocol/) v0.20.0支持MCP
`2026-07-28`
作为客户端和服务器。对于每个连接,客户端首先使用`server/discover`探测新的无状态协议;如果服务器不支持,客户端继续在同一连接上使用传统的`initialize`握手。现有的`addMcpServer`调用不需要单独协议设置或单独客户端。在服务器端,`createMcpHandler`可以从[Worker](https://developers.cloudflare.com/workers/)提供无状态工具、提示、资源和引导,而无需创建传输会话或
[:](https://developers.cloudflare.com/durable-objects/)
__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 Portals 后面。
然后,强制执行您可以控制的边界。编写 Gateway 策略,使用 MCP 检测条件以及流量来源和目标条件,阻止来自受管设备和站点的直接 MCP 连接,并尽可能将自托管上游服务器限制为仅限 Portal 流量。
我们很快将添加更细粒度的功能,用于 MCP 流量的可见性和控制,包括对特定工具使用的控制,以及针对您环境中所有 MCP 服务器(无论您的安全组织是否已知)的工具使用情况的新报告。
我们的 MCP 流量检测教程 涵盖了当前 Gateway 日志可用的主机名、路径和 JSON-RPC 启发式方法。当新信号正式可用时,我们将更新文档,添加协议选择器详细信息。
