第 1 节SECTION 130 秒速览The 30-second version
如果你只有半分钟:MCP 以前要求客户端和服务器先握手、拿一个会话 ID、然后在这条会话上来回对话。这意味着后续每个请求都必须回到「记得这个会话」的那台服务器上。2026-07-28 版规范把这套全删了——握手没了,会话 ID 没了,每个请求自带全部必要信息,因此可以落到任意一台健康的实例上。
If you only have thirty seconds: MCP used to require a handshake, a session ID, and a conversation carried on that session. That meant every follow-up request had to land on the one server that remembered the session. The 2026-07-28 revision removed all of it — no handshake, no session ID, every request carries what it needs, so it can land on any healthy instance.
数据来源:MCP 官方博客、SEP-2322(检索于 2026-09-14)
Sources: MCP official blog, SEP-2322 (retrieved 2026-09-14)
第 2 节SECTION 2它在解决什么问题What problem it solves
先说痛点:MCP 最初是照着「本地」设计的
Start with the pain: MCP was designed for "local" first
MCP(Model Context Protocol,模型上下文协议)最初要解决的问题很朴素:让一个 AI 助手能调用你电脑上的工具——读文件、查数据库、跑命令。在这个场景里,客户端和服务器就在同一台机器上,一对一,进程活着会话就活着。于是协议自然地做成了有状态的:先 initialize 握手协商能力,拿一个 Mcp-Session-Id,之后所有请求都挂在这个会话上。
MCP (the Model Context Protocol) started with a modest problem: let an AI assistant call tools on your own machine — read files, query a database, run commands. In that setting the client and server share a machine, one-to-one, and the session lives as long as the process does. So the protocol was naturally stateful: an initialize handshake to negotiate capabilities, an Mcp-Session-Id, and every later request hanging off that session.
问题出在 MCP 火了之后。人们开始把 MCP 服务部署到云上,让成千上万个 agent 远程调用。这时「有状态」就从设计优点变成了运维负担。
The trouble started once MCP took off. People began deploying MCP servers in the cloud for thousands of agents to call remotely. At that point "stateful" flipped from a design virtue into an operations tax.
有状态的远程服务像银行柜台的叫号:你在 3 号窗口办了一半,资料都摊在 3 号窗口的桌上。你去上个厕所回来,只能回 3 号窗口——别的窗口不知道你办到哪儿了。如果 3 号窗口下班了(实例重启/扩缩容),你得从头再来。
A stateful remote service is like a bank teller window: you're halfway through at window 3, and your paperwork is spread across window 3's desk. Step away and come back, and you must return to window 3 — no other window knows where you left off. If window 3 closes (a pod restarts or scales down), you start over.
无状态则像自助机:你每次把整张表格递进去,哪台机器都能受理。代价是——你每次都得递整张表格。
Stateless is like a self-service kiosk: you hand over the whole form each time, and any kiosk can process it. The cost is that you hand over the whole form each time.
有状态在云上具体贵在哪
Where statefulness actually costs you in the cloud
- 必须做粘性路由:网关要记住「这个会话属于哪台实例」,还得为此拆开请求体看内容(deep packet inspection),网关因此变复杂、变慢。
- 必须有共享会话存储:要么 Redis,要么别的外部存储,又是一个要运维、要保证可用性的组件。
- 扩缩容很难:缩容时把一台实例下掉,挂在上面的所有会话全断。滚动发布同理。
- 必须常驻长连接:服务端如果想问客户端一句(比如要用户确认),得靠一条一直开着的 SSE 流。连接数就是成本,而且它和无服务器(serverless)架构天然冲突。
- Sticky routing is mandatory: the gateway must remember which pod owns a session, often cracking open the request body (deep packet inspection) to find out. The gateway gets more complex and slower.
- A shared session store is mandatory: Redis or something like it — one more component to run and keep available.
- Scaling is painful: draining a pod kills every session pinned to it. Rolling deploys have the same problem.
- Long-lived connections are mandatory: if the server wants to ask the client something (a user confirmation, say), it needs an SSE stream held open. Connection count is cost, and it fights serverless architectures head-on.
一句话概括本次改动的动机:让远程 MCP 服务能像一个普通的 HTTP 微服务那样部署和扩容。官方博客把 2026-07-28 描述为「自协议发布以来最大的一次修订」。
The motivation in one line: make a remote MCP server deployable and scalable like any ordinary HTTP microservice. The official blog calls 2026-07-28 the largest revision since the protocol launched.
来源:MCP 官方博客:2026-07-28 规范、Google Developers Blog
Sources: MCP blog: the 2026-07-28 specification, Google Developers Blog
第 3 节SECTION 3六项核心变化Six core changes
官方说明里提到,无状态不是靠单个改动实现的,而是六个 SEP(Specification Enhancement Proposal,规范增强提案)协同的结果。下面逐条拆开讲——每条都先说「改了什么」,再说「对你意味着什么」。
The official write-up notes that statelessness isn't one change but six SEPs (Specification Enhancement Proposals) working together. Below, one at a time — what changed, then what it means for you.
① 握手和会话 ID 被删掉了
① The handshake and session ID are gone
规范移除了 initialize / initialized 握手,也移除了 Mcp-Session-Id。取而代之:每个请求都自己携带协议版本、客户端信息与 capabilities。
The spec removes the initialize / initialized handshake and removes Mcp-Session-Id. Instead, each request carries its own protocol version, client information, and capabilities.
对你意味着什么:每个请求体大了一点(多带了几十到几百字节的元信息),换来的是「任意实例都能处理」。这是一笔明确的带宽换弹性的交易。
What it means for you: each request body gets slightly bigger (tens to hundreds of bytes of extra metadata) in exchange for "any pod can handle it." It's an explicit bandwidth-for-elasticity trade.
② 两个新 header,让网关不用拆包
② Two new headers, so gateways don't need to open the box
Streamable HTTP 传输现在要求带两个 header:
The Streamable HTTP transport now requires two headers:
- Mcp-Method
- 正在执行的 JSON-RPC 方法名,比如
tools/call、tools/list。 - The JSON-RPC method being executed, e.g.
tools/callortools/list. - Mcp-Name
- 被调用的具体工具、prompt 或 resource 的名字。
- The specific tool, prompt, or resource name being invoked.
对你意味着什么:这是本次改动里最容易立刻吃到红利的一条。你可以在 Nginx / Envoy / API 网关上直接按 header 做路由和限流——比如把重的 tools/call 路到大内存节点、把轻的 tools/list 路到小节点;或者给某个特别贵的工具单独设限流,不用写任何自定义的请求体解析插件。
What it means for you: this is the easiest win in the whole revision. You can route and rate-limit straight off the headers in Nginx / Envoy / your API gateway — send heavy tools/call traffic to big-memory nodes and light tools/list to small ones, or rate-limit one expensive tool specifically, all without a custom body-parsing plugin.
③ 列表结果可以缓存了(SEP-2549)
③ List results are now cacheable (SEP-2549)
tools/list、prompts/list、resources/list 以及 resources/read 的返回值现在可以带上 ttlMs 和 cacheScope 两个字段,语义参照 HTTP 的 Cache-Control;同时规范要求返回结果顺序确定。
tools/list, prompts/list, resources/list, and resources/read results can now carry ttlMs and cacheScope, modeled on HTTP Cache-Control, and the spec requires deterministic ordering of results.
为什么「顺序确定」很重要?因为工具清单通常被放在 LLM 上下文的最前面,是 prompt 缓存前缀的一部分。清单顺序每次抖动一下,缓存前缀就变了,整段缓存全部作废。确定性排序 + ttlMs 一起,直接落到你的 token 账单上。
Why does deterministic ordering matter? The tool list usually sits at the very front of the LLM's context, inside the prompt-cache prefix. If the order jitters between calls, the prefix changes and the whole cached segment is invalidated. Deterministic ordering plus ttlMs shows up directly on your token bill.
④ 服务端主动推送改用 subscriptions/listen
④ Server-initiated messages move to subscriptions/listen
过去服务端要主动给客户端发消息(比如「工具列表变了」),靠的是一条独立的 HTTP GET 长连接流。现在这条独立 GET 流被 subscriptions/listen 取代。
Previously, server-to-client messages (e.g. "the tool list changed") rode a standalone HTTP GET stream. That standalone GET stream is replaced by subscriptions/listen.
⑤ SSE 的可恢复性被移除了 ⚠️
⑤ SSE resumability is removed ⚠️
这是最容易被忽略、后果最实在的一条。SSE 流的可恢复机制(Last-Event-ID 与事件 ID)被移除了。如果响应流断了,那个传输中的请求就丢了,客户端必须用一个新的请求 ID 重新发一次。
This is the easiest one to miss and the one with the most concrete consequences. SSE stream resumability (Last-Event-ID and event IDs) is removed. If a response stream breaks, the in-flight request is lost, and the client must re-issue it as a new request with a new ID.
推论:任何不可逆的工具都必须自己实现幂等。「创建订单」「发起转账」「触发部署」——如果它可能被重发一次,而你的服务端没有幂等键,你就会看到重复执行。规范把这件事从「最佳实践」变成了「不做就会出事」。
The corollary: every irreversible tool must implement its own idempotency. "Create order," "initiate transfer," "trigger deploy" — if it can be re-issued and your server has no idempotency key, you will see duplicate execution. The spec moved this from best practice to non-negotiable.
⑥ 授权:DCR 弃用,改用 CIMD
⑥ Authorization: DCR deprecated in favor of CIMD
动态客户端注册(Dynamic Client Registration, DCR)被正式弃用,改推 CIMD(Client ID Metadata Documents,客户端 ID 元数据文档)。DCR 出于兼容仍然可用。
Dynamic Client Registration (DCR) is formally deprecated in favor of CIMD (Client ID Metadata Documents). DCR still works for backward compatibility.
两者的差别一句话说清:DCR 是「客户端先去授权服务器登记一次,拿一个 client_id」;CIMD 是「客户端的 client_id 本身就是一个它自己托管的 URL,授权服务器需要时去这个 URL 现取元数据」。
The difference in one line: with DCR a client registers with the authorization server once and receives a client_id; with CIMD the client_id is a URL the client hosts itself, and the authorization server resolves it on demand.
对你意味着什么:换授权服务器不再需要重新注册。对同时接多个 MCP 服务、每个服务背后是不同 IdP 的 agent 来说,这消掉了一大堆注册状态。
What it means for you: switching authorization servers no longer requires re-registration. For an agent talking to many MCP servers each behind a different IdP, that erases a pile of registration state.
顺带:什么被弃用了,还能用多久
Also: what's deprecated, and for how long
| 能力 | 状态 | 说明 | Capability | Status | Notes |
|---|---|---|---|---|---|
initialize / Mcp-Session-Id |
已移除 | 协议层不再有会话概念 | Removed | No session concept at the protocol layer | |
| SSE 可恢复(Last-Event-ID) | 已移除 | 断流即丢,需重发 | SSE resumability (Last-Event-ID) | Removed | Break = loss; re-issue required |
| Dynamic Client Registration | 已弃用 | 改用 CIMD,兼容期内继续可用 | Deprecated | Use CIMD; still works during the grace period | |
| Roots / Sampling / Logging | 已弃用 | 官方承诺至少继续可用 12 个月 | Deprecated | Officially guaranteed to keep working for at least 12 months | |
| Tasks | 移出实验性核心 | 进入 io.modelcontextprotocol/tasks 扩展,含轮询式 tasks/get 与新的 tasks/update |
Moved out of the experimental core | Now the io.modelcontextprotocol/tasks extension, with poll-based tasks/get and a new tasks/update |
来源:MCP 官方博客、Appwrite 技术解读、Stacktree 破坏性变更清单
Sources: MCP official blog, Appwrite breakdown, Stacktree breaking-changes list
第 4 节SECTION 4MRTR:没有长连接的「人在回路」MRTR: human-in-the-loop without a stream
前面留了一个问题没答:如果协议没有会话、服务端也不能主动推消息,那「工具执行到一半需要问用户一句」怎么办?——比如一个部署工具要确认「真的要发到生产环境吗?」。这正是 MRTR(Multi Round-Trip Requests,多轮往返请求) 要解决的,它是 SEP-2322,也是本次修订的头号特性。
One question is still open: if the protocol has no session and the server can't push, what happens when a tool needs to ask the user something mid-execution? A deploy tool confirming "really ship to production?", say. That's what MRTR (Multi Round-Trip Requests) is for. It is SEP-2322, and it's the headline feature of this revision.
MRTR 是什么
What MRTR is
一句话:服务端不再「反向发起一个请求去问客户端」,而是先返回一个「还没做完,我需要这些输入」的结果,客户端补齐后重试原来那次工具调用。
In one line: instead of the server initiating a reverse request to ask the client, the server returns an "incomplete — I need these inputs" result, and the client fills them in and retries the original tool call.
具体机制:服务端返回一个 InputRequiredResult(resultType: "input_required"),里面有两样东西——一个 inputRequests 映射(我要问什么),和一个不透明的 requestState 数据块(我做到哪儿了)。客户端拿到答案后,把 requestState 原样带回去重发。
The mechanism: the server returns an InputRequiredResult (resultType: "input_required") containing an inputRequests map (what I need to ask) and an opaque requestState blob (where I got to). Once the client has the answers, it re-sends with requestState attached verbatim.
为什么这很关键:requestState 是可序列化的,所以「我做到哪儿了」这件事被装进了请求里,而不是留在某台服务器的内存里。于是重试可以落到任意一台实例上接着做。这就是 MRTR 成为无状态化关键拼图的原因。
Why this is the keystone: requestState is serializable, so "where I got to" travels inside the request instead of sitting in one server's memory. The retry can therefore be picked up by any instance. That's why MRTR is the piece that makes statelessness work.
安全提醒:requestState 是服务端交给客户端保管、之后原样收回的状态。规范要求它是完整性受保护的(integrity-protected)——也就是说服务端必须能验证它没被篡改(签名或加密)。如果你自己实现服务端,千万不要把未签名的明文状态丢出去:那等于把「我做到哪一步、有什么权限」交给客户端随便改。
Security note: requestState is state the server hands to the client and takes back verbatim. The spec requires it to be integrity-protected — the server must be able to verify it wasn't tampered with (signed or encrypted). If you implement a server, never emit unsigned plaintext state: that hands "where I am and what I'm allowed to do" to the client to edit at will.
换个说法:MRTR 和你熟悉的什么东西像?
Put another way: what does MRTR resemble?
像 HTTP 的 302 重定向 + cookie,但方向反过来:服务端说「我还不能给你结果,你先去拿到这几样东西,然后带着我给你的这张便条再来找我」。那张便条(requestState)对客户端是不可读的黑盒,但服务端一看就知道上次办到哪儿了。
也像 OAuth 的 state 参数——同样是「把服务端的上下文寄存在客户端身上走一圈再拿回来」,同样必须防篡改。如果你实现过 OAuth 回调,MRTR 的心智模型可以直接搬过来。
It resembles an HTTP 302 plus a cookie, but reversed: the server says "I can't give you a result yet — go fetch these things, then come back carrying this note I'm giving you." The note (requestState) is an opaque blob to the client, but the server reads it and knows exactly where it left off.
It also resembles OAuth's state parameter — the same "park the server's context on the client for a round trip and take it back," with the same tamper-proofing requirement. If you've implemented an OAuth callback, that mental model transfers directly.
SDK 支持情况
SDK support
官方博客称本次更新伴随「Tier 1 SDK 的更新」。已确认的具体例子:C# SDK v2.0 已包含 MRTR 支持,并会检查客户端协商的是 2026-07-28 还是旧的有状态版本 2025-11-25,据此走不同路径。
The official blog says the release came with "updated Tier 1 SDKs." One confirmed concrete example: the C# SDK v2.0 ships MRTR support and checks whether the client negotiated 2026-07-28 or the older stateful revision 2025-11-25, branching accordingly.
⚠️ 置信度说明:本次调研只确认到 C# SDK 的具体 MRTR 实现细节。其他语言 SDK(Python / TypeScript / Java / Go 等)的支持进度未能逐一核实,请以各 SDK 仓库的 README 与 release notes 为准。
⚠️ Confidence note: this research only confirmed MRTR implementation details for the C# SDK. Support status for the other language SDKs (Python / TypeScript / Java / Go and so on) was not individually verified — check each SDK's README and release notes.
来源:SEP-2322 规范、PR #2322、C# SDK MRTR 文档、AAIF:requestState 设计
Sources: SEP-2322, PR #2322, C# SDK MRTR docs, AAIF: designing requestState
第 5 节SECTION 5怎么部署How to deploy it
这一节讲无状态带来的实际部署形态变化。核心只有一句话:你之前为 MCP 专门加的那些组件,现在大多可以删掉。
This section covers what statelessness changes in practice. The core of it: most of the components you added specifically for MCP can now be deleted.
网关侧:一个可以直接抄的路由思路
Gateway side: a routing approach you can copy
下面是思路示意(不是从官方文档抄来的配置,请按你自己的网关语法调整)。要点在于:所有判断都只依赖 header,不碰 body。
Below is an illustrative sketch (not copied from official docs — adapt it to your gateway's syntax). The point is that every decision reads headers only and never touches the body.
# Nginx 思路示意 / Nginx sketch
map $http_mcp_method $mcp_pool {
"tools/call" heavy_pool;
"tools/list" light_pool;
"prompts/list" light_pool;
"resources/list" light_pool;
default light_pool;
}
# 给特别贵的单个工具单独限流
# rate-limit one expensive tool specifically
map $http_mcp_name $mcp_limit_key {
"deploy_service" $binary_remote_addr;
default "";
}
limit_req_zone $mcp_limit_key zone=expensive:10m rate=5r/m;
server {
location /mcp {
limit_req zone=expensive burst=2 nodelay;
proxy_pass http://$mcp_pool;
# 不再需要 ip_hash / sticky / session affinity
# no ip_hash / sticky / session affinity needed anymore
}
}
服务端侧:三件必做的事
Server side: three things you must do
- 给不可逆工具加幂等键
因为断流重发会带新的请求 ID,你不能靠请求 ID 去重。约定一个业务层幂等键(比如客户端生成的操作 UUID,放在工具参数里),服务端据此判重。这一条是必做,不是优化。 - 给 requestState 签名
用 HMAC 或加密,带上过期时间。服务端收回时先验签再解析。所有实例共享同一把密钥(这是无状态部署里少数仍需共享的东西,但它是配置,不是会话存储)。 - 给列表接口设合理的 ttlMs
工具清单如果基本不变,给个几分钟到几小时的ttlMs;并保证排序是确定的(按名字排,别按 map 遍历顺序)。这一条直接省 token。
- Add idempotency keys to irreversible tools
A re-issued request carries a new request ID, so you can't dedupe on that. Agree on a business-level idempotency key (a client-generated operation UUID in the tool arguments, say) and dedupe on it server-side. This is mandatory, not an optimization. - Sign your requestState
HMAC or encrypt it, with an expiry. Verify before parsing on the way back. All instances share one key — one of the few things still shared in a stateless deployment, but it's configuration, not a session store. - Set a sensible ttlMs on list endpoints
If your tool list rarely changes, give it attlMsof minutes to hours, and make the ordering deterministic (sort by name; don't emit map iteration order). This one directly saves tokens.
第 6 节SECTION 6迁移清单与会踩的坑Migration checklist and pitfalls
迁移清单
Migration checklist
| 检查项 | 为什么 | 怎么改 | Check | Why | What to do |
|---|---|---|---|---|---|
代码里有没有依赖 Last-Event-ID 或 SSE 消息重放 |
该机制已被移除 | 删掉断流恢复逻辑,改成「失败即用新 ID 重发」 | Any reliance on Last-Event-ID or SSE replay |
The mechanism is gone | Delete resume logic; re-issue with a new ID on failure |
| 有没有不可逆工具 | 重发会导致重复执行 | 加业务层幂等键(必做) | Any irreversible tools | Re-issues cause duplicate execution | Add a business-level idempotency key (mandatory) |
| 取消(cancellation)逻辑 | 每种传输的取消语义需分别实现 | 按传输逐一实现并测试 | Cancellation logic | Cancellation semantics differ per transport | Implement and test per transport |
| 服务端主动发起的 sampling / elicitation | 不能再靠反向请求 | 迁到 MRTR,状态放 requestState |
Server-initiated sampling / elicitation | Reverse requests are no longer available | Move to MRTR with state in requestState |
| 变更通知(list changed 等) | 独立 GET 流已被取代 | 改用 subscriptions/listen |
Change notifications (list changed, etc.) | The standalone GET stream is replaced | Move to subscriptions/listen |
| 授权用的是 DCR | 已弃用(兼容期内仍可用) | 规划迁到 CIMD,不急但要排期 | Authorization uses DCR | Deprecated (still works during the grace period) | Plan a move to CIMD — not urgent, but schedule it |
| 网关的粘性会话配置 | 不再需要 | 确认客户端都已升级后再关掉 | Gateway sticky-session config | No longer needed | Turn it off only after all clients have upgraded |
四个高频坑
Four common traps
坑 1:以为「无状态」= 我的应用不用管状态了。不是。无状态说的是协议层没有会话。你的业务状态(用户数据、任务进度、缓存)该放数据库还得放数据库。真正变了的是:状态不再隐式地绑在某条连接上,而要显式地放进请求里或持久化到共享存储。
Trap 1: reading "stateless" as "my application no longer has state." It doesn't mean that. Statelessness applies to the protocol layer. Your business state (user data, job progress, caches) still belongs in a database. What actually changed is that state is no longer implicitly bound to a connection — it must be explicitly placed in the request or persisted to shared storage.
坑 2:太早关掉粘性路由。客户端和服务端的升级不同步是常态。老客户端还在用 2025-11-25 的有状态玩法时,你把网关的会话亲和性关了,它们会以各种奇怪的方式失败。正确顺序是:服务端先双版本兼容 → 观察流量里旧版本占比降到零 → 再关粘性。
Trap 2: dropping sticky routing too early. Client and server upgrades are never in lockstep. If old clients are still speaking the stateful 2025-11-25 revision when you disable session affinity, they fail in creative ways. The right order: make the server support both revisions → watch the old-revision share of traffic fall to zero → then drop stickiness.
坑 3:把 requestState 当成明文塞回去。前面说过,但值得再说一次:这是把服务端内部状态交给客户端保管。不签名 = 允许客户端伪造「我已经通过确认了」。
Trap 3: sending requestState back as plaintext. Said earlier, but worth repeating: this hands internal server state to the client. Unsigned means the client can forge "I already passed the confirmation."
坑 4:忽略了每请求开销的累加。每个请求都带协议版本、客户端信息、capabilities,单看很小,但在高 QPS 的 agent 场景下会累加成可观的带宽和序列化开销。如果你的 agent 在一个任务里要打几百次工具调用,这一项值得测一下。
Trap 4: ignoring the accumulated per-request overhead. Protocol version, client info, and capabilities on every request look tiny individually, but at agent-scale QPS they add up to real bandwidth and serialization cost. If your agent makes hundreds of tool calls per task, measure this.
来源:MCPJam 迁移指南、Stacktree 变更清单、Equixly 安全视角。坑 1/2/4 属于社区经验与工程推论,非官方明文规定。
Sources: MCPJam migration guide, Stacktree change list, Equixly security analysis. Traps 1/2/4 are community experience and engineering inference, not explicit spec text.
第 7 节SECTION 7对比与选型:我现在该不该迁?Comparison: should I migrate now?
| 你的情况 | 建议 | 理由 | Your situation | Recommendation | Why |
|---|---|---|---|---|---|
| 本地 stdio MCP 服务(个人用、Claude Code 里挂的那种) | 不急 | 无状态解决的是远程扩容问题,本地一对一场景没有这个痛点。等 SDK 升级时顺带跟上即可。 | Local stdio MCP server (personal, wired into Claude Code) | No rush | Statelessness solves remote scaling; a local one-to-one setup doesn't have that pain. Follow along when your SDK bumps. |
| 远程 MCP 服务,单实例,流量小 | 可以等 | 收益主要在多实例扩容。但建议现在就先把幂等做了,那是无论如何都该有的。 | Remote MCP server, single instance, low traffic | Can wait | The payoff is in multi-instance scaling. But do the idempotency work now — you want it regardless. |
| 远程 MCP 服务,已经在跑 Redis 会话存储 + 粘性路由 | 值得迁 | 直接省掉两个运维组件,这是最大受益群体。 | Remote MCP server already running a Redis session store + sticky routing | Worth migrating | You delete two operational components outright. This is the group that benefits most. |
| 想上 serverless / 函数计算 | 必须迁 | 有状态 MCP 和 serverless 是根本冲突的——无状态是前置条件。 | Want to run on serverless / FaaS | Must migrate | Stateful MCP fundamentally conflicts with serverless. Statelessness is the precondition. |
| 重度依赖 elicitation / 人工确认 | 先评估 SDK | 迁移量集中在 MRTR 改造上;先确认你用的语言 SDK 支持到位了再动。 | Heavily reliant on elicitation / human confirmation | Check SDK support first | The bulk of the work is the MRTR rewrite; confirm your language's SDK is ready before starting. |
一个不分情况都成立的建议:无论你迁不迁,现在就给不可逆工具加幂等。有状态时代靠「连接不断就不会重发」这个假设活着的代码,本来就是脆的——网络抖动、客户端重试、用户手快点两下,都会破掉这个假设。无状态只是把这件事从「偶尔出事」变成了「一定出事」。
One recommendation that holds regardless: migrate or not, add idempotency to your irreversible tools now. Code that survived the stateful era by assuming "the connection won't break so nothing gets re-sent" was always fragile — network jitter, client retries, or a user double-clicking all break that assumption. Statelessness just moves this from "occasionally bites" to "definitely bites."
第 8 节SECTION 8术语表Glossary
- MCP (Model Context Protocol)
- 模型上下文协议。让 AI 模型以统一方式调用外部工具与数据源的开放协议。版本号用发布日期表示,如
2026-07-28。 - An open protocol that lets AI models call external tools and data sources in a uniform way. Revisions are named by release date, e.g.
2026-07-28. - SEP (Specification Enhancement Proposal)
- 规范增强提案。MCP 的变更提案流程,类似 Python 的 PEP。本次无状态化由六个 SEP 协同完成。
- MCP's change-proposal process, analogous to Python's PEP. Six SEPs together delivered this statelessness work.
- MRTR (Multi Round-Trip Requests)
- 多轮往返请求,SEP-2322。让一次工具调用可以「中途要输入 → 客户端补齐 → 带状态重试」,从而无需长连接。
- SEP-2322. Lets a single tool call go "needs input mid-way → client fills it in → retry with state attached," removing the need for a held-open stream.
- requestState
- MRTR 中服务端交给客户端、之后原样收回的不透明状态块。必须做完整性保护(签名/加密)。
- The opaque state blob a server hands the client and takes back verbatim in MRTR. Must be integrity-protected (signed or encrypted).
- CIMD (Client ID Metadata Documents)
- 客户端 ID 元数据文档。用「客户端自己托管的 URL」当 client_id,授权服务器按需解析,取代动态客户端注册(DCR)。
- Uses a URL the client hosts itself as the
client_id, resolved on demand by the authorization server. Replaces Dynamic Client Registration (DCR). - Streamable HTTP
- MCP 的 HTTP 传输方式。本次要求它必须携带
Mcp-Method与Mcp-Name两个 header。 - MCP's HTTP transport. This revision requires it to carry the
Mcp-MethodandMcp-Nameheaders. - 粘性会话(Sticky session)
- Sticky session
- 负载均衡策略:把同一会话的所有请求固定路由到同一台后端实例。无状态之后不再需要。
- A load-balancing policy that pins all requests in a session to one backend instance. No longer needed once the protocol is stateless.
- 幂等(Idempotency)
- Idempotency
- 同一个操作执行一次和执行多次,结果一样。实现方式通常是给操作一个唯一键,服务端见过就不再执行。
- Performing an operation once and performing it many times produce the same result. Usually implemented by giving each operation a unique key the server dedupes on.
第 9 节SECTION 9学习资源Resources
按「先读哪个」排序:
Ordered by what to read first:
- MCP 官方博客:The 2026-07-28 Specification —— 一手来源,先读这个。
- SEP-2322: Multi Round-Trip Requests —— MRTR 的正式定义。要实现服务端的必读。
- 2026 MCP Roadmap —— 了解接下来还要变什么,避免刚迁完又变。
- MCPJam:迁移指南 / Stacktree:每个破坏性变更 + 修法 —— 动手迁移时的对照表。
- Google Developers Blog / Microsoft(Azure App Service) —— 两家云厂商各自的规模化部署视角。
- Equixly:无状态 MCP 的安全影响 —— 专讲 requestState 与授权面的风险。
- C# SDK:MRTR 概念文档 —— 目前找到的最完整的 SDK 侧实现说明(其他语言请查各自仓库)。
- MCP 规范版本时间线 —— 想搞清楚各版本之间怎么演变的话看这个。
- MCP official blog: The 2026-07-28 Specification — the primary source. Read this first.
- SEP-2322: Multi Round-Trip Requests — the formal definition of MRTR. Required reading if you're implementing a server.
- The 2026 MCP Roadmap — what's changing next, so you don't finish a migration just in time for another one.
- MCPJam: migration guide / Stacktree: every breaking change, with fixes — the reference tables to keep open while migrating.
- Google Developers Blog / Microsoft (Azure App Service) — two cloud vendors' takes on scaling it.
- Equixly: security implications of stateless MCP — focused on requestState and the authorization surface.
- C# SDK: MRTR concepts — the most complete SDK-side write-up found (check other languages' own repos).
- MCP specification version timeline — for understanding how the revisions evolved.
主页