Skip to content

MCP(Model Context Protocol)协议机制与安全边界 ​

摘要 ​

MCP 将模型应用与 Tool、Resource 和 Prompt 提供方连接起来,核心安全问题集中在 Server 身份、能力发现、Schema 变化、OAuth 资源绑定和不可信返回值。协议兼容不等于授权正确;Host 仍需对工具权限、用户同意和内容到指令边界承担控制责任。

调研/复核日期:2026-07-29 证据来源:以 MCP 官方 specification、正式 tag 和 changelog 为主;二手材料单独标注。

当前稳定 spec 版本:2026-07-28(正式 tag 2026-07-28 已发布)。它相对 2025-11-25 有破坏性变化:协议核心改为无状态,移除初始化握手、HTTP 会话和 GET 事件流,并引入 MRTR、server/discover、标准请求头、缓存语义与正式扩展机制。旧实现不能只改版本号,必须按迁移规则兼容。

协议定位与核心差异 ​

MCP 主要规范模型应用如何发现并调用 Tool、Resource 和 Prompt,不负责独立 Agent 之间的任务委派。与 2025 版相比,2026-07-28 版的核心差异是无状态请求、服务发现、Multi Round-Trip Requests(MRTR)、标准请求头和独立扩展协商;它不是在旧会话协议上简单增加字段。

架构和消息流程 ​

传输层 ​

两种标准传输都承载 UTF-8 JSON-RPC 2.0:

stdio:client 启动 server 子进程;每行一条消息,消息内不得包含换行。server 只能向 stdout 写 MCP 消息,日志写 stderr。2026 版仍使用同一条双向字节流,但连接/进程不代表会话,server 不得从此前请求推断上下文。

Streamable HTTP:单一 MCP endpoint(如 /mcp)只要求支持 POST。每个 request/notification 都用新的 POST;request 的响应可以是单个 application/json 对象,或与该请求绑定的 text/event-stream。长期通知通过 POST subscriptions/listen 建立 SSE 响应流,不再使用独立 GET 流。

2026 版的关键约束:

  • 删除 Mcp-Session-Id、HTTP GET/DELETE 会话操作、SSE event ID 和 Last-Event-ID 续传;断流后必须用新 JSON-RPC ID 重发。
  • 每个 POST 必须带 MCP-Protocol-Version;每个 JSON-RPC request 还必须带 Mcp-Method,tools/call、resources/read、prompts/get request 另带 Mcp-Name。本版 core 不定义经 HTTP 发出的 client notification,因此也未定义其 method header 要求。body 是事实源,header 缺失、格式错误或与 body 不一致时返回 HeaderMismatch(-32020)。
  • server 必须验证出现的 Origin;非法值返回 HTTP 403。公开部署还必须做鉴权,本地部署应只绑定 loopback。
  • SSE 可发送 comment 作为 keep-alive;关闭某个 request 的 SSE 响应流即取消该请求。

向后兼容分两个“时代”:2025-11-25 等版本仍使用 initialize/session/GET SSE;2024-11-05 使用已弃用的双端点 HTTP+SSE。client 应按官方 versioning/transport fallback 流程探测,不能把任意 4xx 都当成同一种旧协议。

消息层与无状态生命周期 ​

消息仍分 request(有 id)、response(result 或 error)与 notification(无 id)。2026 版移除了 initialize、notifications/initialized 和连接级 capability 协商;每个 request 都在 _meta 中携带协议版本和 client capability:

json
{"jsonrpc":"2.0","id":"discover-1","method":"server/discover","params":{"_meta":{
  "io.modelcontextprotocol/protocolVersion":"2026-07-28",
  "io.modelcontextprotocol/clientInfo":{"name":"ExampleClient","version":"1.0.0"},
  "io.modelcontextprotocol/clientCapabilities":{}}}}

server 必须实现 server/discover,返回支持版本、capabilities、身份信息以及缓存字段;client 可选择调用,也可直接发业务 RPC 并处理 UnsupportedProtocolVersionError(-32022)。所有成功 result 新增必需的 resultType:通常为 "complete",需要补充输入时为 "input_required";为兼容旧 server,缺失时按 "complete" 处理。

2026 版不再允许 server 主动发 JSON-RPC request。需要 sampling、elicitation 或 roots 输入时,server 返回 InputRequiredResult;client 收集输入后,用新 request ID、原参数、inputResponses 和原样回传的 requestState 重试。这就是 Multi Round-Trip Requests(MRTR)。

核心原语 ​

  • Tools:tools/list 发现、tools/call 调用。inputSchema/outputSchema 采用完整 JSON Schema 2020-12;structuredContent 可为任意 JSON 值。描述、annotations 和结果都应视为不可信输入。
  • Resources:URI 寻址的数据与上下文,由宿主应用驱动读取;resources/read 可返回文本或二进制内容。
  • Prompts:server 提供、由用户/宿主选择的模板化消息;通过 prompts/list、prompts/get 使用。
  • Elicitation:server 请求用户或外部流程补充信息;2026 版通过 MRTR 承载,不再是 server 主动 RPC。
  • Subscriptions:subscriptions/listen 订阅 tools/prompts/resources 的变化通知;它是长生命周期 request,不是会话。
  • Caching:tools/list、prompts/list、resources/list/read 等返回 ttlMs 与 cacheScope(public/private),与 listChanged 通知互补。
  • Extensions:以 reverse-DNS ID 独立协商和版本化。官方扩展包括 MCP Apps(sandboxed iframe UI)和重新设计的 Tasks;Tasks 已从实验性 core 移出,使用 tasks/get、tasks/update、tasks/cancel,没有 tasks/list。

Roots、Sampling、Logging 与 OAuth Dynamic Client Registration 在 2026-07-28 标记为 Deprecated,仍可用但新实现不应采用;最早移除时间为 2027-07-28 及之后的正式版本。Sampling 的推荐替代是 server 直接集成模型 API。

远程 HTTP 身份认证与授权 ​

MCP server 是 OAuth 2.1 protected resource,授权服务器(AS)独立发现。关键要求:

  • 用 RFC 9728 Protected Resource Metadata 发现 AS;AS metadata 可来自 RFC 8414 或 OpenID Connect Discovery。
  • authorization 与 token request 都必须带 RFC 8707 resource,token 必须绑定目标 MCP server;禁止 token passthrough。
  • Client ID Metadata Documents(CIMD)是无预注册关系时的优先注册方式;RFC 7591 DCR 仅作为兼容 fallback,2026 版已弃用。
  • AS 应按 RFC 9207 返回 iss;client 必须校验出现的 iss 与已记录 issuer 完全匹配。PKCE、精确 redirect URI、scope 最小化仍是基础要求。
  • 无效/过期 token 返回 401;scope 不足返回 403,并可用 WWW-Authenticate 触发 step-up authorization。

stdio 不应使用这套 HTTP OAuth 流程,凭证应通过环境或本地安全机制取得。

公网 HTTP 部署的动态测量 ​

"设计暴露"(Exposed by Design)研究使用 11 个被动来源发现公网 MCP Endpoint,再用 34 个动态模块测试 10 类风险中的 9 类。2026 年 7 月四轮测量确认约 640 个唯一 Server,其中 414 个完成动态审计;作者人工确认并协调披露 68 个安全漏洞,包含 SQL 注入、云元数据 SSRF、Prompt Template 注入和游标路径遍历。受审计 Server 中 91.8% 没有 OAuth;更大确认集合中记录到 687 个无需认证即可调用 Shell 的 Tool 实例。

该研究只覆盖公网 HTTP/SSE,不代表本地 stdio 或全部 MCP 部署;414 个受审计样本存在可达性选择偏差,三天内 Endpoint 流失率为 41.6%,模块精确率与召回率也尚未在标注语料上校准。68 个结果经过单名研究者人工确认,19 个已公开、49 个仍在披露期,尚无独立复现。因此这些数字是 2026 年 7 月样本的下界与作者实测,不是整个 MCP 生态的发生率。

会话中工具面变化:WebMCP 工具面投毒(WebMCP Tool Surface Poisoning) ​

WebMCP 研究把工具攻击分成两类:Tool Hijacking 通过抢注、注销和重注册改变 Agent 实际可见的工具;Tool Framing 保留工具表面功能,但用名称、description、inputSchema 和 readOnlyHint 影响模型选择及参数传递。作者使用 JavaScript Polyfill、Node ProxyClient、三个模型和四类任务,报告注册竞争的平均攻击成功率为 100%、任务完成率为 17%;描述注入的平均攻击成功率为 59%、任务完成率为 81%。前者更容易破坏任务,后者更隐蔽。

字段消融说明 metadata 不是中性文档:仅 description 的平均攻击成功率为 93%,仅 readOnlyHint 为 87%,两者组合在三个模型上均为 100%。作者在 ProxyClient 中模拟 Origin 绑定,并限制第三方工具可接收的参数后,把五个已测条件的攻击成功率从 36% 至 100% 降为 0%。这里的 0 只表示已测四个场景中没有数据到达 Sink,不是浏览器实现的形式化保证。实验没有使用 Chrome 原生 WebMCP,防护也不在浏览器层实现,尚未进行用户研究或跨更多 Agent 架构复验。

本地控制面组合漏洞:AutoJack ​

Microsoft 在 AutoGen Studio 开发分支中验证了一条由网页到宿主进程的组合攻击链:浏览 Agent 渲染攻击者页面后,以本机进程身份连接 loopback MCP WebSocket;该路由被认证中间件排除且 Handler 未补做认证;URL 中的 Base64 server_params 又被直接解析为 StdioServerParams.command 和参数,最终可启动任意进程。该链说明 Origin: localhost 只能描述连接来源,不能证明调用者获得了控制面授权。

维护者在上游提交 b047730 中加固了实现。受影响 MCP WebSocket 从未进入 PyPI 版本,因此不能表述为所有 AutoGen Studio 用户都暴露于该具体攻击。可迁移的结论是:本地 Agent 能浏览不可信网页时,loopback 服务必须实施独立身份认证、逐操作授权和命令 allowlist,浏览 Worker 与高权限 MCP 控制面也不能共享同一信任域。

延迟工具变更与认证控制流失效 ​

Pillar Security 披露的 Deadbugz 活动说明,MCP Server 的初始良性表现不能替代持续完整性校验:攻击者在短时间内向多个开源仓库提交接入远程 MCP Server 的 Pull Request,Server 先正常响应,在约三次工具调用后改变 tools/list 与 Prompt 元数据,转而诱导用户提交凭据并隐藏真实意图。披露统计为 74 分钟内 23 个 PR,其中 19 个关闭、4 个当时仍开放,未见 PR 合并。这个样本证明的是一条在野尝试和可行的延迟变更链,不是 MCP 生态发生率。

Dolt MCP 的 CVE-2026-73554 则展示了更传统但后果直接的实现缺陷:HTTP/JWT 中间件在无效令牌时写出 401,却因缺少控制流终止而继续执行 MCP 操作。受影响版本为 0.3.1–0.3.6,0.3.7 修复;stdio 不受该具体问题影响。攻击者可在未认证状态下以 Server 的数据库凭据执行 SQL 读写和 Dolt 远程操作,而日志表面只显示认证失败。由此可见,状态码、日志和实际副作用必须在测试中联合断言;“返回 401”本身不能证明请求已被阻断。

Grafana MCP 调用目标伪造与 SSRF ​

Grafana Labs 的 CVE-2026-19516 说明,协议身份认证成功也不能替代 Server 对下游请求目的地的约束。mcp-grafana 允许可调用 grafana_api_request 的主体通过未文档化的 X-Grafana-URL 请求头覆盖 Grafana 基址,同时由工具参数选择 HTTP 方法、路径和正文。1.0.0 及更早版本没有把目的地限制在已配置 Grafana 实例,攻击者因而可让 Server 请求内部、loopback 或 link-local 服务(包括云元数据端点)并读取响应,形成服务器端请求伪造(Server-Side Request Forgery, SSRF)。这是 CVE-2026-15583 修复后的残留问题:0.17.1 已阻止把配置的服务账户令牌发送到非预期目的地,但没有阻止请求本身离开受信目标。v1.1.0 删除 X-Grafana-URL,官方将其列为 CVE-2026-19516 的修复版本;同版还增加了可选的 HTTP 调用方 Bearer Token 认证,但未配置该选项时不能据此假定远程调用已被认证。

这里可被伪造的是 Server 外连请求的目标和内容,不是 MCP 2026-07-28 已删除的 HTTP 会话,也没有公开证据证明攻击者伪造了用户登录会话或身份令牌。安全测试应把“调用方身份”“工具调用权限”和“允许访问的出站目的地”作为三个独立断言。下面是本站依据官方公告重构的去武器化测试夹具;.invalid 目标不解析,示例不包含云元数据地址或真实内网端点:

text
request.headers["X-Grafana-URL"] = "https://internal.invalid"
tools/call {
  name: "grafana_api_request",
  arguments: {method: "GET", path: "/health", body: null}
}
expect: reject before outbound dial
assert: selected_origin == configured_grafana_origin
assert: no_response_body_from_unapproved_origin

该结论由 Grafana 官方公告、CVE 记录和 v1.1.0 发布说明直接支持,CVSS 3.1 为 9.1(Critical,PR:L);公开材料没有提供独立复现、在野利用证据、完整攻击样本或各部署模式的可达性统计。结论只适用于 Grafana mcp-grafana 0.0.0 至 1.0.0 的这条工具与请求头组合,不能外推为 MCP 协议本身或 Grafana 主产品的通用会话漏洞。验证修复时除升级外,还应断言调用方不能覆盖基址、DNS 解析和重定向后仍受目的地 allowlist 约束,并监测请求头出现、配置域名偏离及异常 loopback/link-local 出站尝试。

安全风险 ​

  • 工具描述/schema/返回值中的 prompt injection 与 tool poisoning。
  • server 接入后改变工具定义或行为的 rug pull;缓存使变更检测策略更重要。
  • OAuth confused deputy、issuer mix-up、token passthrough 与 audience 混淆。
  • 多 server 下的工具重名、shadowing 和错误路由。
  • MCP Apps 的 iframe sandbox、消息桥权限与 UI 发起工具调用的同意边界。
  • 显式 state handle 泄露或跨用户复用;cacheScope 错配导致跨租户缓存泄露。
  • 不可信 resources/prompts 与私有数据、外发工具组合形成的“lethal trifecta”。

实现与验证建议 ​

  • 对每个 HTTP 请求校验 MCP-Protocol-Version、Mcp-Method、Mcp-Name 与正文的一致性,并把不一致作为协议错误处理。
  • 工具描述、Schema、Prompt、Resource 和工具返回值都按不可信输入处理;工具权限和用户同意由 Host 独立控制。
  • OAuth token 必须绑定目标资源和 issuer,拒绝 token passthrough,并测试多 Server 下的 audience 与 scope 混淆。
  • 缓存键必须包含用户、租户、Server 和 cacheScope;收到能力变化通知后验证旧缓存不会继续授权调用。
  • 对 Server 能力清单和描述做版本固定或签名/哈希复核;在同一安装会话中持续比较 tools/list,对延迟变化重新触发权限审查,不能只在首次连接时批准。
  • 用带副作用的本地夹具验证认证中间件:无效、过期和 scope 不足令牌不仅要返回 401/403,还必须保证 Handler、数据库和远程操作均未执行。
  • 兼容测试应分别覆盖 2026 无状态流程、2025 会话流程和 2024 双端点流程,不能把任意 4xx 统一解释为版本回退信号。
  • SSE 中断后使用新 JSON-RPC ID 重发,并检查工具调用是否已经产生副作用,避免自动重试导致重复执行。

结论适用范围 ​

本文以 MCP 2026-07-28 正式规范为基线。MCP 已由 Linux Foundation 旗下 Agentic AI Foundation 托管,属于跨厂商协议;生态采用情况可通过官方 Registry 与各厂商实现判断,但没有可复现快照时,不应引用精确 Server 数量。协议满足规范不等于具体 Host、Server 或工具已经正确实现身份认证、授权和内容隔离。

关联研究 ​

  • 与 A2A 的定位区分见 a2a-protocol.md:MCP 主要连接 Agent 与工具或数据,A2A 连接独立 Agent。
  • MCP 的 SSE 只是 Streamable HTTP 的一种响应形式,不应概括为“MCP 基于 SSE”。安全议题应与 agent-security 下的提示词注入和工具滥用研究交叉分析。

参考链接 ​