MCP 2026-07-28 发布第五版规范,协议内核从有状态改为无状态。本文逐项对照新旧变化,梳理架构影响与迁移路径。

一、协议变更概述

MCP(Model Context Protocol)在 2026-07-28 发布了第五版规范。这是自 2024 年 11 月协议问世以来幅度最大的一次修订——协议内核从有状态改为无状态。
在这里插入图片描述

MCP 最初的设计场景是桌面应用。Claude Desktop 启动一个本地 MCP 服务器进程,通过 stdio 通信,一个进程对应一个会话,生命周期明确。有状态设计在桌面场景下是合理的——握手后拿到 Session-Id,后续请求携带即可。

随着 MCP 采用量快速增长——月 SDK 下载量突破 4 亿次 [1],社区贡献了 950+ 个 MCP 服务器 [1]——服务从桌面端走向云端、从单进程走向集群时,有状态设计的局限性开始显现。

有状态协议在远程生产环境中有三个主要问题:

  • 粘滞会话:客户端必须持续连接到同一个服务端实例,负载均衡器需要维护 session affinity,无法使用普通轮询负载均衡,也无法部署在 Serverless 和边缘计算架构上。
  • 水平扩展受限:新增实例不持有已有会话,要么迁移会话,要么维护共享状态存储。
  • 滚动发布与故障转移影响进行中会话:旧实例下线意味着所有会话中断。

2025-03-26 引入的 Streamable HTTP 传输在有状态框架下做了补丁——保留了 initialize 握手和 Mcp-Session-Id。2026-07-28 版本彻底改变了这一设计。
在这里插入图片描述


二、新旧对照视图

2.1 核心变更对照

变更项 旧版 新版 影响
会话管理 initialize 握手 + Mcp-Session-Id 无状态,请求头自描述 可水平扩展,支持普通轮询负载均衡
能力发现 initialize 响应协商 server/discover 方法 服务端必须实现新端点
请求头 无标准化请求头 Mcp-Method(必需)、Mcp-Name(条件必需) 网关层可直接路由,无需解析请求体
缓存 ttlMs + cacheScope 列表结果可客户端缓存
Roots 支持资源根注册 进入 12 个月弃用窗口 需迁移至工具参数或资源 URI
Sampling 服务端可请求模型采样 进入 12 个月弃用窗口 改为服务端直接接入模型 API
Logging 服务端日志通道 进入 12 个月弃用窗口 改用 OpenTelemetry 或 stderr
HTTP 传输 HTTP GET + SSE 流 仅 Streamable HTTP 旧 SSE 传输须迁移
多轮交互 依赖长连接 MRTR(多轮往返请求) 连接中断后任意实例可接手

2.2 请求流程对比

旧版流程

Client → Server: initialize (protocolVersion, capabilities, clientInfo)
Server → Client: initialize (protocolVersion, capabilities, serverInfo, …)
Client → Server: notifications/initialized
— 此后所有请求携带 Mcp-Session-Id —
  → 负载均衡器必须维护 session affinity
  → 会话丢失 = 所有工具状态丢失

新版流程

Client → Server: server/discover (查询服务端能力和版本)
Client → Server: 独立请求(每个请求自包含协议版本与能力信息)
  → 普通轮询负载均衡
  → 支持 Serverless 和边缘部署

新版中每个请求自描述,携带完整的协议信息:

POST /mcp HTTP/1.1
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: search
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "search",
    "arguments": {"q": "stateless MCP"},
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": {
        "name": "example-client",
        "version": "1.0.0"
      }
    }
  }
}

2.3 能力发现:server/discover

新版中服务端必须实现 server/discover 方法,客户端在首次连接时通过它查询服务端支持的协议版本、能力和身份,取代了旧版的 initialize 握手。

POST /mcp HTTP/1.1
MCP-Protocol-Version: 2026-07-28
Mcp-Method: server/discover

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "server/discover"
}

服务端返回:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2026-07-28",
    "capabilities": {
      "tools": {},
      "resources": {},
      "prompts": {}
    },
    "serverInfo": {
      "name": "example-server",
      "version": "1.0.0"
    }
  }
}

2.4 请求头与缓存

Mcp-Method 是所有 Streamable HTTP 请求的必需请求头。tools/callresources/readprompts/get 还必须携带 Mcp-Name。这两个字段让网关不解析 JSON 请求体即可识别请求意图,按工具配置速率限制、路由和审计策略。服务端必须校验请求头与 JSON-RPC 请求体的一致性,不一致时拒绝请求。

tools/listresources/list 等列表操作的响应结果新增了 ttlMscacheScope 字段,客户端据此判断结果缓存时长和跨用户共享范围,减少重复查询。


三、状态管理:从会话到句柄

无状态化之后,业务状态怎么存,是每个 MCP 服务器开发者需要重新思考的问题。在这里插入图片描述

3.1 句柄模式的设计逻辑

旧版协议中,状态通过 Session-Id 隐式关联到服务端会话。服务端在内存中维护一个会话上下文,客户端只要带上 Session-Id,服务端就知道"这个请求属于哪个会话"。但这个上下文对模型是透明的——模型只知道要发请求,不知道也不关心传输层维护了什么状态。

新版的做法是把状态推到业务层:工具调用返回一个显式句柄,模型在后续调用中将其作为参数传回。服务端可以把句柄对应的状态存在任何地方——数据库、对象存储、Durable Object——协议只负责传递一个标识符。

一个典型的交互流程如下:

// 工具返回句柄
{
  "tool": "browser_open",
  "result": {
    "browser_id": "brw_7f31a2c8",
    "url": "https://example.com",
    "status": "loaded"
  }
}

// 后续操作将句柄作为参数
{
  "tool": "browser_click",
  "arguments": {
    "browser_id": "brw_7f31a2c8",
    "selector": "#submit-btn"
  }
}

3.2 这种设计好在哪

从架构角度看,句柄模式有三个值得注意的优势。

第一,句柄对模型可见。模型可以理解"这个 ID 对应刚才打开的浏览器页面",可以在多个工具之间组合和传递。旧版 Session-Id 对模型不透明,模型无法对其推理,也就无法做出"需要先打开页面再点击"这类跨工具决策。

第二,部署无关。任意服务实例只要能访问共享状态存储,就可以处理任何句柄的请求。这给了开发者选择存储方案的自由——可以用 Redis、PostgreSQL、S3、Durable Objects,取决于业务场景。

第三,语义边界清晰。句柄的作用域、权限和有效期由业务层控制,不由协议层隐式管理。一个句柄在什么条件下有效、由谁生成、可以被哪些工具使用,这些信息都可以在工具定义中明确声明。

3.3 代价

句柄模式也引入了新的复杂性。句柄需要是不可猜测的标识符(如 UUID),不能把数据库主键直接暴露给模型;工具定义需要说明句柄由哪个调用产生、可以传给哪些调用;删除、退款、支付等高风险操作不能只凭句柄授权,仍需验证用户身份;服务端还需要处理幂等——客户端在网络中断后重试时,同一操作不应被执行两次。

这些代价在旧版 Session 机制下同样存在,只是被协议层隐式处理了。新版把这些责任从协议层转移到了业务层,让开发者有了更多控制权,同时也要承担更多管理责任。从协议设计的角度看,这是合理的取舍——MCP 负责描述请求、能力和交互模式,业务状态由应用自己管理。


四、交互模式:从长连接到 MRTR

4.1 长连接的问题

某些工具调用无法一次收齐所有参数。创建云资源前要先展示价格,删除数据前需要用户确认,表单走到中途可能还需要补充字段。

旧版协议依赖长连接维持这些交互状态。服务端保持连接打开,等待客户端下一步输入。这在有状态模式下可以工作,但代价是连接必须持续存在,且始终路由到同一个服务端实例。一旦连接中断,整个交互流程必须从头开始。

4.2 MRTR 的工作原理

新版引入的 MRTR(Multi Round-Trip Requests)改变了这个模式。服务端在需要用户输入时返回 InputRequiredResult,客户端收集输入后重新发送完整请求。

// 服务端返回:需要用户确认
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "resultType": "input_required",
    "inputRequests": {
      "confirm": {
        "type": "elicitation",
        "message": "将删除 3 个文件,是否继续?",
        "schema": {"type": "boolean"}
      }
    },
    "requestState": "opaque-server-state"
  }
}

// 客户端重发:附带用户确认
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "delete_files",
    "arguments": {"paths": ["/tmp/a", "/tmp/b", "/tmp/c"]},
    "inputResponses": {
      "confirm": true
    },
    "requestState": "opaque-server-state"
  }
}

关键变化在于,任意服务实例都可以接手这次重试。它不需要持有上一次请求的连接,也不需要认识原来的协议会话。每次交互都是一个完整的请求-响应周期,无需持续维护一个长连接流。

MRTR 还给交互增加了一层安全约束:服务端只有在处理客户端请求时才能提出输入要求。客户端不会在没有用户或代理发起动作的情况下,突然收到一个服务端确认框。


五、订阅、可观测性与迁移策略

5.1 订阅机制重构

旧版的 HTTP GET 流、SSE 断点续传、Last-Event-ID 和事件重投递被移除。变更通知合并到 subscriptions/listen,客户端通过长生命周期的 POST 响应流订阅资源变化。

一个可能被忽略的细节是:MCP 移除了跨请求的协议会话,但保留了请求范围内的流式响应和显式订阅流。这意味着响应流可以在单个请求范围内持续推送数据,但不同请求之间不再有隐式的状态关联。这个边界划分很关键——它区分了"一次请求的持续响应"和"多个请求之间的会话关联"。

5.2 可观测性的提升

新版规范统一了 OpenTelemetry Trace Context 在 _meta 中的键名。结合 Mcp-MethodMcp-Name 请求头,网关可以实现完整的调用链追踪。

这些变化没有工具调用本身醒目,但更接近生产团队每天要处理的问题。在旧版中,MCP 请求的追踪和路由因为 session affinity 的存在变得复杂——网关无法直接按工具类型分发请求,观测数据也难以聚合。新版让 MCP 的请求可以像普通 HTTP 服务一样被观测和管理。

5.3 迁移策略

2026-07-28 包含破坏性变更,直接升级会有兼容性问题。建议的迁移路径是分六步执行:

第一步:盘点会话依赖

搜索代码中的 Mcp-Session-Idinitializeinitialized,列出所有按会话保存的数据。

MCP 迁移检查清单 ① — 会话依赖
□ 是否使用了 initialize 握手? → 改为 server/discover
□ 是否依赖 Mcp-Session-Id? → 移除会话状态管理
□ 会话中保存了哪些数据? → 评估哪些需要跨请求保留

第二步:迁移服务端发起请求

MCP 迁移检查清单 ② — 服务端请求
□ 是否使用了 Sampling? → 改为服务端直接接入模型 API
□ 是否使用了 Roots? → 改为工具参数或资源 URI
□ 是否需要用户确认? → 改用 MRTR
□ 是否使用了进度通知? → 仍可通过响应流返回

第三步:改造传输和订阅

MCP 迁移检查清单 ③ — 传输和订阅
□ 是否使用了 HTTP GET + SSE 流? → 迁移到 Streamable HTTP
□ 是否使用了 Last-Event-ID 或事件重投递? → 应用层重试
□ 是否使用了 resources/subscribe? → 改为 subscriptions/listen
□ 是否使用了 ping? → 无需替代
□ 是否使用了 logging/setLevel? → 改为 OpenTelemetry 或 stderr

第四步:补齐网关与安全校验

MCP 迁移检查清单 ④ — 网关和安全
□ 是否为每个 Streamable HTTP POST 添加了 MCP-Protocol-Version 头?
□ 是否为 tools/call 等请求添加了 Mcp-Method 和 Mcp-Name 头?
□ 是否在服务端校验了请求头与请求体的一致性?
□ OAuth 客户端是否验证了 iss 字段?
□ 凭据存储是否按 issuer 分区?

第五步:双版本运行

过渡期内,生产端点最好同时支持 2025-11-25 和 2026-07-28:

MCP 迁移检查清单 ⑤ — 双版本兼容
□ 新客户端能否先调用 server/discover?
□ 遇到只支持旧版的服务端,能否回退到旧握手?
□ 双版本支持是否覆盖了真实客户端、网关和重试场景?
□ 协议兼容是否经过了集成测试?

第六步:流量切换

MCP 迁移检查清单 ⑥ — 切换
□ 是否先部署了无状态端点并观察了错误率?
□ 是否对比了重试率、缓存命中率和 MRTR 完成率?
□ 滚动发布期间是否有失败监控?
□ 旧会话自然排空后,是否移除了旧路由?
□ 是否给仍在使用旧 SDK 的客户端设定了明确的升级期限?

先部署无状态端点观察错误率,待旧会话自然排空后再移除旧路由。


六、SDK 与生态

SDK 语言 状态 版本 备注
TypeScript Tier 1 稳定版 v2.x 拆分为 server/client 独立包
Python Tier 1 稳定版 v2.x 同步更新
Go Tier 1 稳定版 v1.7.0 支持 2026-07-28
C# Tier 1 稳定版 v1.0-preview 同步更新
Rust 社区稳定版 rmcp 3.0.0 已发布

Cloudflare Agents SDK 0.20.0 已支持 2026-07-28 客户端和服务端。Google MCP Toolbox for Databases 已支持候选规范。Figma、Intuit、Netlify、Zoom 等企业已公开支持新规范。

Claude 产品线同步推出 MCP Apps(服务端在对话中渲染交互式 UI)、EMA(企业托管认证,通过 Okta/Entra 统一配置连接器)、MCP Tunnels(研究预览,安全连接内网 MCP 服务器)。

这次改动的价值集中在远程服务的可运维性上。无状态内核让请求可经过普通负载均衡器落到任意实例;显式句柄承载业务状态;MRTR 承载用户确认;subscriptions/listen 承载持续通知;标准请求头、缓存字段和追踪字段服务于网关与观测。

从协议演进的视角看,这是一轮协议边界的重新划分——MCP 负责描述请求、能力和交互模式;业务状态、恢复策略、权限和幂等由应用自己管理。这个边界更清晰,也更适合生产环境。


参考来源:

[1] Anthropic 官方博客:Bringing MCP 2026-07-28 to Claude(2026-07-28) [2]
MCP 2026-07-28 稳定版
Release:https://github.com/modelcontextprotocol/specification/releases/tag/v2026-07-28
[3] MCP
变更日志:https://github.com/modelcontextprotocol/specification/blob/main/CHANGELOG.md
[4] MCP 官方 SDK 分级页:https://modelcontextprotocol.io/sdk [5] 涂阿燃:MCP
2026-07-28 无状态协议如何改变部署、交互与迁移(2026-07-29) [6] Cloudflare Agents SDK
0.20.0 更新说明 [7] Google MCP Toolbox for Databases 公告

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐