Model Context Protocol 自发布以来最大的一次修订:协议层彻底无状态化、UI 与长时任务成为官方扩展、授权对齐 OAuth/OIDC、首个正式弃用政策。本文讲清:改了什么、为什么这么改、你的 Agent 工程要怎么跟。
先说人话版:MCP(Model Context Protocol)是让 AI 应用(如 Claude、各类 Agent)以统一方式连接外部工具和数据的开放协议——你可以把它理解为「AI 世界的 USB 接口标准」。它由 Anthropic 于 2024 年底发起,现已成为 Agent 生态的事实标准之一。
2026 年 5 月 21 日,官方锁定了新版规范 2026-07-28 的候选版(RC),最终版将于 2026 年 7 月 28 日发布——也就是三周后。注意:MCP 的版本号是「最后一次不兼容变更的日期」,不是发布日;当前正式生效的版本仍是 2025-11-25。
要理解这次修订,得先看 MCP 这两年的处境变化。它最初是为「本地工具接入」设计的:你的电脑上跑一个 MCP 服务器,Claude 桌面版连上它,一对一、长连接、有来有回,状态放在连接里天经地义。
但 2025 年之后,MCP 大量跑进了生产环境的远程部署:一个公司把 MCP 服务器部署成云服务,成千上万的客户端同时连。这时旧设计的三个痛点全暴露了(官方 2026 路线图将「传输层演进与可扩展性」列为四大优先级之首):
Mcp-Session-Id,之后所有请求必须回到发出这个 ID 的那台服务器实例——负载均衡器被迫做「粘性路由」,水平扩容非常别扭。官方在 2025 年 12 月的《传输层的未来》一文中就预告了这个方向,本次 RC 由六个 SEP(Specification Enhancement Proposal,规范增强提案——MCP 社区的正式提案机制,类似 Python 的 PEP)协同完成了这个计划。
两条最大的变化(也是最主要的破坏性变更):
是什么删除 initialize 握手(SEP-2575):旧版客户端连上服务器要先发 initialize、收到响应后再发 notifications/initialized,交换协议版本和能力。新版彻底删除这个流程——这些信息改为随每个请求放在 _meta 字段里携带(如 io.modelcontextprotocol/clientInfo);同时新增 server/discover 方法(服务器必须实现),客户端想提前了解服务器能力时随时可查。
为什么握手的本质是「建立连接前的一次性状态交换」——只要有它,协议就天然是有状态的。把这些信息摊到每个请求里,任何一台服务器实例才能独立处理任何一个请求。
是什么删除协议级会话(SEP-2567):Mcp-Session-Id 请求头及其背后的会话机制整体移除。tools/list 等列表接口不再「因连接而异」。
为什么会话 ID 是粘性路由的罪魁祸首。删掉它,请求落到哪台实例都行,负载均衡器用最普通的轮询就够了,共享会话存储也不需要了。
看一眼前后对比(代码来自官方 RC 公告):
# 旧版(2025-11-25):先握手拿会话 ID,之后每个请求都要带
POST /mcp
{"jsonrpc":"2.0","id":1,"method":"initialize", ...}
→ 服务器返回 Mcp-Session-Id: 1868a90c-...
POST /mcp
Mcp-Session-Id: 1868a90c-3a3f-4f5b ← 被钉死在一台实例上
{"jsonrpc":"2.0","id":2,"method":"tools/call", ...}
# 新版(2026-07-28):单个自包含请求,任何实例都能处理
POST /mcp
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: search
{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"search","arguments":{"q":"otters"},
"_meta":{"io.modelcontextprotocol/clientInfo":{...}}}}
看到这里你可能会问:那需要跨调用记住状态的服务器怎么办?(比如购物车、浏览器自动化)官方答案是回归 HTTP API 的老智慧——显式句柄(explicit handle)模式:
create_basket,服务器创建购物车并返回一个 basket_id。add_item 时把 basket_id 作为普通参数传回去,任何实例都能凭 ID 找到状态。无状态之后,MCP 流量要在真实世界的负载均衡器、网关、限流器之间穿行。三个配套改动让这件事变得省力:
Streamable HTTP 的 POST 请求现在必须带 Mcp-Method(操作类型,如 tools/call)和 Mcp-Name(如工具名)两个头。网关无需拆开 JSON 请求体就能按操作路由、限流。服务器会拒绝「头和请求体不一致」的请求。据 Stacktree 解读,同一提案还支持通过 x-mcp-header 从工具参数注入自定义头。
tools/list、prompts/list、resources/list、resources/read 等结果现在必须携带两个字段,模型借鉴自 HTTP Cache-Control:
ttlMs:新鲜度提示(毫秒)——客户端在此期间可放心用缓存,不必反复拉取工具目录;cacheScope:"public" 或 "private"——控制共享中间层(如 CDN、网关)能否缓存,即「这份工具列表能不能跨用户共享」。这解决了一个无状态化带来的现实问题:列表接口不再按连接区分后,客户端怎么知道何时该刷新?答案是「按 TTL 缓存 + 原有 listChanged 通知补充」,长连 SSE 流不再是感知变化的唯一手段。
W3C Trace Context(traceparent / tracestate / baggage)在 _meta 里的键名被正式固定。一次工具调用从宿主应用 → 客户端 SDK → MCP 服务器 → 下游服务,能在 OpenTelemetry 兼容后端里串成一棵完整的 span 树。做生产级 Agent 可观测性的人应该会很高兴。
还有一个棘手问题:无状态协议下,服务器执行到一半需要问用户怎么办?(比如「确认删除 3 个文件吗?」这类 elicitation——服务器向用户征求结构化输入的机制)
旧版做法是服务器通过保持打开的 SSE 连接「反向」发请求——这又依赖长连接了。新版 SEP-2322 引入 MRTR(Multi Round-Trip Requests,多轮往返请求)模式,把「服务器提问」改造成「返回一种特殊结果」:
inputRequests(要问的问题,可以是 elicitation 或 sampling 请求)和一段不透明的 requestState(把执行现场打包编码)。inputResponses 和原样回传的 requestState。因为「现场」全在负载里,任何一台实例都能接着办。// 服务器中途要确认时返回(示例来自官方 RC 公告)
{
"resultType": "inputRequired",
"inputRequests": {
"confirm": { "type": "elicitation",
"message": "Delete 3 files?",
"schema": { "type": "boolean" } } },
"requestState": "eyJzdGVwIjoxLCJmaWxlcyI6WyJhIiwiYiIsImMiXX0="
}
扩展机制在旧版就存在,但没有正式流程。SEP-2133 补上了:扩展用反向域名 ID 标识(如 io.modelcontextprotocol/tasks),通过客户端/服务器能力声明中的 extensions 映射协商启用,有独立仓库、独立维护者、独立于规范的版本节奏,并有从实验到官方的晋升路径。首批两个官方扩展:
是什么MCP 服务器可以携带交互式 HTML 界面,宿主(如 Claude 客户端)在沙箱化 iframe 中渲染。工具需提前声明 UI 模板,宿主可以预取、缓存、做安全审查。
为什么纯文本交互撑不起很多真实场景(选座、画布、表格编辑)。关键设计在安全:UI 发起的每个动作都走与直接工具调用同一条 JSON-RPC 审计与确认链路,UI 不是绕过权限的后门。
例子一个订票 MCP 服务器可以下发座位图界面,用户点选座位后,「选座」这个动作和模型直接调用 select_seat 工具走完全一样的确认流程。
Tasks 在 2025-11-25 里是实验性核心特性,生产使用暴露出不少设计问题,这次移出核心、重设计为扩展。新生命周期:
tools/call 直接返回一个任务句柄(且可以「主动」决定某个调用应作为任务运行,无需客户端逐请求申请);tasks/get 轮询进度(替代旧的阻塞式 tasks/result)、用 tasks/update 传入新输入、用 tasks/cancel 取消;tasks/list 被移除——没有会话就无法安全地界定「谁能列出哪些任务」。tasks/result → 轮询 tasks/get,并处理 tasks/list 移除后的任务索引问题(自己在应用层记录句柄)。六个 SEP 把授权规范与 OAuth 2.0 / OpenID Connect 的实际部署方式对齐。背景是 MCP 独特的部署形态——一个客户端连很多服务器——放大了一类「混淆攻击」的风险。要点(均出自官方 RC 公告):
iss(SEP-2468,按 RFC 9207):客户端要验证授权响应里的签发者参数,防「张冠李戴」的 mix-up 攻击;未来版本将要求直接拒绝缺失 iss 的响应——授权服务器现在就该补上。application_type(SEP-837):动态客户端注册时声明自己是桌面/CLI 还是 Web 应用,避免授权服务器默认按 Web 处理而拒绝 localhost 回调地址——桌面 MCP 客户端的经典痛点。issuer 绑定,资源迁移到别的授权服务器时重新注册。.well-known 发现后缀澄清(SEP-2351)。注:Stacktree 提醒,授权相关 SEP 的确切集合在 RC 阶段仍可能微调,以 7 月 28 日最终版为准。
本次有三个核心特性被标记弃用(SEP-2577),各有官方指定的替代路径:
| 被弃用特性 | 它原本做什么 | 官方替代方案 |
|---|---|---|
| Roots | 客户端向服务器声明可操作的文件根目录 | 工具参数、资源 URI 或服务器配置 |
| Sampling | 服务器「借」客户端的 LLM 做推理(人在回路) | 直接集成 LLM 提供商 API |
| Logging | 协议内置的日志通道 | stdio 用 stderr;结构化可观测用 OpenTelemetry |
此外,据 Stacktree 解读,更老的 HTTP+SSE 传输也被归类为弃用。
但「弃用」不等于「消失」——这正是同时落地的特性生命周期政策(SEP-2596)的意义:
工具的 inputSchema/outputSchema 不再是受限子集:输入支持组合(oneOf/anyOf/allOf)、条件、引用($ref/$defs),根部仍须是 object;输出完全不限,structuredContent 可以是任何 JSON 值。安全要求:不得自动解引用外部 $ref URI,应限制 schema 深度和校验耗时。对做复杂工具接口的人是实打实的表达力提升。
「资源不存在」的错误码从 MCP 自定义的 -32002 改为 JSON-RPC 标准的 -32602(Invalid Params)。如果你的客户端代码硬编码匹配 -32002,记得改。
综合官方公告与 Stacktree 的建议,按角色整理:
_meta 读协议版本与客户端能力,不再依赖握手和 Mcp-Session-Id;跨调用状态改用显式句柄。server/discover:这是新版的硬性要求(MUST)。ttlMs 和 cacheScope。Mcp-Method / Mcp-Name 头,网关改为按这两个头路由,撤掉会话亲和配置。InputRequiredResult 并带 requestState 重发。iss、声明 application_type,检查硬编码的 -32002。inputRequests 里仍可携带 sampling 型请求完成同类交互;弃用的是旧的独立 Sampling 特性,官方推荐的长期方向是直接集成 LLM API。覆盖度自评:「是什么/为什么/怎么变/怎么迁移」四个维度有官方一手来源+第三方交叉验证,较扎实;「生产实战案例」维度较薄——RC 尚未定稿,公开的真实迁移案例还少,建议 8 月后关注各 SDK 的迁移笔记。
① MCP 正在从「实验室协议」变成「基建级协议」——无状态化是它为水平扩容、网关友好、可观测性付出的一次性阵痛。
② 状态没有消失,而是从传输层「暗处」搬到了模型可见的「明处」(句柄、requestState、任务句柄)——这与 context engineering 的大方向完全一致。
③ 7 月 28 日定稿,12 个月弃用缓冲——现在了解、按需规划迁移,不必抢跑,但新项目别再压注被弃用的特性。