MCP 新特性详解:从有状态连接走向无状态协议
2026-07-28是截至 2026 年 8 月 MCP 的最新稳定规范。这次更新不是给旧协议添几个字段,而是重新划分了连接、状态和双向交互的边界:MCP 不再依赖连接级 Session 和初始化握手,每个请求都要带齐版本与能力信息。如果你已经读过《MCP 协议简要介绍》,这篇可以当作更新补丁。旧版的 Host、Client、Server 以及 Tools、Resources、Prompts 仍然成立,但生命周期、服务端反向请求和 Streamable HTTP 的工作方式已经变了。
本文脉络:
- 一、先说版本:最新稳定版是 2026-07-28
- 二、这次更新到底改了什么
- 三、变化一:删除连接级 Session,协议转向无状态
- 四、变化二:用 server/discover 取代初始化握手
- 五、变化三:MRTR 取代服务端主动请求
- 六、变化四:统一订阅与通知通道
- 七、变化五:列表与读取结果支持标准缓存语义
- 八、变化六:Tasks 从实验能力变成官方扩展
- 九、哪些功能被弃用了
- 十、安全、Schema 与可观测性变化
- 十一、如何从旧版迁移
- 十二、常见问题
一、先说版本:最新稳定版是 2026-07-28
MCP 的版本号采用日期,而不是 1.0、2.0 这种语义化版本。截至本文写作时间 2026 年 8 月 5 日,官方 Release 页面列出的最新稳定规范是 2026-07-28,上一版是 2025-11-25。
这两个日期很重要,因为 MCP Client 和 Server 并不会因为代码更新就自动说同一种“方言”。客户端必须先确定对方支持哪个协议版本,再按对应版本的生命周期和消息结构通信。
| 版本 | 状态 | 核心模型 |
|---|---|---|
2025-11-25 |
仍会在存量实现中存在 | 初始化握手、连接级状态、服务端可发起请求 |
2026-07-28 |
最新稳定版 | 无状态、自描述请求、客户端驱动的多轮交互 |
draft |
持续变化 | 下一版候选内容,不适合直接当稳定接口承诺 |
官方也提醒过:SDK 会按各自节奏采用新规范,旧版本可能继续存在一段时间。生产环境不能只看 SDK 包版本,应该确认它实际支持的 protocol revision。
二、这次更新到底改了什么
先给一张速查表。
| 旧模型 | 2026-07-28 新模型 |
直接影响 |
|---|---|---|
initialize / notifications/initialized |
每个请求携带版本和能力;可用 server/discover 探测 |
生命周期重写 |
Mcp-Session-Id |
删除协议级 Session | HTTP 服务更容易无状态扩缩容 |
| 服务端主动调用 Sampling、Elicitation、Roots | Multi Round-Trip Requests(MRTR) | 所有业务请求仍由客户端发起 |
| HTTP GET 通道和分散的资源订阅 | subscriptions/listen |
长连接通知入口统一 |
| 列表结果主要靠变更通知刷新 | ttlMs + cacheScope |
客户端可以标准化缓存 |
| Tasks 位于核心协议且处于实验状态 | io.modelcontextprotocol/tasks 官方扩展 |
长任务独立演进 |
| Roots、Sampling、Logging 处于核心能力 | 标记为 Deprecated | 新实现不应继续接入 |
| SSE 事件 ID 支持断线续传 | 删除响应流恢复与消息重投 | 断线后用新请求重新执行 |
我认为这版最值得记住的只有一句话:
MCP 从“先建立一段有状态会话,再在会话里双向通信”,转向“每个请求自带协议信息,由客户端驱动一次或多次往返”。
后面的变化几乎都能从这句话推出来。
三、变化一:删除连接级 Session,协议转向无状态
旧版 Streamable HTTP 可以通过 Mcp-Session-Id 把多次调用关联到同一个服务端 Session。新规范直接删除了协议级 Session,也删除了这个 Header。
与此同时,tools/list、resources/list、prompts/list 的结果不应再因为某条连接不同而变化。一个请求打到实例 A,下一次打到实例 B,只要身份和参数相同,服务端暴露的能力就应该保持一致。
这对云端部署很友好:
- 请求更容易经过负载均衡分发;
- 服务端实例不必保存连接级协议状态;
- 扩容、滚动发布和故障转移更简单;
- 中间代理可以根据请求自带的信息做路由。
但“无状态协议”不等于“业务不能有状态”。购物车、研究任务、数据库游标当然仍然需要状态,只是不能再偷偷寄存在 MCP 连接里。
新规范给出的方向是:服务端创建显式 Handle,把它作为普通 Tool 参数交给客户端保管,后续调用再传回来。
{ |
这种设计看起来啰嗦一点,却把状态所有权说清楚了:协议负责搬运 Handle,服务端负责 Handle 对应的数据、权限、过期时间和清理策略。
四、变化二:用 server/discover 取代初始化握手
2025-11-25 及更早版本建立连接时,客户端会发送 initialize,双方交换版本和能力,然后客户端再发 notifications/initialized。
到了 2026-07-28,这套握手被删除。每个请求都在 _meta 中携带:
io.modelcontextprotocol/protocolVersion:本次请求使用的协议版本;io.modelcontextprotocol/clientCapabilities:本次请求可使用的客户端能力;io.modelcontextprotocol/clientInfo:客户端身份,规范要求客户端应该提供。
服务端也应该在结果的 _meta 里返回 io.modelcontextprotocol/serverInfo。
一个简化后的请求会长这样:
{ |
请求已经可以自我描述,为什么还要 server/discover?
因为客户端在第一次正式调用前,可能还不知道服务端支持哪些版本和能力。新规范要求 Server 实现 server/discover,用来返回支持的协议版本、服务端能力和身份。客户端可以先探测,再选择双方都支持的最高版本。
这里要注意兼容逻辑:老 Server 不认识 server/discover,新 Client 不能看到 MethodNotFound 就宣布服务挂了。它应该识别这是旧时代实现,再回退到 initialize 流程。
同样,新 Server 收到不支持的版本时,会返回 UnsupportedProtocolVersionError,而不是在一段已建立的 Session 中重新协商。
五、变化三:MRTR 取代服务端主动请求
这是整版规范里最容易读懵、也最关键的变化。
旧版 MCP 允许 Server 主动向 Client 发 JSON-RPC Request,例如:
sampling/createMessage:请求客户端调用模型;elicitation/create:请求客户端向用户收集信息;roots/list:请求客户端提供可访问的根目录。
问题是,一旦允许服务端在任意时刻反向发请求,HTTP、代理、重试和断线恢复都会变复杂。新规范换了一个思路:服务端不再主动开一条反向 RPC,而是在当前响应中声明“我还缺什么”。
这就是 Multi Round-Trip Requests,简称 MRTR。
MRTR 的一次完整往返
用户调用 book_flight,但没有提供付款确认:
- Client 发送原始
tools/call。 - Server 返回
resultType: "input_required",并在inputRequests中描述需要用户确认的内容。 - Client 展示确认界面或收集其他输入。
- Client 重新发送原始请求,同时带上
inputResponses。 - Server 得到足够输入,返回
resultType: "complete"。
示意响应如下:
{ |
新规范还要求所有 Result 都带 resultType。普通完成结果是 "complete",需要继续交互则是 "input_required"。为了兼容旧 Server,Client 看到没有该字段的旧版结果时,应按 "complete" 处理。
MRTR 的好处不是少写几行代码,而是把控制方向统一了:请求永远由客户端发起,服务端只返回结果或额外输入需求。代价也很直接——Client 必须保存并重放原始请求,Server 则要用 requestState 等显式数据关联多轮交互。
六、变化四:统一订阅与通知通道
旧版 Streamable HTTP 存在 HTTP GET SSE 通道,资源又有 resources/subscribe、resources/unsubscribe,通知入口比较分散。
新规范用 subscriptions/listen 统一处理客户端主动订阅的服务端变更通知。Client 通过一个长生命周期的 POST 响应流,选择自己关心的类型:
toolsListChanged;promptsListChanged;resourcesListChanged;resourceSubscriptions。
服务端确认订阅后,会用 io.modelcontextprotocol/subscriptionId 标记相关通知。
这里有一条边界必须分清:
- 工具列表变化这类跨请求通知,走
subscriptions/listen; notifications/progress、notifications/message这类请求内通知,继续走原请求的响应流。
另外,Streamable HTTP 不再支持通过 Last-Event-ID 和 SSE Event ID 恢复中断的响应流。连接断开意味着当前请求结果丢失,Client 必须使用新的 Request ID 重新发起调用。
这就带回一个老问题:如果 Tool 有副作用,重试是否会执行两次?答案是可能。因此支付、退款、发消息、创建工单等 Tool 必须在业务层实现幂等,不能指望传输层替你实现 exactly-once。
七、变化五:列表与读取结果支持标准缓存语义
Agent 每轮都重新拉取完整工具列表,会消耗网络、序列化开销和模型 Prompt。尤其 Tool 多的时候,仅工具描述就可能占掉大量上下文。
2026-07-28 为以下结果引入统一的 CacheableResult 语义:
tools/list;prompts/list;resources/list;resources/read;resources/templates/list。
这些结果需要返回:
| 字段 | 含义 |
|---|---|
ttlMs |
新鲜度提示,告诉 Client 多久内可以复用结果 |
cacheScope |
public 允许共享中间缓存;private 只允许面向当前用户或授权上下文缓存 |
这两个字段与 listChanged 通知是互补关系,不是二选一。TTL 负责“多久可以先相信缓存”,通知负责“服务端知道变化时主动失效”。
规范还建议 tools/list 使用确定性顺序返回工具。这不是洁癖:列表顺序稳定,客户端缓存和 LLM Prompt Cache 才更容易命中。
我会把它列为本版最实用、却最容易被大特性掩盖的改动。它不炫,但能直接影响延迟和 Token 成本。
八、变化六:Tasks 从实验能力变成官方扩展
上一版把 Tasks 作为实验能力放进核心协议,用于跟踪长时间运行、可延迟取结果的请求。新版本把它移到 io.modelcontextprotocol/tasks 官方扩展中。
这不是删除 Tasks,而是承认它并不适合绑死在核心协议里。扩展可以独立演进,并由 Client 和 Server 显式声明支持。
新版 Tasks 的主要变化包括:
- 用
tasks/get轮询状态和结果,不再使用阻塞式tasks/result; - 新增
tasks/update,允许客户端在任务运行中补充输入; - 删除
tasks/list; - Server 可以直接返回 Task Handle,不需要每个请求事先选择加入。
适合 Tasks 的场景是:深度研究、长视频处理、大型代码分析、跨系统审批。普通的 200 毫秒数据库查询没必要包装成 Task。
还有一个容易混淆的点:MRTR 解决“当前请求缺少输入”,Tasks 解决“工作需要长时间异步执行”。一个 Task 在执行途中需要用户补信息时,两者可以组合。
九、哪些功能被弃用了
2026-07-28 正式引入特性生命周期和弃用策略。Deprecated 不等于立刻删除:功能仍在规范中工作,但新实现不应该再接入,并且至少有十二个月弃用窗口。
| 被弃用能力 | 官方建议方向 | 我的判断 |
|---|---|---|
| Roots | 用 Tool 参数、Resource URI 或 Server 配置传递目录和文件 | 权限边界更显式 |
| Sampling | Server 直接集成模型 Provider API | 减少协议内反向模型调用 |
| Logging | stdio 写 stderr,远程服务使用 OpenTelemetry |
日志回归标准可观测体系 |
| HTTP+SSE Transport | 迁移到 Streamable HTTP | 旧 Transport 不应再新建项目 |
includeContext: thisServer/allServers |
省略字段或使用 none |
避免隐式扩散上下文 |
| OAuth Dynamic Client Registration | 优先 Client ID Metadata Documents | 客户端身份配置更适合现代部署 |
这里最引人注意的是 Sampling。2025-11-25 才刚给 Sampling 增加 Tool Calling,新版却把整个 Sampling 标记为 Deprecated。这并不矛盾:社区最终选择简化 MCP 核心,让 Server 需要模型能力时直接连接 Provider,而不是让 MCP Client 充当模型代理。
如果你维护现有实现,不必马上拔掉这些能力;但如果今天新写一个 Server,我不会再围绕 Roots、Sampling 或协议 Logging 设计核心功能。
十、安全、Schema 与可观测性变化
除了主架构,本版还有几项值得开发者逐条检查的变化。
HTTP Header 更明确
Streamable HTTP POST 请求需要携带标准 Mcp-Method、Mcp-Name Header,方便网关或中间件在不解析 JSON Body 的情况下识别请求。Tool 参数还可以通过 x-mcp-header 映射为自定义 Header。
消息体仍然是协议元数据的事实来源。如果 Header 与 Body 冲突,Server 应返回 HeaderMismatchError。
OAuth 凭证必须按 Issuer 隔离
Client 不能把一个 Authorization Server 签发的凭证拿去另一个 Authorization Server 使用。持久化凭证需要以 Issuer 为键;授权服务变化时,应重新注册。
授权响应如果包含 RFC 9207 的 iss,Client 必须校验它与之前记录的 Issuer 一致。这类要求看起来琐碎,却是在挡授权服务器混淆攻击。
Tool Schema 更完整
inputSchema 和 outputSchema 现在允许使用任意 JSON Schema 2020-12 关键字,structuredContent 可以是任意 JSON 值,而不局限于对象。实现方还要正确处理 $ref,并对递归或组合 Schema 设置资源上限,避免恶意 Schema 拖垮解析器。
OpenTelemetry Trace Context 有了约定
规范记录了通过 _meta 传播 traceparent、tracestate、baggage 的约定。对于跨 Host、Client、Server 的一次 Agent 调用,这比自造 trace_id 字段靠谱得多。
需要注意:baggage 可能携带业务信息,传播前要做白名单和敏感数据控制。
十一、如何从旧版迁移
这次迁移不适合用“升级 SDK,然后重新编译”带过。建议按下面顺序做。
1. 先做版本矩阵
列清楚你支持的 Client、Server、Transport 和协议版本。尤其确认 SDK 是“发布了新版”还是“完整实现了新版规范”。两者不是一回事。
2. Client 同时支持两套生命周期
新 Client 可以先调用 server/discover。如果对方支持 2026-07-28,使用无状态请求;如果返回 MethodNotFound 或符合旧实现特征,再退回 initialize。
不要看到任何错误都降级。UnsupportedProtocolVersion、Header 不一致、缺少必要能力通常是实质错误,盲目回退可能掩盖配置问题。
3. 清理连接级状态
搜索 Mcp-Session-Id、按连接保存的工具列表、连接专属权限和内存 Session。业务状态改用显式 Handle,并绑定租户、用户、权限、TTL 和审计信息。
4. 重写服务端主动请求
把 Sampling、Elicitation、Roots 等反向 RPC 使用点列出来:
- 需要用户输入的流程迁移到 MRTR;
- Server 需要模型能力时评估直接集成 Provider;
- 文件和目录范围改为显式参数、Resource URI 或配置。
5. 重新审视重试
响应流不再续传,Client 会重新发起请求。有副作用的 Tool 必须支持业务幂等键,并能查询最终执行状态。只在 Agent 内存里记“调用过一次”不够。
6. 加入协议级测试
除了单元测试,还应覆盖:
- 新旧版本探测与回退;
- 每个请求的
_meta是否完整; - MRTR 多轮输入和取消;
- 通知订阅断开与重连;
- TTL 缓存失效;
- 有副作用 Tool 的超时重试;
- Deprecated 能力的兼容窗口。
官方已经维护 MCP Conformance Test Framework。能跑一致性测试,就别只用两个自家 Demo Client 互调后宣布兼容。
十二、常见问题
| 问题 | 回答要点 |
|---|---|
2026-07-28 还是 RC 吗? |
不是。官方已在 2026 年 7 月 28 日发布稳定版。 |
| 无状态后 MCP Server 不能保存任务状态了吗? | 可以保存业务状态,但要通过显式 Handle、Task 等方式关联,不能依赖连接级 Session。 |
server/discover 每次请求都要调用吗? |
不需要。它用于发现版本、能力和身份;正式请求本身仍要携带版本与客户端能力。 |
| MRTR 是不是 WebSocket? | 不是。它是多轮请求—响应模式,客户端补充输入后重新发送原请求。 |
| MRTR 和 Tasks 有什么区别? | MRTR 处理“还缺输入”,Tasks 处理“执行时间很长”;两者可以组合。 |
| Streamable HTTP 还能用 SSE 吗? | 响应仍可使用请求范围的 SSE Stream,但旧的独立 HTTP+SSE Transport 已弃用,Event ID 续传也被删除。 |
| Roots、Sampling、Logging 已经不能用了吗? | 仍处于 Deprecated 窗口,可以兼容存量实现,但新项目不应继续依赖。 |
| 所有 SDK 都已经支持新版了吗? | 不一定。协议发布与 SDK 落地存在时间差,需要逐个核对 SDK 的协议版本和功能覆盖。 |
| 旧 MCP Server 要立即升级吗? | 不必一刀切,但 Client 应支持版本协商,Server 应制定迁移和弃用计划。 |
2026-07-28 做了一件很克制的事:它主动删掉了不少“连接建立以后会比较方便”的机制,换来请求自描述、基础设施友好和更清楚的控制方向。
这会让一部分应用代码变得更显式——状态要有 Handle,多轮输入要重发请求,副作用要自己保证幂等。可这些复杂度本来就存在。新协议只是没再把它们藏在 Session 和双向连接里。