MCP 2.0 深度解析:2026-07-28 无状态协议、完整差异与实战指南

2026 年 7 月 28 日发布的 Model Context Protocol 最新规范 不是一次普通增量更新。它移除了协议级会话和初始化握手,把版本与能力协商移到每一个请求,用 MRTR 重构服务器向客户端索取信息的方式,并将长任务移出核心协议。
如果把早期 MCP 看成“为桌面 AI 应用连接本地工具的会话协议”,那么这次修订更像是“可穿过网关、负载均衡器和无状态计算平台的 Agent 基础设施协议”。
MCP 官方使用日期作为协议版本,例如 2025-11-25、2026-07-28,官方没有发布名为 MCP 1.0 或 MCP 2.0 的语义化版本。
为方便理解,本文将官方称为 Legacy 的 2025-11-25 及更早版本简称为“MCP 1.0”,将官方称为 Modern 的 2026-07-28 版本简称为“MCP 2.0”。这是社区化表达,不是官方版本名。生产代码必须使用日期版本。
一、先看结论:MCP 2.0 改变了什么?
一句话概括:
MCP 2.0 把协议状态从“连接和会话”搬进了“每个请求、显式参数和可验证句柄”。
最重要的变化有九类:
- 删除
initialize/notifications/initialized握手。 - 删除协议级 Session 和
Mcp-Session-Id。 - 每个请求通过
_meta携带版本、客户端身份和能力。 - 新增服务器必须实现的
server/discover。 - 用 MRTR 的
input_required结果替代服务器主动反向请求。 - 用
subscriptions/listen统一承载长期变更通知。 - 所有成功结果必须有
resultType,普通结果为complete。 - 长任务从核心移到
io.modelcontextprotocol/tasks官方扩展。 - 加入缓存提示、标准 HTTP 头、OpenTelemetry 上下文和更严格的授权规则。

这张图左侧表示 Legacy MCP:客户端先穿过初始化握手,随后依赖连接上的会话状态,双向请求和事件也共享长连接语境。右侧表示 Modern MCP:每个请求自带版本和能力,可以落到任意服务器实例;发现、请求级进度和长期订阅各自拥有清晰通道。
二、MCP 到底解决什么问题?
MCP 是连接 LLM 应用与外部数据、工具和工作流的开放协议。它使用 JSON-RPC 2.0 定义 Host、Client 和 Server 之间的交互,让 AI 应用不必为每一个数据库、代码仓库、SaaS 或本地工具单独设计插件协议。
2.1 三个核心角色
- Host:LLM 应用和总协调者,管理用户授权、上下文聚合、多个 Client 与模型调用。
- Client:Host 内部与一个特定 Server 通信的连接器;每个 Client 只对应一个 Server。
- Server:提供聚焦能力的服务,可以是本地进程,也可以是远程 HTTP 服务。
安全边界非常重要:Server 默认不应看到完整对话,也不应看到其他 Server 的上下文。Host 决定把哪些信息交给哪个 Server。
2.2 Server 暴露的三类原语
| 原语 | 控制者 | 用途 | 例子 |
|---|---|---|---|
| Resources | 应用控制 | 向模型提供可读取的上下文和数据 | 文件、数据库记录、API 响应 |
| Prompts | 用户控制 | 提供可复用的提示模板和工作流入口 | 代码审查模板、事故复盘模板 |
| Tools | 模型控制 | 允许模型在用户同意下执行动作 | 查询、写文件、创建工单、部署 |
MCP 2.0 没有抛弃这三个核心原语,而是重新设计了承载它们的基础协议。
三、MCP 1.0 与 MCP 2.0 完整差异表
官方 Key Changes 将 2026-07-28 与前一版 2025-11-25 的变化分为重大变化、次要变化和弃用项。下面按工程影响重新整理。
| 维度 | MCP 1.0 / Legacy(≤ 2025-11-25) | MCP 2.0 / Modern(2026-07-28) | 工程影响 |
|---|---|---|---|
| 协议状态 | 连接/会话承载状态 | 协议无状态,每次请求自包含 | 易于横向扩容和故障转移 |
| 初始化 | initialize → notifications/initialized | 删除初始化握手 | 首次请求不必绑定后续连接 |
| Session | Streamable HTTP 可用 Mcp-Session-Id | 删除协议级 Session | 不再需要粘性会话 |
| 版本声明 | 初始化时协商 | 每个请求 _meta 都带版本 | 请求可独立校验和路由 |
| HTTP 版本头 | MCP-Protocol-Version 已存在于部分版本 | 每个 POST 必须携带,且必须与 _meta 一致 | 网关可快速拒绝错误版本 |
| 能力协商 | 初始化时声明一次 | 每个请求携带 Client capabilities | 能力按请求生效 |
| 服务器发现 | 依赖初始化响应 | Server 必须实现 server/discover | 可预先发现版本、能力和身份 |
| 版本不兼容 | 初始化失败或实现自定义处理 | 标准 UnsupportedProtocolVersion,错误码 -32022 | 客户端可选择共同版本后重试 |
| 服务端反向请求 | Server 可主动发 roots/list、Sampling、Elicitation | 禁止主动请求,改用 MRTR | 更适配无状态 HTTP 和负载均衡 |
| 多轮交互 | 同一连接上的双向 JSON-RPC | input_required → Client 收集输入 → 新 ID 重试原请求 | 每一轮可落到不同实例 |
| 成功结果 | 结果没有统一判别字段 | 所有结果必须包含 resultType | 支持 complete、input_required、扩展结果 |
| 普通成功 | 任意结果对象 | resultType: "complete" | 客户端必须按结果类型分发 |
| 长任务 | Tasks 曾是核心实验能力 | 移到 io.modelcontextprotocol/tasks 扩展 | 核心更小,异步能力可独立演进 |
| 长任务取结果 | 阻塞式 tasks/result | tasks/get 轮询,tasks/update 提交中途输入 | 断线后可通过 task handle 恢复 |
| 长期通知 | HTTP GET 流、资源订阅 RPC 和连接事件混合 | 单一 subscriptions/listen POST 响应流 | 订阅意图明确,可按类型选择 |
| 资源订阅 | resources/subscribe / resources/unsubscribe | 由 subscriptions/listen 的 resourceSubscriptions 替代 | 统一通知模型 |
| 请求级通知 | 与其他长流容易混合 | 只走发起该请求的响应 SSE | Progress/Logging 与请求严格关联 |
| Streamable HTTP GET | 可建立独立 GET SSE 流 | 删除 GET,只保留 POST | MCP Endpoint 更简单 |
| SSE 恢复 | Last-Event-ID 和事件重放 | 删除可恢复性与消息重发 | 断流后用新 request ID 重发请求 |
| Ping | 核心 ping | 删除 | 存活检测交给传输和平台 |
| 日志级别 | logging/setLevel | 每请求 _meta.io.modelcontextprotocol/logLevel | 不再依赖连接级设置 |
| 日志通知 | Server 可持续发送 | 只有请求明确带 logLevel 时才可发送 | 降低意外数据泄露与噪声 |
| Roots 变化通知 | notifications/roots/list_changed | 删除 | Roots 本身也进入弃用阶段 |
| 列表缓存 | 客户端自行决定 | ttlMs + cacheScope 成为必需提示 | 降低重复发现与 Token 成本 |
| 列表顺序 | 未强调稳定排序 | Tools 应确定性排序 | 提高 LLM Prompt Cache 命中率 |
| HTTP 路由头 | 中间件需解析 JSON Body | 必须有 Mcp-Method,部分请求必须有 Mcp-Name | 网关/WAF 可不解析 Body 即路由 |
| 工具参数转 Header | 无标准机制 | JSON Schema 支持 x-mcp-header | 可将区域、租户等参数镜像为 Header |
| JSON Schema | 约束较保守 | 完整支持 JSON Schema 2020-12 关键字和 $ref | 工具输入输出表达力更强 |
| Structured Content | 以对象为主 | 可为任意 JSON 值 | 数组、标量、null 都合法 |
| 可观测性 | 实现自行约定 | _meta 约定 traceparent、tracestate、baggage | 与 OpenTelemetry 链路贯通 |
| 扩展 | 实验能力常进入核心 | Capabilities 新增 extensions 映射 | 双方显式选择 Tasks、Apps 等扩展 |
| OAuth Issuer | 规则较弱 | 建议授权响应带 iss,Client 必须校验已出现的 iss | 防授权服务器混淆攻击 |
| Client 凭证 | 容易按 MCP Server 保存 | 必须按 Authorization Server issuer 绑定 | 禁止跨 Issuer 复用凭证 |
| 动态注册 | OAuth DCR 是主要路径之一 | DCR 弃用,转向 Client ID Metadata Documents | 更适合现代 OAuth 客户端发现 |
| 功能生命周期 | 缺少统一退役机制 | Active → Deprecated → Removed,至少 12 个月弃用窗口 | 迁移节奏更可预测 |
3.1 这不是“改几个字段”
旧实现常把初始化结果、能力、Session ID、订阅和反向请求绑定到一个连接对象。Modern MCP 要求这些假设全部拆开:
Legacy: Connection = Version + Capabilities + Session + Reverse Requests
Modern: Request = Version + Client Capabilities + Auth + Parameters
Server State = Explicit Handle / requestState / Task ID
Notifications = Dedicated subscriptions/listen Stream
因此,声称支持 2026-07-28 的实现不能只修改协议版本字符串。
四、核心变化详解
4.1 无状态:删除握手与协议 Session
Legacy 客户端首先发送 initialize,服务器返回选定版本、能力和实现信息,客户端再发送 notifications/initialized。Streamable HTTP 还可以用 Mcp-Session-Id 把后续请求绑定到同一会话。
Modern MCP 删除了整个流程。每个请求必须在 params._meta 中声明:
{
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "rainlib-client",
"version": "2.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {
"elicitation": {},
"extensions": {
"io.modelcontextprotocol/tasks": {}
}
}
}
这让负载均衡器可以把连续两次工具调用分配给不同实例。若业务本身需要跨调用状态,Server 应签发显式 handle,并让 Client 像普通工具参数一样回传,而不是偷偷依赖连接内存。
协议不再提供隐式 Session,但业务仍然可以有任务、事务、游标和工作流状态。差别在于这些状态必须通过明确的 taskId、cursor、tool argument 或受保护的 requestState 表达。
4.2 server/discover:服务器能力的新入口
Modern Server 必须实现 server/discover。Client 可在其他请求前调用它,获取:
supportedVersionscapabilitiesserverInfo- 可选的
instructions ttlMs和cacheScope
{
"jsonrpc": "2.0",
"id": "discover-1",
"method": "server/discover",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "rainlib-client",
"version": "2.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}
Server 返回的 serverInfo 是自报信息,只适合展示、日志和调试,不能用于安全决策。Client 也可以跳过 discovery,直接调用目标 RPC;若版本不支持,Server 返回 -32022 和支持版本列表,Client 再选择共同版本重试。
4.3 MRTR:服务器不再主动“反向调用”客户端
Legacy MCP 中,Server 可以在处理 tools/call 时主动向 Client 发出 elicitation/create、sampling/createMessage 或 roots/list 请求。这要求双方保持可双向通信的活跃连接,也给代理和水平扩容增加了复杂度。
Modern MCP 引入 Multi Round-Trip Requests:Server 不主动发请求,而是返回“我还缺什么”。

流程如下:
- Client 用 JSON-RPC ID
1发起tools/call。 - Server 返回
resultType: "input_required",其中包含inputRequests和可选requestState。 - Host 根据请求向用户收集信息、调用模型或提供 Roots。
- Client 用新的 JSON-RPC ID
2重试原始tools/call,附带inputResponses,并原样回传requestState。 - 任意 Server 实例仅凭新请求即可继续处理,最终返回
resultType: "complete"。
requestState 对 Client 是不透明字符串,Client 不得解析或修改。Server 必须把它当成攻击者可控输入;若它影响授权或业务逻辑,应使用 HMAC 或 AEAD 保护完整性,并绑定用户、短 TTL 和原始请求摘要。
4.4 subscriptions/listen:把长期通知放到专用流
Modern Streamable HTTP 只有一个支持 POST 的 MCP Endpoint:
长期变更通知只走 subscriptions/listen 的响应 SSE;notifications/progress 和按请求日志只走所属请求的响应流。两者不混用。
旧的 HTTP GET 流、resources/subscribe、resources/unsubscribe 被替换。SSE 也不再支持 Last-Event-ID 恢复:请求流断开就视为本次请求丢失,Client 应使用新 ID 重新发起。
4.5 结果多态:resultType 成为必需字段
所有成功结果现在都必须带 resultType:
resultType | 所属 | 含义 |
|---|---|---|
complete | Core | 请求已经完成 |
input_required | Core | Server 需要 Client 补充输入并重试 |
task | Tasks 扩展 | Server 已创建可持久化长任务 |
为了向后兼容,Modern Client 遇到旧 Server 返回的无 resultType 结果时,必须把它当作 complete。但 Modern Server 不能省略该字段。
4.6 Tasks:长任务成为正式扩展
Tasks 扩展 适用于 CI、批处理、部署、模型训练、人工审批等不应一直占用连接的操作:
Client 与 Server 都在 capabilities 中声明 io.modelcontextprotocol/tasks 后,Server 可返回 resultType: "task" 和持久化 taskId。Client 使用:
tasks/get:轮询状态和最终结果tasks/update:提交任务中途需要的输入tasks/cancel:请求协作式取消subscriptions/listen:可选接收notifications/tasks
断线重连后仍可用相同 taskId 恢复,这正是它相对“保持一个超长 SSE 响应”的价值。
4.7 缓存:为工具列表和资源读取降低成本
以下 complete 结果必须返回 ttlMs 与 cacheScope:
server/discovertools/listprompts/listresources/listresources/templates/listresources/read
ttlMs 是新鲜度提示,语义类似 HTTP max-age;cacheScope 只能是:
public:可跨用户、跨授权上下文共享缓存。private:只能在同一授权上下文复用。
通知和 TTL 可以组合:TTL 避免频繁拉取,收到 list_changed 或资源更新通知时立即让缓存失效。
工具列表还应保持确定性顺序。工具定义常被注入模型上下文,稳定排序能减少 Prompt 变化,提高 LLM Prompt Cache 命中率。
4.8 Streamable HTTP 更适合网关
每个 POST 除了 MCP-Protocol-Version,还必须镜像关键字段到 HTTP Header:
| Header | 来源 | 何时需要 |
|---|---|---|
MCP-Protocol-Version | _meta.io.modelcontextprotocol/protocolVersion | 所有 POST |
Mcp-Method | JSON-RPC method | 所有请求 |
Mcp-Name | params.name 或 params.uri | tools/call、resources/read、prompts/get |
这让 API Gateway、WAF 和可观测性组件无需解析 JSON Body 就能按方法和工具名执行路由、限流与审计。
工具的 JSON Schema 还可以用 x-mcp-header 把非敏感的原始参数镜像到 Mcp-Param-* Header,例如 region 或 tenant。密码、Token 和 PII 不应放入 Header,因为中间网络组件可能记录它们。
五、MCP 2.0 的主要特点
5.1 云原生和横向扩展友好
请求不依赖连接 Session,可被任意实例处理;滚动发布、自动扩缩容、Serverless 和多区域部署不再要求粘性会话。显式状态 handle 也更容易审计和设置生命周期。
5.2 能力按请求最小化
Client 不必在连接开始时永久开放全部能力。每个请求声明当前愿意支持的 Elicitation、Roots 或扩展,Server 不得发送 Client 未声明的 inputRequests。这形成更细的最小权限面。
5.3 核心更小,扩展更清晰
Tasks、MCP Apps 等能力通过双方显式协商启用:
- Tasks:长任务、断线恢复、人工审批、进度状态。
- MCP Apps:在对话内渲染沙箱化图表、表单、Dashboard 和媒体界面。
- Skills over MCP:面向 Agent 工作流的结构化指令发现与消费;相关规范仍应关注官方工作组进度。
一方不支持扩展时,支持方必须回退到 Core 行为或明确拒绝,不能假设对端理解额外字段。
5.4 可观察、可缓存、可治理
OpenTelemetry trace context、标准 Header、确定性工具顺序、显式 TTL、标准错误码和新的功能生命周期,使 MCP 更像生产级基础设施协议,而不只是桌面插件接口。
5.5 安全边界更明确
- 工具调用应始终允许用户拒绝,尤其是写操作。
- Tool annotations 必须视为不可信,除非来自可信 Server。
- Streamable HTTP Server 必须验证
Origin,本地服务建议只绑定127.0.0.1。 requestState必须防篡改、防跨用户复用并设置短 TTL。- OAuth Client 凭证必须绑定授权服务器 Issuer,不能跨 Issuer 复用。
serverInfo仅是自报元数据,不能作为身份认证依据。
六、哪些功能被弃用?
MCP 2.0 首次正式引入 Active、Deprecated、Removed 生命周期。Deprecated 功能仍在规范中,但新实现不应采用。根据官方弃用表:
| 弃用功能 | 推荐迁移路径 | 最早可移除时间 |
|---|---|---|
| Roots | 通过工具参数、Resource URI 或 Server 配置传目录/文件 | 2027-07-28 之后首个修订版 |
| Sampling | Server 直接集成 LLM Provider API | 2027-07-28 之后首个修订版 |
| Logging | stdio 写 stderr;生产可观测性使用 OpenTelemetry | 2027-07-28 之后首个修订版 |
| Dynamic Client Registration | Client ID Metadata Documents | 2027-07-28 之后首个修订版 |
| HTTP+SSE | Streamable HTTP | SEP-2596 Final 后三个月 |
includeContext: thisServer/allServers | 省略或使用 none | 跟随 Sampling |
Roots、Sampling 和 Logging 在当前规范中仍可工作,但新项目不应再围绕它们设计架构。双时代 Client 仍需兼容旧 Server,但应该为功能退出准备迁移路径。
七、如何使用 MCP 2.0:TypeScript Server 实战
下面用官方 TypeScript SDK 建立一个最小天气 Server。SDK 会处理协议层细节;业务代码重点是声明 Tool、Schema 和返回内容。
7.1 创建项目
官方教程要求 Node.js 20 或更高版本:
mkdir weather-mcp
cd weather-mcp
npm init -y
npm install @modelcontextprotocol/server zod
npm install -D typescript @types/node
package.json 至少配置 ESM 和构建命令:
{
"type": "module",
"scripts": {
"build": "tsc"
}
}
7.2 注册一个 Tool
import { McpServer } from "@modelcontextprotocol/server";
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import { z } from "zod";
const server = new McpServer({
name: "rainlib-weather",
version: "2.0.0",
});
server.registerTool(
"get_weather",
{
description: "Get current weather for a city",
inputSchema: z.object({
city: z.string().min(1).describe("City name"),
}),
},
async ({ city }) => {
// 实际项目应调用可信天气 API,并设置超时与错误处理。
const result = {
city,
temperatureC: 26,
condition: "Cloudy",
};
return {
content: [
{
type: "text",
text: `${city}: ${result.temperatureC}°C, ${result.condition}`,
},
],
structuredContent: result,
};
},
);
const transport = new StdioServerTransport();
await server.connect(transport);
// stdio Server 不能 console.log,否则会污染 JSON-RPC stdout。
console.error("Weather MCP Server is running");
McpServer 中的 version: "2.0.0" 是你的 Server 软件版本,不是 MCP 协议版本。协议使用日期 2026-07-28,由支持 Modern era 的 SDK/Transport 写入请求元数据并完成协商。升级前要确认所用 SDK 的协议支持矩阵,而不是只改应用版本号。
7.3 构建并运行
npx tsc
node build/index.js
对于 stdio Server,Host 通常通过配置启动本地命令:
{
"mcpServers": {
"weather": {
"command": "node",
"args": ["/ABSOLUTE/PATH/weather-mcp/build/index.js"]
}
}
}
Host 是否已经支持 2026-07-28 需要查看产品说明。Modern 与 Legacy 的传输行为存在破坏性差异,不能假设所有 MCP Client 都会立即升级。
八、直接调用 Modern Streamable HTTP
理解原始请求有助于排查 SDK、代理和 Header 不一致问题。一个符合 Modern MCP 的 tools/call 请求大致如下:
curl https://api.example.com/mcp \
-X POST \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2026-07-28' \
-H 'Mcp-Method: tools/call' \
-H 'Mcp-Name: get_weather' \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {"city": "Shanghai"},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "rainlib-cli",
"version": "2.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}'
正常 JSON 响应必须包含:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "complete",
"content": [
{
"type": "text",
"text": "Shanghai: 26°C, Cloudy"
}
],
"isError": false
}
}
注意四个常见错误:
- Header 的日期版本和 Body
_meta不一致,会返回HeaderMismatch。 - Server 不支持目标版本,应返回
-32022和supported列表。 tools/call缺少Mcp-Name不符合 Modern Streamable HTTP 规范。- 断开的 SSE 请求不能用
Last-Event-ID恢复,必须换新 JSON-RPC ID 重试。
九、使用 MCP Inspector 测试
MCP Inspector 是官方参考调试工具,能够协商 Legacy 与 Modern 协议时代。当前文档要求 Node.js 22.19.0 或更高版本。
9.1 Web UI
npx @modelcontextprotocol/inspector node build/index.js
适合查看 Tool、Resource、Prompt、原始协议消息、Capability 和错误响应。
9.2 CLI
# 列出工具
npx @modelcontextprotocol/inspector --cli \
node build/index.js \
--method tools/list
# 调用远程工具
npx @modelcontextprotocol/inspector --cli \
https://api.example.com/mcp \
--transport http \
--method tools/call \
--tool-name get_weather \
--tool-arg city=Shanghai \
--format json
9.3 TUI
npx @modelcontextprotocol/inspector --tui node build/index.js
在没有浏览器或通过 SSH 调试时,TUI 比 Web UI 更方便。
测试 Modern Server 时,至少检查:
server/discover能返回版本、能力、身份和缓存字段。- 每个请求都有正确
_meta。 - HTTP Header 与 Body 中的方法、名称、版本一致。
- 所有成功结果都有
resultType。 input_required重试使用新 ID,并原样回传requestState。- 列表和资源读取包含非负
ttlMs与正确cacheScope。 - Server 不依赖
Mcp-Session-Id或粘性负载均衡。
十、从 MCP 1.0 迁移到 MCP 2.0
10.1 Server 迁移清单
- 实现
server/discover。 - 删除
initialize、notifications/initialized依赖。 - 删除
Mcp-Session-Id与连接级状态。 - 将跨调用状态改为显式、受保护、有 TTL 的 handle。
- 所有成功结果添加
resultType。 - 把服务器反向请求重构为 MRTR。
- 用
subscriptions/listen替代 GET 流和资源订阅 RPC。 - 为可缓存操作返回
ttlMs和cacheScope。 - 确保 Tools、Prompts、Resources 列表顺序稳定。
- 为 Streamable HTTP 校验
Origin、版本头和标准请求头。 - 将长任务迁移到 Tasks 扩展或显式业务 Job API。
- 用 OpenTelemetry /
stderr替代对核心 Logging 的新依赖。
10.2 Client / Host 迁移清单
- 每个请求都携带协议版本、ClientInfo 和 ClientCapabilities。
- 支持
server/discover和-32022版本回退。 - 将结果解析改成按
resultType分发。 - 实现
input_required的收集输入与独立重试流程。 - 把
requestState当不透明值原样回传。 - 通过
subscriptions/listen管理变更通知。 - 处理请求 SSE 断流后的新 ID 重试,不再发送
Last-Event-ID。 - 缓存键包含方法、有效参数和授权上下文。
-
private缓存不得跨 Access Token 或用户共享。 - Tool annotations 和
serverInfo均按不可信输入处理。 - 按 Authorization Server issuer 存储 OAuth Client 凭证。
10.3 双时代兼容策略
官方允许实现同时支持 Modern 与 Legacy:
- stdio:先用
server/discover探测;遇到非 Modern 已知错误时回退到 Legacyinitialize。 - Streamable HTTP:先尝试 Modern 请求,检查
400 Bad Request的 JSON-RPC Body 再决定是否回退。
推荐把协议适配封装在 Transport/Protocol Adapter,而不是让 Tool 业务处理器到处判断版本:
十一、设计 MCP 2.0 服务的最佳实践
11.1 Tool 要小而明确
Tool 名称应稳定、可区分,Schema 要限制输入边界。破坏性动作与只读查询分开,不要把“查询、修改、发布”塞进一个巨型工具。
11.2 不要假装无状态
把状态藏进进程全局 Map,再要求负载均衡器粘住连接,只是把 Legacy Session 换了名字。需要状态时应明确选择:
- 短多轮交互:签名或加密的
requestState - 长任务:Tasks
taskId - 分页:cursor
- 业务实体:显式资源 ID / workflow ID
11.3 缓存要考虑授权
如果 tools/list 会因 Scope、租户或用户不同而变化,必须返回 cacheScope: "private",缓存键还要包含授权上下文。错误地标记为 public 可能向另一个用户暴露工具或资源元数据。
11.4 用户同意不能只靠描述
Tool 描述由 Server 提供,Host 不应无条件相信。对于转账、删除、发送消息、部署和权限修改:
- 展示将要调用的 Server、Tool 和关键参数。
- 明确区分只读与写入。
- 允许用户拒绝和修改输入。
- 返回后展示执行结果和失败原因。
11.5 为重试设计幂等性
Modern SSE 断流后 Client 会用新 ID 重发请求。Server 应为可能产生副作用的工具提供业务幂等键、去重机制或查询已完成结果的 handle,避免“网络断了但操作已经成功”导致重复付款、重复发布或重复创建。
十二、常见问题
MCP 2.0 是否与旧版本二进制兼容?
不是。初始化、Session、服务器反向请求、订阅和 SSE 恢复均发生破坏性变化。但 Server 和 Client 可以实现 Dual-era 适配,同时支持 Legacy 与 Modern。
JSON-RPC 还是 2.0,为什么叫 MCP 2.0?
JSON-RPC 2.0 是底层消息格式,与 MCP 协议时代不是一回事。本文“MCP 2.0”只是对 Modern 2026-07-28 大版本式变化的方便称呼。
无状态是否意味着不能做多轮 Agent 工作流?
不意味着。短多轮交互使用 MRTR,长流程使用 Tasks,业务状态使用显式 handle。多轮能力保留了,只是不再隐式依附于连接。
stdio 也必须每次携带 _meta 吗?
是。Modern 协议的每个请求都必须带版本和 Client capabilities。HTTP 额外要求版本、方法和名称 Header;stdio 没有这些 HTTP Header。
是否应该在新项目中使用 Roots、Sampling 和 Logging?
不建议。它们目前仍可用但已 Deprecated。新 Server 应通过 Tool 参数/Resource URI 表达目录,通过 Provider API 完成模型调用,通过 stderr 或 OpenTelemetry 完成日志与观测。
现在应该立即升级吗?
如果你维护 SDK、网关、Inspector、远程 MCP 平台或需要大规模无状态部署,应尽快完成架构评估。普通 Server 作者首先应确认目标 Host 和官方 SDK 是否已经完整支持 2026-07-28,再采用 Dual-era 或分阶段升级。
十三、总结
MCP 2026-07-28 的真正价值不在于增加了多少新 RPC,而在于删除了一批会让协议依赖连接状态的机制:
- Session 变成显式状态句柄。
- 初始化协商变成每请求元数据和服务器发现。
- 服务器反向请求变成 MRTR 返回与重试。
- 混杂的长连接事件变成专用订阅流。
- 长任务变成可选、可恢复的 Tasks 扩展。
- 缓存、Header、Trace 和授权规则进入生产级治理。
它让 MCP 从适合单机桌面集成的插件协议,向可被云网关路由、可水平扩容、可观测、可缓存、可安全扩展的 Agent 基础设施迈进了一大步。
但也要记住:无状态不会自动带来安全和可靠性。 实现者仍需正确处理幂等、用户授权、缓存隔离、requestState 完整性、OAuth Issuer 绑定和工具输入验证。
如果你只记住一条迁移原则,可以记住这句:
不要把连接当作上下文。让每个请求说明自己是谁、会什么、要做什么;需要延续的状态,使用显式且可验证的句柄。