Mingyu's Library主页
协议升级 · AGENT 基建PROTOCOL UPGRADE · AGENT INFRA

MCP 无状态新规范
2026-07-28:自远程化以来最大的一次重构

MCP Goes Stateless:
the 2026-07-28 spec, its biggest revision yet

握手没了,会话 ID 没了,MCP 从「有状态双向协议」变成「请求/响应无状态协议」。这份文档讲清:为什么要改、改了什么、怎么迁移、哪里有坑。

The handshake is gone, the session ID is gone: MCP has turned from a stateful bidirectional protocol into a stateless request/response protocol. This document covers why it changed, what changed, how to migrate, and where the traps are.

调研时间:2026-08-14 · 基于 MCP 官方博客、官方规范与社区迁移指南 · 术语保留英文原名

Researched: 2026-08-14 · Based on the official MCP blog, the specification, and community migration guides

130 秒速览

1In 30 Seconds

MCP(Model Context Protocol,让 AI 应用接入外部工具和数据的开放协议)在 2026 年 7 月 28 日发布了新版规范。官方数据:Tier 1 SDK 每月下载量已接近 5 亿次,TypeScript 与 Python SDK 累计均破 10 亿次——这已经是 Agent 生态的水电煤。这次升级做了一件核心的事:把协议核心改成无状态(stateless),即服务器不再需要记住「这个客户端之前和我说过什么」,每个请求自带全部上下文。

MCP (Model Context Protocol — the open protocol that connects AI applications to external tools and data) shipped a new specification on July 28, 2026. Official numbers: Tier 1 SDKs see close to half a billion downloads per month, with both the TypeScript and Python SDKs past 1 billion total — this is the plumbing of the agent ecosystem. The release does one central thing: it makes the protocol core stateless — servers no longer need to remember "what this client said to me before"; every request carries its full context.

一句话版本The one-liner 以前的 MCP 服务器像「有会员卡的理发店」:先办卡(initialize 握手)、认卡(session ID)、只能找同一个理发师。新版像「快餐店点单」:每张订单写清全部要求,哪个柜台空闲哪个接单——于是可以随便加柜台(水平扩容)。 Old MCP servers were like a hair salon with membership cards: register first (the initialize handshake), present your card (session ID), and always see the same stylist. The new MCP is fast-food ordering: every ticket states the full order, and any free counter can take it — so you can add counters at will (horizontal scaling).

八个要点:①核心无状态,initialize 握手与 Mcp-Session-Id 移除;②协议版本与客户端能力随每个请求放进 _meta,可选的 server/discover 按需查询服务器能力;③跨调用状态改用「显式 handle」(工具返回一个 ID,后续调用传回来);④新增 HTTP 头 Mcp-Method / Mcp-Name,网关不解析 JSON 就能路由;⑤交互式调用改用 MRTR(多轮请求);⑥扩展框架转正,Tasks、MCP Apps 成为正式扩展;⑦Roots、Sampling、协议 Logging 弃用(至少保留 12 个月);⑧授权加固,DCR 弃用、转向 CIMD。

Eight takeaways: ① stateless core — the initialize handshake and Mcp-Session-Id are removed; ② protocol version and client capabilities travel in _meta on every request, with an optional server/discover call for up-front capability discovery; ③ cross-call state moves to explicit handles (a tool returns an ID; later calls pass it back); ④ new HTTP headers Mcp-Method / Mcp-Name let gateways route without parsing JSON; ⑤ interactive calls use MRTR (Multi Round-Trip Requests); ⑥ a formal extensions framework, with Tasks and MCP Apps as official extensions; ⑦ Roots, Sampling, and protocol Logging are deprecated (kept for at least 12 months); ⑧ authorization hardening — DCR deprecated in favor of CIMD.

2背景与动机:远程 MCP 的「会话税」

2Why: Remote MCP and the "Session Tax"

MCP 诞生于 2024 年底,最初的典型场景是桌面应用在本机拉起一个子进程,通过标准输入输出(stdio)通信。在这个世界里,「先握手、再基于连接维持一个会话」几乎没有成本——反正就一条连接、一个进程。

MCP was born in late 2024. Its original setting was a desktop app launching a local subprocess and talking over standard input/output (stdio). In that world, "shake hands first, then keep a per-connection session" cost almost nothing — there was one connection and one process anyway.

远程 MCP 改变了经济账。服务器发一个 Mcp-Session-Id,客户端每次请求都带上它;只要服务器往会话里存了任何东西,后续请求就必须落到同一台实例,或者所有实例共享一个会话存储。于是水平扩容意味着:粘性路由(sticky routing)、共享状态、以及一个「懂 MCP」的网关。社区迁移指南把这叫作「为了维持协议会话而交的分布式系统税」。更麻烦的是,各家实现对 session 的语义理解并不一致——有的每个聊天开一个会话,有的一个用户共享一个,有的进程崩溃就直接丢弃——把应用逻辑建在这上面本来就脆弱。

Remote MCP changed the economics. The server would issue an Mcp-Session-Id and the client returned it with every request; the moment a server stored anything against that session, follow-up requests had to reach the same instance — or every instance had to share a session store. Horizontal scaling then meant sticky routing, shared state, and a gateway that "understood MCP." Community migration guides call this the distributed-systems tax paid just to keep protocol sessions alive. Worse, implementations never agreed on session semantics — one client opened a session per chat, another shared one per user, a third dropped it on any crash — so application logic built on sessions was fragile from the start.

旧:有状态(2025-11-25 及之前) 新:无状态(2026-07-28 起) 客户端(带 Session-Id) 粘性负载均衡器 实例 A ★ 实例 B 实例 C 会话必须一直落在实例 A(或共享存储) 客户端(请求自带上下文) 普通轮询负载均衡器 实例 A 实例 B 实例 C 任何请求可落任何实例,无需共享会话

旧架构的「会话税」 vs 新架构的普通负载均衡(依据 MCP 官方博客绘制)

Old: stateful (≤ 2025-11-25) New: stateless (2026-07-28+) Client (Session-Id) Sticky load balancer Node A ★ Node B Node C Session pinned to Node A (or shared store) Client (self-contained) Plain round-robin LB Node A Node B Node C Any request can land on any instance

The "session tax" of the old architecture vs plain load balancing in the new one (drawn from the official MCP blog)

官方对新方向的概括是「按需付费的复杂度」(pay-as-you-go complexity):核心请求模型保持精简,状态、UI、长任务这些能力只在应用需要时通过扩展加回来。社区已经开始把这次升级俗称为「MCP v2」——官方按日期给规范定版,并没有 v2 这个名字,但这个说法足见变化之大。

The official framing for the new direction is "pay-as-you-go complexity": keep the core request model lean, and add state, UI, or long-running work back through extensions only where an application needs them. Developers have taken to calling this release "MCP v2" — officially the spec is versioned by date and there is no v2, but the nickname says a lot about the size of the change.

3无状态核心:握手没了,状态去哪了

3The Stateless Core: No Handshake — So Where Does State Go?

旧协议里,一切从 initialize / initialized 握手开始:客户端先自报家门,服务器回协议版本和能力清单,之后的请求都挂在这条「关系」上。新协议里(依据 SEP-2575 / SEP-2567),每个请求都是自包含的:协议版本、客户端身份、客户端能力全部放进请求的 _meta 字段随行;想提前了解服务器能力,调一个新增的 server/discover RPC 即可——但它不是必须的。

In the legacy protocol everything started with the initialize / initialized handshake: the client introduced itself, the server replied with protocol version and capabilities, and all later requests hung off that relationship. In the modern protocol (per SEP-2575 / SEP-2567), every request is self-contained: protocol version, client identity, and client capabilities travel in the request's _meta field. A client that wants capabilities up front can call the new server/discover RPC — but it is optional.

POST /mcp HTTP/1.1
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":{"name":"my-app","version":"1.0"}}}}

示例来自 MCP 官方博客(2026-07-28);实际开发请使用 SDK 生成的类型,不要手写这个结构。

Example from the official MCP blog (2026-07-28); in real code, use your SDK's generated types rather than hand-writing this shape.

应用状态改用「显式 handle」

Application state moves to explicit handles

去掉协议会话不等于你的应用不能有状态。官方推荐的替代模式朴素到有点无聊:工具返回一个 ID,后续调用把它当参数传回来。比如购物车工具第一次调用返回 basket_id: "bsk_a1b2c3",之后的 add_item 显式带上这个 ID。官方博客说,实践中这比藏在传输层里的会话状态效果更好——模型「看得见」这个 handle,能自己在多个工具间穿针引线。

Removing protocol sessions doesn't mean your application can't have state. The officially recommended replacement is deliberately boring: a tool returns an ID, and later calls pass it back as an argument. A cart tool's first call returns basket_id: "bsk_a1b2c3"; subsequent add_item calls carry that ID explicitly. The official blog notes this works better in practice than session state hidden in the transport — the model can see the handle and thread it between tools.

显式状态还更有表达力:设想一个编排 Agent 带三个调研子 Agent,它们该共用同一个购物车、但各自需要独立的浏览器上下文。会话模式下你只能「全共享」或「全隔离」二选一;handle 模式下,编排者可以共享一个 basket_id、同时发三个不同的 browser_id。handle 还能跨对话续用、交给子 Agent、同时保持两份文档打开——这些都是隐藏会话做不到的。

Explicit state is also more expressive. Picture an orchestrator with three research subagents: they should share one shopping cart but each needs an isolated browser context. Under sessions you had to pick between sharing everything and isolating everything; with handles, the orchestrator shares one basket_id while issuing three different browser_id values. Handles can also survive into later conversations, be handed to subagents, or keep two documents active at once — none of which hidden session state allowed.

安全提醒:handle 是能力凭证,不是「随便一个字符串」 Security note: a handle is a capability, not "just a string" handle 会出现在对话记录、日志、prompt 和子 Agent 上下文里。社区迁移指南(MCPJam,2026-07-31)给出的底线:handle 要不可猜测、绑定到认证主体与租户、每次调用都重新鉴权、有过期与可恢复的报错;无认证场景下 handle 事实上是 bearer token,至少 128 位安全熵。永远不要把「拿着 handle」当成「有权使用它」。 Handles show up in transcripts, logs, prompts, and subagent context. The community migration guide (MCPJam, 2026-07-31) sets the floor: make handles unguessable, bind them to the authenticated principal and tenant, re-authorize on every call, give them expiry and recoverable errors; where an unauthenticated handle effectively acts as a bearer token, use at least 128 bits of secure entropy. Never treat possession of a handle as proof of authorization.

原来挂在 initialize 上的逻辑(预热缓存、建限流桶、加载租户配置)也要搬家:进程级的放进程启动或首次使用时懒加载;用户级的从认证后的请求上下文来;持久状态给显式 ID。另一个别忽视的点:无状态化之后,幂等性(idempotency,重复执行不产生重复效果)必须自己做——写操作提交了但 HTTP 响应丢了、客户端重试,没有去重就会发布两次。对不可逆的工具,官方社区建议接受 idempotency_key 参数并存储结果去重。

Logic that used to hang off initialize (cache warming, rate-limit buckets, tenant config) needs a new home: process-wide things move to process startup or lazy first use; user context comes from authenticated request state; durable state gets explicit IDs. And don't skip this one: with statelessness, idempotency (repeat execution must not repeat the effect) is your job — if a write commits but the HTTP response is lost and the client retries, you publish twice without deduplication. For irreversible tools, the community guidance is to accept an idempotency_key argument and return the stored result on repeats.

4MRTR:一次工具调用,拆成多个请求

4MRTR: One Tool Call, Multiple Requests

老问题:工具执行到一半需要用户输入(确认、补一个参数)怎么办?旧协议靠一条常开的双向流,让服务器反向发请求(elicitation / sampling)。无状态协议里这条流没了,取而代之的是 MRTR(Multi Round-Trip Requests,多轮往返请求,SEP-2322):服务器返回 resultType: "input_required" 和它需要的问题清单,客户端拿到用户答案后,带着 inputResponses 重发原调用。一次逻辑操作,跨了两个(或多个)独立的 HTTP 请求。

The old question: what if a tool needs user input mid-call (a confirmation, a missing parameter)? Legacy MCP relied on a held-open bidirectional stream so the server could send requests back (elicitation / sampling). That stream is gone. In its place: MRTR (Multi Round-Trip Requests, SEP-2322) — the server returns resultType: "input_required" plus the questions it needs answered, and the client retries the original call with the answers attached in inputResponses. One logical operation now spans two (or more) independent HTTP requests.

客户端 服务器 ① tools/call publish_post ② resultType:"input_required" +「确认发布吗?」 用户思考 5 秒… ③ 重发原调用 + inputResponses(答案) ④ resultType:"complete" ✓(可落在另一台实例)

MRTR:服务器「要输入」不再靠反向长连接,而是让客户端带答案重试(依据 SEP-2322 绘制)

Client Server ① tools/call publish_post ② resultType:"input_required" + "Confirm publish?" user thinks for 5s… ③ retry original call + inputResponses ④ resultType:"complete" ✓ (may land on another instance)

MRTR: "the server needs input" no longer requires a reverse long-lived connection — the client retries with answers (drawn from SEP-2322)

真实落地的例子:Supabase 在官方博客的合作方评价中说,他们的 MCP 服务器本来就是无状态部署,以前想做 elicitation(执行前和用户确认,比如「新建项目要花这些钱,确认吗」「这个查询会删数据,确认吗」)一直做不了,MRTR 直接解锁了这件事。

A concrete adopter: in the release's partner quotes, Supabase notes its MCP server always ran stateless, which made elicitation (confirming with the user before acting — "this new project will cost X, proceed?", "this query deletes data, confirm?") impossible before; MRTR unlocks exactly that.

可观测性的隐形坑The hidden observability trap 一次逻辑操作现在对应多个 JSON-RPC ID。如果监控按「一个 ID = 一次工具调用」统计,MRTR 会让它把 1 次操作记成 2 次、把 6 秒的端到端耗时记成 1 秒、还丢掉中间人等待的 5 秒。正确做法:在客户端/宿主侧铸造「逻辑操作 ID」贯穿重试,并分开记录服务器处理时长、等待外部输入时长、端到端时长。(来源:MCPJam 迁移指南) One logical operation now maps to multiple JSON-RPC IDs. Monitoring that assumes "one ID = one tool call" will count 1 operation as 2, report a 6-second end-to-end operation as 1 second of work, and lose the 5 seconds of human decision time. The fix: mint a logical-operation ID in the client/host telemetry, carry it across retries, and track server-processing, external-wait, and end-to-end durations separately. (Source: MCPJam migration guide)

5基础设施红利:路由、缓存、追踪

5Infrastructure Wins: Routing, Caching, Tracing

这次升级里最讨运维喜欢的三件事,都指向同一个方向:让 MCP 流量变成「普通的 HTTP 流量」,现有的网关、CDN、WAF、追踪系统直接可用。

The three changes operators like most all point the same way: make MCP traffic behave like ordinary HTTP traffic, so existing gateways, CDNs, WAFs, and tracing systems just work.

头路由(SEP-2243)
Streamable HTTP 请求必须带 Mcp-Method(镜像 JSON-RPC 方法名),tools/call / resources/read / prompts/get 还要带 Mcp-Name。网关不解析 JSON 请求体就能按工具路由、按工具限流、按操作记指标。代价是一条新的校验边界:头和体不一致必须拒绝(HTTP 400 + HeaderMismatch 错误码 -32020),否则网关按头授权、后端按体执行,就是一个协议混淆漏洞。
可缓存的列表(SEP-2549)
tools/list 等响应带上 ttlMs(可缓存多久)和 cacheScope(public / private)。工具目录不再随连接变化,编排器给多个子 Agent 复用同一份目录,省流量也省 token。服务器要按确定性顺序返回工具;用户相关的目录绝不能标 public。
W3C Trace Context
_meta 里规范化传递 traceparent / tracestate / baggage,一次 Agent 动作可以进同一条 OpenTelemetry 兼容的分布式追踪。注意 baggage 不是杂物袋:限制大小、白名单键名、不放凭证。
Header routing (SEP-2243)
Streamable HTTP requests must carry Mcp-Method (mirroring the JSON-RPC method); tools/call / resources/read / prompts/get also carry Mcp-Name. Gateways can route per tool, rate-limit per tool, and record operation metrics without parsing JSON bodies. The price is a new validation boundary: header/body disagreement must be rejected (HTTP 400 + HeaderMismatch, -32020) — a gateway that authorizes on the header while the backend executes the body is a protocol-confusion bypass.
Cacheable list results (SEP-2549)
Responses to tools/list and friends carry ttlMs (freshness) and cacheScope (public / private). Tool catalogs no longer vary per connection, so an orchestrator can reuse one catalog across subagents — saving both wire traffic and tokens. Servers should return tools in deterministic order; never mark a user-specific catalog public.
W3C Trace Context
traceparent / tracestate / baggage now propagate through _meta in a standardized way, so one agent action can join a single OpenTelemetry-compatible trace. Baggage is not a junk drawer: bound its size, allowlist keys, keep credentials out.
生态信号Ecosystem signal 发布当天的站台名单说明了这次升级的分量:AWS(Bedrock AgentCore 已支持并贡献了 Tasks 扩展)、Cloudflare(Agents SDK day-zero 支持)、Google Cloud、Microsoft Foundry、Netlify、Figma、Supabase、PostHog、honeycomb.io(称其月度交互查询近 20% 已来自 Agent)。工具侧 FastMCP 4.0 宣布一等支持;框架 mcp-use 称新 SDK v2 让其包体积缩小约 83%、快 25%(单方数据,未独立核实)。 The day-one endorsement list shows the release's weight: AWS (supported in Bedrock AgentCore; contributed the Tasks extension), Cloudflare (day-zero Agents SDK support), Google Cloud, Microsoft Foundry, Netlify, Figma, Supabase, PostHog, and honeycomb.io (which says nearly 20% of its monthly interactive queries now come from agents). On the tooling side, FastMCP 4.0 announced first-class support; the mcp-use framework reports the new SDK v2 cut its package size by ~83% and made it 25% faster (vendor's own numbers, not independently verified).

6扩展框架、授权加固与弃用清单

6Extensions, Auth Hardening, Deprecations

扩展成为一等公民

Extensions become first-class

MCP 正式确立扩展框架:扩展有命名空间标识、通过能力协商启用、独立演进版本。两个核心官方扩展:MCP Apps(2026 年 1 月 26 日成为首个官方扩展,本次并入正式框架)让服务器提供交互式 HTML 界面,宿主在沙箱 iframe 里渲染;Tasks(io.modelcontextprotocol/tasks)承载长任务——一次 tools/call 可以返回一个 task handle,客户端用 tasks/get 轮询、tasks/update 更新、tasks/cancel 协作取消;tasks/list 已移除。曾用 2025-11-25 实验版 Tasks 的注意:这是「真正的移植」,不是改个 import。长任务还要自己做配额、过期清理、幂等创建——否则「创建便宜、执行昂贵」的任务就是一个现成的 DoS 原语。

MCP now has a formal extensions framework: namespaced identifiers, capability-negotiated activation, independent versioning. Two central official extensions: MCP Apps (the first official extension since January 26, 2026, now folded into the formal framework) lets a server ship an interactive HTML UI that the host renders in a sandboxed iframe; Tasks (io.modelcontextprotocol/tasks) carries long-running work — a tools/call can return a task handle which the client drives via tasks/get (polling), tasks/update, and cooperative tasks/cancel; tasks/list is removed. If you built on the experimental 2025-11-25 Tasks: this is a real port, not an import rename. Long-running work also needs quotas, expiry/cleanup, and idempotent creation — otherwise "cheap to request, expensive to run" tasks are a ready-made DoS primitive.

授权:把 OAuth 的坑填掉几个

Authorization: closing OAuth gaps

授权是实现者花时间最多的地方,这次的加固包括:客户端必须校验授权响应的 iss 参数(RFC 9207,堵住授权服务器混淆漏洞,SEP-2468);客户端凭证绑定签发它的 issuer,不得跨授权服务器复用(SEP-2352);DCR(Dynamic Client Registration,动态客户端注册)正式弃用,转向 CIMD(Client ID Metadata Documents:client ID 就是一个指向元数据文档的 URL,授权服务器自己去读,免去逐个注册)——DCR 向后兼容仍可用,但未来版本会移除。

Authorization is where implementers spend the most integration time. This round hardens it: clients must validate the iss parameter in authorization responses (RFC 9207, closing an authorization-server mix-up hole, SEP-2468); client credentials are bound to the issuer that minted them and can't be reused across authorization servers (SEP-2352); and DCR (Dynamic Client Registration) is formally deprecated in favor of CIMD (Client ID Metadata Documents — the client ID is a URL pointing to a metadata document the authorization server reads itself, avoiding per-server registration). DCR keeps working for backward compatibility but will be removed in a future version.

弃用清单(至少保留 12 个月)

The deprecation list (kept ≥ 12 months)

弃用项原来的角色推荐去向
Roots客户端提供会话级操作边界(如工作目录)工具参数、资源 URI 或服务器配置显式传递;客户端给的路径不等于授权,服务器仍要校验
Sampling服务器「借用」客户端的模型做生成服务器直连模型供应商,或改为显式 MRTR 输入流程——这是最贵的一项弃用:凭证、推理成本、数据合规都转到服务器运营方
协议 Logging服务器向客户端流式发结构化日志stdio 用 stderr;生产环境用 OpenTelemetry 与常规日志系统
HTTP+SSE 旧传输早期远程传输Streamable HTTP(此项走单独的较短下线窗口)
DeprecatedPrevious roleRecommended direction
RootsClient supplies session-scoped operating boundaries (e.g. a working directory)Pass scope explicitly via tool arguments, resource URIs, or server config; a client-supplied path is not authorization — validate server-side
SamplingServer "borrows" the client's model for generationDirect provider integration, or explicit MRTR input flows — the most expensive deprecation: credentials, inference cost, and data compliance shift to the server operator
Protocol LoggingServer streams structured logs to the clientstderr for stdio; OpenTelemetry plus normal logging in production
Legacy HTTP+SSE transportThe early remote transportStreamable HTTP (this one has its own, shorter removal window)

另外几处线上变化容易踩空:资源不存在的错误码从自定义 -32002 改为标准 -32602;协议错误分配了 -32020~-32099 区间(-32020 HeaderMismatch、-32021 MissingRequiredClientCapability、-32022 UnsupportedProtocolVersion);工具 schema 升级到完整 JSON Schema 2020-12(支持 oneOf / $ref 等);独立的 HTTP GET 通知流被 subscriptions/listen 订阅流取代,SSE 断流不可续传(Last-Event-ID 不再提供重投递)——这又回到「写操作要自己做幂等」。

A few wire-level changes are easy to trip on: the resource-not-found error moves from custom -32002 to standard -32602; the -32020…-32099 range is now reserved for MCP errors (-32020 HeaderMismatch, -32021 MissingRequiredClientCapability, -32022 UnsupportedProtocolVersion); tool schemas move to full JSON Schema 2020-12 (oneOf, $ref, etc.); and the standalone HTTP GET notification stream is replaced by a subscriptions/listen subscription stream, with SSE resumability gone (Last-Event-ID no longer redelivers) — which again means mutations need application-level idempotency.

7迁移指南与常见坑

7Migration Guide & Common Pitfalls

先说结论:没有任何东西在 7 月 28 日当天坏掉。旧客户端和旧服务器可以继续用旧协议对话。断裂只发生在「跨代」:只会新协议的一方遇到只会旧协议的一方。官方版本文档定义三类实现:Legacy(用 initialize 握手,2025-11-25 及之前)、Modern(用逐请求元数据,2026-07-28 起)、Dual-era(两代都支持)。要兼容两代,客户端得主动探测对端年代:stdio 上先探 server/discover,超时或不认识就回退 legacy initialize;HTTP 上看 400 响应体是不是「可识别的 modern 错误」再决定回退——注意 401/403/429 不能当作「对面是旧服务器」的证据。

First, the punchline: nothing broke on July 28. Legacy clients and servers keep talking legacy MCP to each other. The break is cross-era: a modern-only side meeting a legacy-only side. The official versioning docs define three categories: Legacy (initialize handshake, 2025-11-25 and earlier), Modern (per-request metadata, 2026-07-28+), and Dual-era (supports both). To bridge eras, a client must actively detect the other side: over stdio, probe server/discover and fall back to legacy initialize on timeout or unrecognized errors; over HTTP, inspect whether a 400 body is a recognized modern error before falling back — and never treat 401/403/429 as evidence of a legacy server.

  1. 搜代码找依赖。rg 'Mcp-Session-Id|sessionIdGenerator|initialize|initialized' .——逐条审查:哪些是协议上下文(协议现在自带),哪些该进请求中间件,哪些要落持久存储。
  2. 把跨调用状态改成显式 handle。绑定主体与租户、每次调用重新鉴权、加过期与可恢复错误。
  3. 给不可逆工具加幂等键。并测试「提交后超时重试」的行为;MRTR 续传与 Tasks 更新也要做重放保护。
  4. 升级 SDK 并显式启用新协议。TypeScript / Python / Go / C# 四个 Tier 1 SDK 已支持,Rust beta。注意:新大版本 ≠ 默认走新协议——TypeScript v2 里 modern 行为是 opt-in 的,默认 Client.connect() 仍可能走旧握手。迁移期钉死 SDK 版本。
  5. 审计整条 HTTP 链路。CDN、WAF、网关、反向代理、服务网格逐跳确认 Mcp-* 头存活;头名不区分大小写但值区分,会「规范化大小写」的代理能悄悄弄坏它。
  6. 四层测试。单测应用行为 → 官方 conformance 测试套件 → 用 mcp-spec-check 探生产端点 → 拿真实客户端和模型跑评测(协议对了不代表模型会选对工具)。
  1. Search your code for dependencies. rg 'Mcp-Session-Id|sessionIdGenerator|initialize|initialized' . — review every hit: some is protocol context (now carried by the protocol), some belongs in request middleware, some must move to durable storage.
  2. Convert cross-call state to explicit handles. Bind to principal and tenant, re-authorize per call, add expiry and recoverable errors.
  3. Add idempotency keys to irreversible tools. Test timeout-after-commit retries; apply replay protection to MRTR continuations and Task updates too.
  4. Upgrade the SDK and opt in explicitly. The TypeScript / Python / Go / C# Tier 1 SDKs support 2026-07-28 (Rust in beta). Careful: a new major version ≠ modern-by-default — in TypeScript v2, modern behavior is opt-in and a default Client.connect() can still perform the legacy handshake. Pin exact SDK versions during migration.
  5. Audit the whole HTTP path. CDN, WAF, gateway, reverse proxy, service mesh — confirm Mcp-* headers survive every hop; header names are case-insensitive but their values are case-sensitive, so case-normalizing proxies can silently corrupt them.
  6. Test at four levels. Unit-test app behavior → the official conformance suite → probe deployed endpoints with mcp-spec-check → run real clients and models (protocol correctness doesn't mean the model picks the right tool).
你是谁紧迫度与动作
本地 stdio 服务器作者低——从容升级 SDK 即可,很多场景只是版本更新
远程 HTTP 服务器作者高——立刻审计会话、状态、头、鉴权与部署,这是真正的架构迁移
客户端 / 宿主作者高——优先做年代探测、discover、MRTR、鉴权与缓存
网关 / 平台中高——测头校验、路由、追踪与混合版本共存
用了实验版 Tasks / SamplingTasks 当成真移植做;Sampling 要当产品与合规决策来规划
You build…Urgency & action
A local stdio serverLow — upgrade deliberately; often just an SDK bump
A remote HTTP serverHigh — audit sessions, state, headers, auth, deployment now; this is a real architectural migration
A client / hostHigh — prioritize era detection, discovery, MRTR, auth, caching
A gateway / platformMedium-high — test header validation, routing, tracing, mixed versions
Experimental Tasks / Sampling usersTreat Tasks as a real port; treat Sampling as a product & compliance decision
高频坑位速查Quick pitfall reference ① SDK 升了但没显式 opt-in,以为自己已经是 modern;② 观测系统按 JSON-RPC ID 计数,MRTR 后指标翻倍、时延失真;③ 网关按头授权、后端按体执行(必须校验头体一致);④ 把 _meta 里客户端自报的身份当认证结果(它是不可信输入);⑤ 硬编码 -32002 的断言没改;⑥ 在应用代码里读 resultType(TS v2 SDK 会在返回前消费掉它,不可移植);⑦ 指望 SSE 断线续传(已移除)。 ① Upgraded the SDK but never opted in — you think you're modern, you're not; ② observability counts JSON-RPC IDs, so MRTR doubles metrics and distorts latency; ③ gateway authorizes on headers while the backend executes the body (must validate header/body agreement); ④ trusting client-self-reported identity in _meta as authenticated context (it's untrusted input); ⑤ leftover hard-coded -32002 assertions; ⑥ reading resultType in app code (the TS v2 SDK consumes it before returning — not portable); ⑦ expecting SSE resumability (removed).

8争议:MCP 现在不就是 HTTP 吗?

8The Debate: Isn't MCP Just HTTP Now?

这是社区(如 r/mcp 的讨论)对这次发布最尖锐、也最合理的质疑:既然远程 MCP 现在长得像普通 HTTP 服务,为什么不直接暴露普通 API?社区迁移指南给出的诚实回答是:有时候确实应该用普通 API——如果只是一个应用调一个已知服务、不需要动态的 Agent 集成。MCP 的价值在 HTTP 之上:面向 Agent 的工具发现、统一的 tool/resource/prompt schema、宿主-客户端-服务器的通用角色、授权发现、能力与扩展协商、MCP Apps、Tasks,以及一份宿主可以统一套上审批与策略控制的集成契约。把传输层变「无聊」正是目的:协调工作在协议层解决一次,而不是每个集成重新发明。

This is the sharpest — and fairest — community pushback (see the r/mcp discussion): if remote MCP now looks like a conventional HTTP service, why not just expose a normal API? The honest answer from the migration guides: sometimes you should — if one application calls one known service and doesn't need dynamic agent integration. MCP earns its keep above HTTP: agent-oriented tool discovery, uniform tool/resource/prompt schemas, common host/client/server roles, authorization discovery, capability and extension negotiation, MCP Apps, Tasks, and a single integration contract that hosts can wrap in approval and policy controls. Making the transport boring is the point: solve the coordination problem once at the protocol level instead of reinventing it per integration.

另一处真实分歧是 Sampling 弃用:支持者认为服务器直连模型供应商能自主控制模型选择与评测;反对者指出这把凭证、推理账单、数据处理责任和企业模型政策全压到了服务器运营方头上。官方立场是把它当「产品、安全与计费决策」而非机械迁移——若只是需要用户输入,MRTR 往往是更好的替代。

The other live disagreement is the Sampling deprecation: proponents say direct provider integration gives server authors control over model choice and evals; critics note it shifts credentials, inference bills, data-handling duties, and enterprise model policy onto server operators. The official stance: treat it as a product, security, and billing decision, not a mechanical migration — and where you merely need user input, MRTR is often the better replacement.

官方视角In their words 「这是自远程 MCP 发布一年多以来最重要的一个版本……吸收了过去 18 个月的全部经验,为 MCP 的未来提供了坚实地基。」——David Soria Parra,MCP 联合发明人(官方发布博客) "The new release is MCP's most important since remote MCP first launched over a year ago. It … takes all the lessons learned over the last 18 months to provide a robust foundation for MCP's future." — David Soria Parra, MCP co-inventor (official release blog)

9学习资源

9Resources