🔌 MCP 2026-07-28 规范深度解读
无状态核心、MCP Apps 与 Tasks 扩展

Model Context Protocol 自发布以来最大的一次修订:协议层彻底无状态化、UI 与长时任务成为官方扩展、授权对齐 OAuth/OIDC、首个正式弃用政策。本文讲清:改了什么、为什么这么改、你的 Agent 工程要怎么跟。

调研时间:2026-07-05 · 基于官方 Release Candidate 公告及第三方解读交叉核对 · 最终版规范 7 月 28 日定稿,细节以官方为准

⚡ ① 30 秒速览:这次更新到底是什么

先说人话版: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 从「需要会话、需要握手的有状态协议」改造成「每个请求自带全部信息的无状态协议」,从而能像普通 Web 服务一样水平扩容;同时把「服务器带 UI」(MCP Apps)和「长时任务」(Tasks)变成官方扩展。它包含破坏性变更,做 Agent 工程的人需要了解迁移路径。

无状态核心删握手/删会话 扩展框架Apps + Tasks 授权加固对齐 OAuth/OIDC 弃用政策12 个月窗口 基建友好路由/缓存/追踪 MCP 2026-07-28 的五大变化
本次修订的五大块。前两块(无状态核心、扩展框架)是重头戏,后面章节逐个拆开讲。

🕰 ② 背景与动机:为什么非要「无状态」不可

要理解这次修订,得先看 MCP 这两年的处境变化。它最初是为「本地工具接入」设计的:你的电脑上跑一个 MCP 服务器,Claude 桌面版连上它,一对一、长连接、有来有回,状态放在连接里天经地义。

但 2025 年之后,MCP 大量跑进了生产环境的远程部署:一个公司把 MCP 服务器部署成云服务,成千上万的客户端同时连。这时旧设计的三个痛点全暴露了(官方 2026 路线图将「传输层演进与可扩展性」列为四大优先级之首):

🔗 类比
旧版 MCP 像一家「必须认脸」的餐厅:你第一次进门要登记(握手),之后每次都必须找同一个服务员(粘性会话),他不在你就没法点菜。新版改成了「凭小票服务」:你每次点单都出示完整小票(请求自带全部上下文),任何一个服务员都能接待你——餐厅想加多少服务员就加多少。
2024-11MCP 发布 2025-11-25当前正式版Tasks 实验性上线 2026-032026 路线图无状态列为头号优先 2026-05-21RC 锁定十周验证窗口 2026-07-28最终版发布
MCP 版本演进时间线。RC 到定稿之间的十周是给 SDK 维护者与客户端实现方做真实负载验证的窗口。

官方在 2025 年 12 月的《传输层的未来》一文中就预告了这个方向,本次 RC 由六个 SEP(Specification Enhancement Proposal,规范增强提案——MCP 社区的正式提案机制,类似 Python 的 PEP)协同完成了这个计划。

🧱 ③ 核心变化一:无状态协议核心

3.1 握手没了,会话也没了

两条最大的变化(也是最主要的破坏性变更):

是什么删除 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":{...}}}}
拓扑对比图:旧版客户端经负载均衡器粘性路由到某一台 MCP 服务器实例且各实例共享会话存储;新版客户端可被路由到任意实例且不再需要会话存储
🖼️ 原图已失效(来自 MCP 官方博客)。该图展示的是:旧版流量必须粘性路由到固定实例并依赖共享会话存储;新版任意请求可落到任意实例,会话存储整体消失。
官方对比图:无状态化前后的部署拓扑。图源:MCP 官方博客(RC 公告)。

3.2 协议无状态 ≠ 应用无状态:显式句柄模式

看到这里你可能会问:那需要跨调用记住状态的服务器怎么办?(比如购物车、浏览器自动化)官方答案是回归 HTTP API 的老智慧——显式句柄(explicit handle)模式:

  1. 工具铸造句柄:模型调用 create_basket,服务器创建购物车并返回一个 basket_id
  2. 模型持有句柄:这个 ID 出现在模型的上下文里,对模型是「可见的状态」。
  3. 后续调用回传:模型调用 add_item 时把 basket_id 作为普通参数传回去,任何实例都能凭 ID 找到状态。
时序图:模型调用 create_basket,MCP 服务器返回 basket_id,模型将同一 basket_id 作为参数传入 add_item
🖼️ 原图已失效(来自 MCP 官方博客)。该图展示的是句柄模式时序:create_basket 返回 basket_id → 模型在 add_item 中回传同一 basket_id。
官方时序图:显式句柄模式。图源:MCP 官方博客(RC 公告)。
💡 官方的观察很有意思:这不只是权宜替代,反而更强大——状态从「藏在传输层元数据里」变成「模型看得见、能推理、能在多个工具间组合传递」的一等公民。这与 Agent 工程里「让上下文对模型可见」的大原则一脉相承。
💬 没看懂?换个说法讲一遍
以前协议帮你偷偷记住「这是哪个用户的会话」,像商场寄存柜台帮你记住你是谁;现在改成「凭寄存牌取件」——牌子(handle)交到模型手里,模型自己保管、自己出示,哪怕换了个柜员(服务器实例)也照样取件。代价是模型要多传一个参数,好处是整个系统再没有「只有某台机器知道」的隐藏状态。

🛣 ④ 核心变化二:让基础设施「看得懂」MCP 流量

无状态之后,MCP 流量要在真实世界的负载均衡器、网关、限流器之间穿行。三个配套改动让这件事变得省力:

4.1 必带路由头:Mcp-Method 与 Mcp-Name(SEP-2243)

Streamable HTTP 的 POST 请求现在必须Mcp-Method(操作类型,如 tools/call)和 Mcp-Name(如工具名)两个头。网关无需拆开 JSON 请求体就能按操作路由、限流。服务器会拒绝「头和请求体不一致」的请求。据 Stacktree 解读,同一提案还支持通过 x-mcp-header 从工具参数注入自定义头。

4.2 响应缓存:ttlMs 与 cacheScope(SEP-2549)

tools/listprompts/listresources/listresources/read 等结果现在必须携带两个字段,模型借鉴自 HTTP Cache-Control:

这解决了一个无状态化带来的现实问题:列表接口不再按连接区分后,客户端怎么知道何时该刷新?答案是「按 TTL 缓存 + 原有 listChanged 通知补充」,长连 SSE 流不再是感知变化的唯一手段。

4.3 分布式追踪落进规范(SEP-414)

W3C Trace Context(traceparent / tracestate / baggage)在 _meta 里的键名被正式固定。一次工具调用从宿主应用 → 客户端 SDK → MCP 服务器 → 下游服务,能在 OpenTelemetry 兼容后端里串成一棵完整的 span 树。做生产级 Agent 可观测性的人应该会很高兴。

🔁 ⑤ 核心变化三:多轮往返请求(MRTR)

还有一个棘手问题:无状态协议下,服务器执行到一半需要问用户怎么办?(比如「确认删除 3 个文件吗?」这类 elicitation——服务器向用户征求结构化输入的机制)

旧版做法是服务器通过保持打开的 SSE 连接「反向」发请求——这又依赖长连接了。新版 SEP-2322 引入 MRTR(Multi Round-Trip Requests,多轮往返请求)模式,把「服务器提问」改造成「返回一种特殊结果」:

  1. 服务器返回 InputRequiredResult:工具调用不直接完成,而是返回一个「需要输入」的结果,里面装着 inputRequests(要问的问题,可以是 elicitation 或 sampling 请求)和一段不透明的 requestState(把执行现场打包编码)。
  2. 客户端收集答案:向用户弹窗、或按 sampling 流程调用 LLM,拿到回答。
  3. 客户端重发原调用:带上 inputResponses 和原样回传的 requestState。因为「现场」全在负载里,任何一台实例都能接着办
// 服务器中途要确认时返回(示例来自官方 RC 公告)
{
  "resultType": "inputRequired",
  "inputRequests": {
    "confirm": { "type": "elicitation",
                 "message": "Delete 3 files?",
                 "schema": { "type": "boolean" } } },
  "requestState": "eyJzdGVwIjoxLCJmaWxlcyI6WyJhIiwiYiIsImMiXX0="
}
客户端调用tools/call InputRequiredResultinputRequests + requestState 客户端收集输入问用户 / 调 LLM 重发原调用 → 完成inputResponses + requestState MRTR:状态随负载走,任何实例都能续办
MRTR 四步流程。一个 InputRequiredResult 可同时打包 elicitation 和 sampling 请求,一次往返搞定。
🔒 配套安全规则(SEP-2260):服务器发起的请求(如向用户提问)现在只允许发生在「正在处理客户端请求」期间——旧版只是建议,新版是硬性要求。用户永远不会被凭空弹窗,每次提问都能追溯到自己(或自己的 Agent)发起的某个操作。

🧩 ⑥ 扩展框架转正:MCP Apps 与 Tasks

扩展机制在旧版就存在,但没有正式流程。SEP-2133 补上了:扩展用反向域名 ID 标识(如 io.modelcontextprotocol/tasks),通过客户端/服务器能力声明中的 extensions 映射协商启用,有独立仓库、独立维护者、独立于规范的版本节奏,并有从实验到官方的晋升路径。首批两个官方扩展:

6.1 MCP Apps:服务器可以下发交互界面(SEP-1865)

是什么MCP 服务器可以携带交互式 HTML 界面,宿主(如 Claude 客户端)在沙箱化 iframe 中渲染。工具需提前声明 UI 模板,宿主可以预取、缓存、做安全审查。

为什么纯文本交互撑不起很多真实场景(选座、画布、表格编辑)。关键设计在安全:UI 发起的每个动作都走与直接工具调用同一条 JSON-RPC 审计与确认链路,UI 不是绕过权限的后门。

例子一个订票 MCP 服务器可以下发座位图界面,用户点选座位后,「选座」这个动作和模型直接调用 select_seat 工具走完全一样的确认流程。

6.2 Tasks:长时任务的新生命周期(SEP-2663)

Tasks 在 2025-11-25 里是实验性核心特性,生产使用暴露出不少设计问题,这次移出核心、重设计为扩展。新生命周期:

tools/call发起调用 返回任务句柄服务器决定异步化 tasks/get 轮询tasks/update 补充输入 ✅ 完成取结果 ✖ tasks/cancel Tasks 扩展:从阻塞等待改为轮询驱动
Tasks 新生命周期:与无状态模型对齐,轮询取代阻塞,句柄取代隐式会话。
⚠️ 如果你基于 2025-11-25 的实验性 Tasks API 上过生产,需要迁移:阻塞式 tasks/result → 轮询 tasks/get,并处理 tasks/list 移除后的任务索引问题(自己在应用层记录句柄)。

🔐 ⑦ 授权加固:向真实世界的 OAuth/OIDC 靠拢

六个 SEP 把授权规范与 OAuth 2.0 / OpenID Connect 的实际部署方式对齐。背景是 MCP 独特的部署形态——一个客户端连很多服务器——放大了一类「混淆攻击」的风险。要点(均出自官方 RC 公告):

注:Stacktree 提醒,授权相关 SEP 的确切集合在 RC 阶段仍可能微调,以 7 月 28 日最终版为准。

🍂 ⑧ 弃用三兄弟与首个生命周期政策

本次有三个核心特性被标记弃用(SEP-2577),各有官方指定的替代路径:

被弃用特性它原本做什么官方替代方案
Roots客户端向服务器声明可操作的文件根目录工具参数、资源 URI 或服务器配置
Sampling服务器「借」客户端的 LLM 做推理(人在回路)直接集成 LLM 提供商 API
Logging协议内置的日志通道stdio 用 stderr;结构化可观测用 OpenTelemetry

此外,据 Stacktree 解读,更老的 HTTP+SSE 传输也被归类为弃用。

但「弃用」不等于「消失」——这正是同时落地的特性生命周期政策(SEP-2596)的意义:

🧭 治理层的深意:配合「扩展框架」(新能力先做扩展孵化)和「一致性套件门槛」(SEP-2484:提案没有配套一致性测试场景就不能定稿),官方的意图是——这次破坏性大改是为了以后不再破坏性大改。实现 2026-07-28 的人应该能平滑升级未来版本,不用重写传输层。

🔧 ⑨ 其他值得知道的变化

工具 Schema 升级为完整 JSON Schema 2020-12(SEP-2106)

工具的 inputSchema/outputSchema 不再是受限子集:输入支持组合(oneOf/anyOf/allOf)、条件、引用($ref/$defs),根部仍须是 object;输出完全不限,structuredContent 可以是任何 JSON 值。安全要求:不得自动解引用外部 $ref URI,应限制 schema 深度和校验耗时。对做复杂工具接口的人是实打实的表达力提升。

错误码标准化(SEP-2164)

「资源不存在」的错误码从 MCP 自定义的 -32002 改为 JSON-RPC 标准的 -32602(Invalid Params)。如果你的客户端代码硬编码匹配 -32002,记得改。

🧳 ⑩ 迁移指南:你现在该做什么

综合官方公告与 Stacktree 的建议,按角色整理:

如果你维护 MCP 服务器

  1. 放弃会话依赖:从 _meta 读协议版本与客户端能力,不再依赖握手和 Mcp-Session-Id;跨调用状态改用显式句柄。
  2. 实现 server/discover:这是新版的硬性要求(MUST)。
  3. 给列表/读取结果附上 ttlMscacheScope
  4. 用了实验性 Tasks 的,迁到扩展新生命周期(轮询式)。

如果你维护 MCP 客户端 / 网关

  1. 发送 Mcp-Method / Mcp-Name,网关改为按这两个头路由,撤掉会话亲和配置。
  2. 实现 MRTR:能处理 InputRequiredResult 并带 requestState 重发。
  3. 校验 iss、声明 application_type,检查硬编码的 -32002
但不必恐慌:当前正式版仍是 2025-11-25;弃用政策保证至少 12 个月过渡;Tier 1 SDK 会在十周验证窗口内跟进支持。Stacktree 的建议很中肯——现在该做的是读官方 changelog、跟踪 SDK 进展、避免在新项目里对被弃用特性(Roots/Sampling/Logging/HTTP+SSE)建立强依赖

⚠️ ⑪ 常见坑与容易误解的地方

📚 ⑫ 学习资源清单

覆盖度自评:「是什么/为什么/怎么变/怎么迁移」四个维度有官方一手来源+第三方交叉验证,较扎实;「生产实战案例」维度较薄——RC 尚未定稿,公开的真实迁移案例还少,建议 8 月后关注各 SDK 的迁移笔记。

🎓 带走三句话

① MCP 正在从「实验室协议」变成「基建级协议」——无状态化是它为水平扩容、网关友好、可观测性付出的一次性阵痛。

② 状态没有消失,而是从传输层「暗处」搬到了模型可见的「明处」(句柄、requestState、任务句柄)——这与 context engineering 的大方向完全一致。

③ 7 月 28 日定稿,12 个月弃用缓冲——现在了解、按需规划迁移,不必抢跑,但新项目别再压注被弃用的特性。