编程 MCP 2026-07-28 规范深度拆解:当 AI 连接协议决定拆掉「会话」——从有状态 RPC 到无状态核心、扩展框架与 Tasks/MCP Apps 的全链路工程革命

2026-08-12 13:44:24 +0800 CST views 8

MCP 2026-07-28 规范深度拆解:当 AI 连接协议决定拆掉「会话」——从有状态 RPC 到无状态核心、扩展框架与 Tasks/MCP Apps 的全链路工程革命

2026 年 7 月 28 日,Anthropic 发布了被官方定性为「问世以来规模最大、最系统性的一次颠覆式修订」的 MCP 规范第 5 版。它最核心的一刀,是砍掉了自 2024-11 协议诞生起就存在的有状态会话,把整个协议重写成一个无状态核心(Stateless Core),并配套引入了版本化扩展框架、Tasks 长任务扩展、MCP Apps 交互扩展、OAuth/OIDC 授权加固与标准化链路追踪。

本文不堆砌发布稿,而是从工程视角把这次改动拆开揉碎:为什么「有状态」会成为 AI 工具协议的阿喀琉斯之踵?无状态核心到底改了哪些字节?网关、长任务、交互界面这三座大山是怎么被新扩展抬走的?我们如何用 TypeScript / Python 从零搭一个符合新规范的无状态 MCP 服务,并在生产里把它跑稳?


一、背景介绍:为什么「连接协议」会成为一个时代命题

1.1 一个被低估的瓶颈

2024 年底,当大模型的能力还在以月为单位翻番时,行业遇到一个很反直觉的问题:模型越强,越「聋哑」

一个能写诗、能解偏微分方程的模型,却连「查一下我昨天下的订单」「把这张表写进数据库」「调一下内部 CRM 接口」都做不到。根源不在模型智力,而在于模型与外部世界之间缺少一层标准、安全、可组合的「插座」

在那之前,每个团队都在用自己的一套私活把工具接给 LLM:

  • 有的把函数签名塞进 system prompt,靠模型「自觉」输出 JSON 再自己 parse——脆弱、不可控、不可观测;
  • 有的用 OpenAI 的 function calling,但每一家 API 格式都不同,换模型等于重写一遍;
  • 有的干脆在 agent 框架里硬编码 tool 调用逻辑,工具一多就变成一团意大利面。

Anthropic 在 2024-11 推出 MCP(Model Context Protocol,模型上下文协议),想做的事一句话概括:给 AI 世界做一根 USB-C 线——任何模型、任何客户端、任何外部工具,只要都插这根线,就能即插即用地对话。

1.2 前两代 MCP 的「原罪」:有状态

MCP 2024-11 到 2025-11 的几个版本,采用的是典型的 有状态连接(Stateful Connection) 模型:

  1. 客户端先发一个 initialize 请求,做能力协商(你支持哪些 method、哪些 feature);
  2. 服务端返回一个 sessionId,此后所有请求都带着这个 sessionId;
  3. 服务端可以通过 SSE(Server-Sent Events)主动向客户端推送通知(notifications);
  4. 能力发现(这个 server 有哪些 tools/resources/prompts)是通过初始化阶段的协商完成的,不是按需查询。

这套模型在「单客户端 ↔ 单本地进程」的场景下工作得不错——事实上它撑起了 MCP 从 0 到 400+ 开源 server 的生态爆发。但它有三个结构性问题,随着规模上来被无限放大:

问题一:网关成了「拆包地狱」。
当 MCP 服务要上云、要被成千上万个客户端共享时,你一定需要一个反向代理 / API 网关来做事:鉴权、限流、路由、灰度、缓存。但有状态模型下,网关为了知道「这个请求要路由到哪个后端、要不要走缓存、属于哪个租户」,必须解析 JSON-RPC 的 body,因为关键信息(method 名、tool 名)藏在 JSON 里,而 sessionId 又在另一个头里。一个本该做 L7 转发的网关,被迫变成了「读懂每个请求语义」的业务系统。这在高并发下是灾难。

问题二:水平扩展几乎不可能。
有状态意味着「同一个 session 的后续请求必须打到同一台机器」(sticky session)。一旦某台机器挂了,上面所有 session 全废;想做蓝绿发布、想弹性伸缩,都受制于会话亲和。在 AI 流量「突发、长尾、潮汐」的特征下,这等于给基础设施套了枷锁。

问题三:长任务与交互界面「拧巴」。
MCP 早期为了做长任务(比如「生成一份 30 页报告」要跑 5 分钟),只能靠服务端一直 hold 住 SSE 连接、不停推进度——但 SSE 单向、且浏览器/网关对长连接都有限制。想让工具弹出一个交互式表单(让用户填参数再继续),早期协议根本没有标准载体,各厂自己造轮子,互不兼容。

1.3 2026-07-28:把「状态」还给基础设施

第 5 版规范的解法非常「Unix 哲学」:协议只负责定义「一次请求一次响应」的最小契约,把会话、路由、缓存、长任务、交互这些「有状态的东西」统统交还给已经成熟的基础设施(HTTP、网关、OAuth、消息队列)去处理。

这绝不是偷懒,而是一次精准的架构归位。下面我们进入核心概念。


二、核心概念:无状态核心到底改了什么

2.1 三个被移除的「旧世界遗产」

旧世界(≤2025-11)新世界(2026-07-28)
initialize 握手 + 能力协商移除握手;能力通过显式查询获取
sessionId 绑定有状态会话无 sessionId;每个请求自包含
服务端经 SSE 主动推送服务端不再主动说话;改由客户端驱动的请求-响应 / 任务轮询
method/tool 名藏在 JSON body提升到 Mcp-Method / Mcp-Name 标准头
能力发现 = 初始化阶段一次性完成能力发现 = 按需主动查询(可缓存、可 CDN)
扩展 = 各厂私有的实验字段扩展 = 版本化、插件化的官方框架

2.2 关键新原语一:Mcp-MethodMcp-Name

新规范把「这个请求要干什么」从 JSON body 里提拔到 HTTP 头,变成两个标准头:

Mcp-Method: tools/call
Mcp-Name: query_orders
  • Mcp-Method 是协议级动作,比如 tools/calltools/listresources/readtasks/getapps/render
  • Mcp-Name 是具体资源的名字,比如某个 tool 叫 query_orders

为什么这一步是「质变」而不是「洁癖」? 因为有了这两个头,一个不懂 MCP 语义的普通 HTTP 网关,也能在不解析 body 的前提下完成:

  • 路由:按 Mcp-Name 把不同 tool 打到不同后端微服务;
  • 限流:按 Mcp-Method + Mcp-Name 维度做 QPS 控制;
  • 缓存tools/listresources/list 这种「读多写少」的声明性请求,可以直接进 CDN / 边缘缓存;
  • 灰度 / 多版本:头部携带 method 名,网关按名字做金丝雀,完全不需要理解 JSON。

这叫「参数镜像(Parameter Mirroring)」——协议把路由所需的关键参数,在头部「镜像」了一份给网关看,网关从此有了「透视挂」。

2.3 关键新原语二:客户端驱动的能力发现

旧世界里,能力(有哪些 tool)是在 initialize 时由服务端「推」给客户端的,且往往不可缓存(绑定在 session 上)。新世界改成:客户端随时主动发 tools/list / resources/list / prompts/list,服务端返回纯声明性、幂等、可缓存的 JSON Schema 列表。

因为请求是无状态的、响应是幂等的,于是:

  • 网关可以给 tools/listCache-Control: public, max-age=300
  • 多客户端共享同一个 server 时,工具清单可以被边缘节点缓存,命中率极高;
  • 工具 Schema 现在可以用完整的 JSON Schema(不再是早期被阉割的 subset),支持 format$defsanyOf、循环引用等高级玩法。

2.4 关键新原语三:服务端「闭嘴」,请求-响应独大

旧世界服务端能经 SSE 主动推 notification。新世界下,服务端不能主动发起任何对话——所有信息交换都必须是「客户端发一个请求 → 服务端回一个响应」。

那「服务端想告诉客户端一件事」(比如「你订阅的那个资源变了」)怎么办?新规范把两套通知机制合并成一个,并统一走客户端轮询 / 任务查询通道。这看似「退化」了实时性,实则是把「实时推送」这件难做且易崩的事,交还给 WebSocket / SSE / Webhook 这些本就为此而生的传输层,协议核心保持极简。

2.5 一句话总结无状态核心

旧 MCP:把「连接」当有状态对象来管理。
新 MCP:把「连接」当无状态 HTTP 请求来处理,状态由调用方自己携带或交给外部系统。

这正是 REST 当年相对于 SOAP/RPC 的那次心智跃迁。


三、架构分析:旧世界 vs 新世界

3.1 旧世界时序(有状态)

Client                         Gateway                     Server A (session 绑定)
  |                              |                            |
  |-- initialize -------------->|-- 转发 ------------------->|  (协商能力, 建 session)
  |<------------- sessionId -----|<---------------------------|
  |                              |                            |
  |-- tools/call (sessionId) --->|-- 解析body知是tools/call ->|  (必须打到 A, 因 session 在 A)
  |<------------- result --------|<---------------------------|
  |                              |                            |
  |<== SSE: notification (服务端主动推) ======================|  (长连接 hold 住)

痛点:Gateway 必须解析 body;Server A 挂了 session 全灭;SSE 长连接占满网关连接数。

3.2 新世界时序(无状态)

Client                         Gateway (只看头)              Server 集群 (任意一台)
  |                              |                            |
  |-- POST /mcp --------------->|-- 读 Mcp-Method/Mcp-Name ->|  按名字路由到健康实例
  |   Mcp-Method: tools/call    |   (不解析 body)            |
  |   Mcp-Name: query_orders    |-- 路由(可限流/可缓存) ---->|
  |   Body: {orderId:"123"}     |                            |
  |<------------- result --------|<---------------------------|  无状态, 任意实例都能答
  |                              |                            |
  |-- POST /mcp (Mcp-Method:tasks/get, Mcp-Name:report_gen)
  |<-- {status:"running", progress:0.4}                      |  长任务轮询, 不占长连接

新世界的每一个请求都是自包含、幂等、可重放、可路由、可缓存的。Gateway 回归它最擅长的「管道」角色。

3.3 扩展框架:协议「瘦身」,能力「插件化」

这是本次更新最容易被低估、却最影响生态寿命的设计。新规范引入了版本化扩展框架(Versioned Extensions Framework):核心协议保持极简且稳定,任何「超出核心」的能力都以独立、带版本号、可协商的扩展形式挂载。

首批被正式纳入的两个扩展:

  • Tasks 扩展:解决「长任务」问题。工具可以返回一个 task 句柄,客户端用 tasks/get 轮询状态、进度、产物;任务生命周期(queued → running → succeeded/failed)有标准状态机。
  • MCP Apps 扩展:解决「交互界面」问题。工具可以返回一个 app 内容块——一段由 Host(比如 Claude Desktop、IDE、浏览器)负责渲染的结构化 UI(表单、图表、按钮),让用户填空/确认后,结果再回流给模型。

二者都不修改核心协议的一个字节,只是「装上去」的插件。这意味着:未来出现「MCP 支付」「MCP 文件选择器」等新能力时,不需要再发一次破坏性的规范大版本,而是加一个扩展即可。

3.4 授权加固:从「变通方案」到「生产级身份」

旧世界把鉴权基本甩给传输层,企业里要接 Azure AD / Okta 往往得各种 hack。新规范把 OAuth 2.0 + OIDC 作为一等公民写进协议:

  • 服务端可以直接对接 Entra(微软企业身份)Okta 等 IdP,无需客户端做适配层;
  • 标准 Authorization: Bearer <token> + Discovery 端点(/.well-known/oauth-authorization-server);
  • 明确了「无状态核心下,token 必须由每个请求自带」(因为不再有 session 帮你记着登录态)——这反而让鉴权更清晰、更可审计。

3.5 可观测性:链路追踪标准化

新规范把分布式追踪标准化了:请求自动携带 W3C traceparent / tracestate 头,一次 tools/call 从 Client → Gateway → Server → 内部微服务,能在 Jaeger / Tempo / 云厂商 APM 里串成一条完整调用链。这是把 MCP 真正「拖进生产可观测体系」的关键一步——此前每个团队都得自己发明一套埋点。

3.6 正式弃用策略

第 5 版第一次给出了正式的 deprecation policy:被移除的功能(如 initialize 握手、session 机制、服务端单向 SSE 推送)不会「默默消失」,而是有明确淘汰周期、迁移指引和版本号标记。这对企业来说意味着:升级不再是一场俄罗斯轮盘赌。


四、代码实战:从零搭一个无状态 MCP 服务

下面用 TypeScript(Node.js) 为主、Python 为辅,搭一个符合 2026-07-28 规范的无状态 MCP 服务,并覆盖网关路由、Tasks、MCP Apps、双版本兼容。

4.1 一个最小无状态 server(TypeScript)

核心点:StreamableHTTPServerTransportsessionIdGenerator 设为 undefined,即声明「我是无状态的」。每次请求都新建 server 实例(或复用已注册 handler 的无状态 server),处理完即释放——没有跨请求的内存状态。

// server.ts — 符合 MCP 2026-07-28 的无状态 server
import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";

const app = express();
app.use(express.json());

// 工具清单集中注册(声明性、可缓存)
function buildServer(): McpServer {
  const server = new McpServer({
    name: "orders-mcp",
    version: "2026.7.28",
  });

  // 注意:inputSchema 现在支持完整 JSON Schema(draft 2020-12)
  server.tool(
    "query_orders",
    {
      description: "按订单号或时间范围查询订单",
      inputSchema: {
        type: "object",
        properties: {
          orderId: { type: "string", description: "订单号,二选一" },
          since: { type: "string", format: "date-time", description: "起始时间" },
          limit: { type: "integer", minimum: 1, maximum: 200, default: 20 },
        },
        anyOf: [{ required: ["orderId"] }, { required: ["since"] }],
      },
    },
    async ({ orderId, since, limit = 20 }) => {
      const rows = await db.queryOrders({ orderId, since, limit });
      return {
        content: [{ type: "text", text: JSON.stringify(rows, null, 2) }],
      };
    }
  );

  return server;
}

// 无状态:每个 POST /mcp 都走一个独立 transport,不分配 sessionId
app.post("/mcp", async (req, res) => {
  const server = buildServer();
  const transport = new StreamableHTTPServerTransport({
    sessionIdGenerator: undefined, // ★ 无状态核心的关键开关
  });
  await server.connect(transport);
  await transport.handleRequest(req, res, req.body);
  // 响应结束即断开,无会话残留
});

app.listen(3000, () => console.log("stateless MCP server on :3000"));

要点解读:

  • sessionIdGenerator: undefined 是「声明无状态」的硬开关。一旦设了它,传输层就不会维护 session 映射表,内存里不再有「连接状态」对象。
  • inputSchema 里我们用了 anyOf 做「二选一必填」、format: "date-time"minimum/maximum——这些都是完整 JSON Schema 才有的能力,旧版 MCP 子集是不支持的。Host 端能据此自动生成更智能的参数表单。

4.2 网关路由:只读头,不拆包

新规范最爽的工程红利,是网关可以完全不解析 body。下面用 15 行伪代码展示一个「按 tool 名分流到不同微服务集群」的网关:

// gateway.ts — 无状态友好的 MCP 网关
import express from "express";
const app = express();

const BACKENDS: Record<string, string> = {
  query_orders: "http://orders-svc:3000",
  gen_report: "http://report-svc:3000", // 重任务走专用集群
  search_docs: "http://rag-svc:3000",
};

app.post("/mcp", async (req, res) => {
  // ★ 只看头,不读 body
  const method = String(req.headers["mcp-method"] ?? "");
  const name = String(req.headers["mcp-name"] ?? "");

  // 1) 限流:按 method+name 维度
  if (!rateLimit.allow(`${method}:${name}`)) {
    return res.status(429).json({ error: "rate limited" });
  }

  // 2) 缓存:声明性请求可走边缘缓存
  if (method === "tools/list" || method === "resources/list") {
    const cached = edgeCache.get(req.originalUrl);
    if (cached) return res.json(cached); // 命中,连后端都不打
  }

  // 3) 路由:按 Mcp-Name 打到对应后端
  const upstream = BACKENDS[name] ?? BACKENDS["__default"];
  const r = await fetch(upstream + "/mcp", {
    method: "POST",
    headers: {
      "content-type": "application/json",
      "mcp-method": method,
      "mcp-name": name,
      authorization: req.headers["authorization"]!, // token 透传,无状态=每请求自带
    },
    body: JSON.stringify(req.body),
  });
  const data = await r.json();
  if (method === "tools/list") edgeCache.set(req.originalUrl, data, 300);
  res.json(data);
});

app.listen(8080);

对比旧世界:同样的网关,旧规范下你得 JSON.parse(req.body) 才能拿到 method/tool 名,还得处理 session 亲和(同一 session 必须回同一后端),代码量和出错面都指数级上升。新规范下,网关退化成一个「读两个头 + 转发」的纯管道,这才是它该有的样子

4.3 Tasks 扩展:把长任务「转正」

过去「生成 30 页报告要 5 分钟」,要么 hold 住 SSE 一直推,要么客户端自己搞轮询约定。新规范用 Tasks 扩展给出标准答案:tool 调用立刻返回一个 task 句柄,后续用 tasks/get 轮询。

// report_task.ts — Tasks 扩展实战
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";

server.tool(
  "gen_report",
  {
    description: "生成季度经营分析报告(长任务)",
    inputSchema: {
      type: "object",
      properties: { quarter: { type: "string", pattern: "^\\d{4}-Q[1-4]$" } },
      required: ["quarter"],
    },
  },
  async ({ quarter }, { sendTaskUpdate }) => {
    // 立即返回任务句柄,不阻塞
    const taskId = `task_${crypto.randomUUID()}`;

    // 异步推进(真实场景进消息队列 / 后台 worker)
    (async () => {
      await sendTaskUpdate(taskId, { status: "running", progress: 0.1 });
      const data = await extractQuarterData(quarter);
      await sendTaskUpdate(taskId, { status: "running", progress: 0.5 });
      const doc = await renderReport(data);
      await sendTaskUpdate(taskId, {
        status: "succeeded",
        progress: 1.0,
        result: { url: doc.url, pages: doc.pages },
      });
    })();

    // 立刻把句柄交还给客户端
    return {
      content: [{ type: "task", taskId, status: "running", progress: 0.0 }],
    };
  }
);

客户端侧的标准轮询:

// client 轮询任务
async function waitTask(taskId: string) {
  while (true) {
    const r = await client.call("tasks/get", { taskId });
    if (r.status === "succeeded") return r.result;
    if (r.status === "failed") throw new Error(r.error);
    await sleep(2000); // 进度 0.1 → 0.5 → 1.0
  }
}

为什么这比 SSE 推送更稳? 因为长任务期间客户端和服务端之间的「连接」可以随时断、随时重连,任务状态存在服务端(或消息队列)而非某条 TCP 连接里。网关不会因为 5 分钟的长连接把连接池撑爆;客户端刷新页面也不会丢进度。

4.4 MCP Apps 扩展:让工具「长出界面」

有些工具不是「给模型吃文本」,而是要让用户参与。比如「配置一个数据同步任务」——与其让模型瞎编参数,不如弹个表单让用户填。MCP Apps 扩展就是干这个的:tool 返回一个 app 内容块,由 Host 渲染成结构化 UI,用户填完,结果回流。

server.tool(
  "setup_sync",
  { description: "配置数据同步任务", inputSchema: { type: "object", properties: {} } },
  async () => {
    // 返回一个结构化 UI 卡片,Host(IDE/桌面端)负责渲染
    return {
      content: [
        {
          type: "app",
          appId: "sync-wizard",
          title: "数据同步配置",
          schema: {
            type: "form",
            fields: [
              { name: "source", label: "数据源", control: "select", options: ["mysql", "pg", "kafka"] },
              { name: "target", label: "目标", control: "select", options: ["s3", "doris"] },
              { name: "cron", label: "调度周期", control: "text", placeholder: "0 2 * * *" },
            ],
          },
        },
      ],
    };
  }
);

Host 拿到这个 app 块,渲染出表单;用户提交后,Host 用 apps/submit 把填写结果回传给 server,server 再据此真正建任务。这一套把「人机协同」第一次变成了 MCP 的一等公民,而不再是各厂私有的 hack。

4.5 Python 侧对照

Python 生态的 mcp SDK 同样支持无状态 HTTP。写法同构:

# server.py — Python 无状态 MCP server
from mcp.server import Server
from mcp.server.streamable_http import StreamableHTTPServerTransport
import mcp.types as types
import anyio

app = Server("orders-mcp-py")

@app.call_tool()
async def call_tool(name: str, arguments: dict):
    if name == "query_orders":
        rows = await db_query(arguments)
        return [types.TextContent(type="text", text=__import__("json").dumps(rows))]
    raise ValueError(f"unknown tool: {name}")

# 无状态:每次连接用独立 transport,不维护 session
async def handle(scope, receive, send):
    transport = StreamableHTTPServerTransport(session_id_generator=None)
    async with app.run(transport):
        await transport.handle(scope, receive, send)

注意 session_id_generator=None 这个等价开关。Python 侧同样享受「无状态 = 任意实例可答 = 随便水平扩」的红利。

4.6 双版本兼容迁移(关键!)

别头铁一次性切。官方与各大云厂(AWS AgentCore Gateway、Cloudflare)都给出同一建议:双版本并行过渡最稳。网关按 Mcp-Protocol-Version 头广播,旧客户端走旧逻辑、新客户端走新逻辑。

// 网关按版本头分流
app.post("/mcp", (req, res) => {
  const ver = String(req.headers["mcp-protocol-version"] ?? "2025-11-25");
  if (ver >= "2026-07-28") {
    return handleStateless(req, res);   // 无状态新核心
  }
  return handleLegacy(req, res);          // 旧有状态兼容分支
});

实测里,把 tools/list 这类声明性接口先切到新规范(风险极低、收益最高:立刻获得缓存),再逐步把 tools/call 迁过去,是平滑度最高的顺序。


五、性能优化:无状态带来的真实红利

光说「架构更优雅」不够,我们算几笔工程账。

5.1 连接数:从「长连接占用」到「请求级释放」

旧世界一个长任务 = 一条被 hold 住的 SSE 连接 = 网关/服务端一个被占用的连接槽,5 分钟不动也占着。新世界长任务走 Tasks 轮询,连接发完即回收。在「1000 个并发用户在跑长任务」的场景下,旧架构需要 1000 个常驻连接,新架构只需要「轮询瞬间」的短连接——连接池压力下降一到两个数量级。

5.2 缓存命中:声明性接口进 CDN

tools/list / resources/list 在旧世界绑定 session、几乎不可缓存。新世界它们是幂等、自包含、可加 Cache-Control 的。某云厂实测:把工具清单缓存 5 分钟(max-age=300)后,边缘缓存命中率 70%+,后端 MCP server 的 tools/list QPS 直接砍掉七成。对一个「每次会话开始都要拉一次工具清单」的 agent 场景,这是肉眼可见的成本下降。

5.3 水平扩展:告别 sticky session

无状态 = 请求到哪台机器都能答 = 负载均衡可以随便轮询(round-robin / 最少连接)。这意味着:

  • 发布新版本可以无损滚动更新(没有 session 被「钉」在旧实例上);
  • 流量突增可以秒级扩副本(不需要预热会话);
  • 单实例崩溃零会话丢失(下一个请求自动落到健康实例)。

对一个 AI 产品「白天忙、夜里闲、偶尔爆」的潮汐流量,这等于把基础设施成本打了对折。

5.4 网关零解析:CPU 省给业务

网关不再 JSON.parse 每个请求 body,只做「读两个头 + 转发」。在 10k+ QPS 下,省掉的 JSON 解析 CPU 相当可观,且网关的故障面显著缩小(不会因为某个畸形 JSON body 把网关自己搞挂)。

5.5 一段 benchmark 思路(供你自测)

# 用 k6 压无状态 server,观察连接数与 p99
k6 run -e BASE=http://localhost:8080 - <<'EOF'
import http from 'k6/http';
export const options = { vus: 200, duration: '30s' };
export default () => {
  http.post(`${__ENV.BASE}/mcp`,
    JSON.stringify({ jsonrpc:'2.0', id:1, method:'tools/call',
                     params:{ name:'query_orders', arguments:{ orderId:'123' } } }),
    { headers: { 'content-type':'application/json',
                 'mcp-method':'tools/call', 'mcp-name':'query_orders' } });
};
EOF

关注三个指标:p99 延迟、网关 CPU、单实例可承载 VU 数。对比同一逻辑的有状态实现,通常会看到 p99 更稳、拐点更高。


六、总结展望:一次「归位」而非「重写」

6.1 这次更新的本质

MCP 2026-07-28 不是一次功能堆砌,而是一次职责归位:把「会话状态」还给 HTTP、把「路由缓存」还给网关、把「长任务」还给队列、把「交互界面」还给 Host、把「身份」还给 OAuth/OIDC、把「追踪」还给 W3C 标准。协议核心被削到最薄,却因此获得了最强的扩展性与最好的基础设施亲和力。

这其实和同年其他大版本(PostgreSQL 18 的 AIO、Python 3.14 拆 GIL、Kubernetes 1.36 为 AI 重写调度)是同一股暗流:把「本不属于自己」的复杂度,交还给更擅长它的那一层。 这是成熟系统的标志。

6.2 对生态意味着什么

  • 对云厂:AWS AgentCore Gateway、Cloudflare 都已第一时间支持新规范,并强调「按版本头广播即可并行兼容」。网关侧成本骤降,MCP 真正适合上云多租户。
  • 对开发者:写 server 更简单(不用管 session 生命周期),写网关更爽(只读头),写长任务/交互有标准载体。
  • 对企业:OAuth/OIDC + 标准化追踪 + 正式弃用策略,把 MCP 从「玩具协议」推到了「可审计、可治理、可演进」的生产级协议。
  • 对模型侧:TS 7.0(Go 重写)编译器路线、各类 agent 框架,都会基于「无状态、可缓存、可路由」的 MCP 重新组织工具调用层。

6.3 迁移行动清单(别等)

  1. 先升级 SDK 到支持 2026-07-28 的版本(TS SDK、Python mcp 均已发版)。
  2. tools/list / resources/list 这类声明性接口优先切到无状态 + 加缓存——低风险高收益。
  3. 网关改造:加 Mcp-Method / Mcp-Name 头解析与按名路由,移除 session 亲和逻辑。
  4. 长任务从 SSE 推送迁移到 Tasks 扩展轮询。
  5. 需要人机交互的工具,改用 MCP Apps 标准 app 块。
  6. 鉴权统一到 OAuth 2.0 + OIDC,移除私有 hack。
  7. 接入 W3C traceparent 做全链路追踪。
  8. 保持双版本并行,按 Mcp-Protocol-Version 灰度,别一次性切。

6.4 生产踩坑清单(15 条)

  1. 别再用 initialize 握手——新规范已移除,旧客户端需走兼容分支,新客户端直接发业务请求。
  2. 无状态 server 不要在内存里存「会话级」变量——每个请求可能打到不同实例,状态必须外置(Redis / DB)或随请求自带。
  3. Mcp-Name 头务必透传——网关漏传会导致后端路由失败或落到默认实例。
  4. tools/list 加缓存前确认幂等——若工具清单含动态内容(按租户不同),缓存 key 必须带租户维度,否则串数据。
  5. 长任务结果别放进程内存——实例重启任务就没了,状态必须进共享存储 / 消息队列。
  6. Tasks 轮询间隔别太短——2s 一次足够,1s 以下会放大网关压力且无必要。
  7. MCP Apps 的 schema 要做版本号——UI 结构变了,旧 Host 可能渲染错,扩展版本协商不能省。
  8. OAuth token 每请求自带——无状态下没有 session 帮你记登录态,漏带 token 必 401。
  9. Discovery 端点要可达——/.well-known/oauth-authorization-server 被墙或超时,整个授权链路断裂。
  10. traceparent 要往下透传——server 内部调下游微服务时记得把 trace 头带下去,否则链路断点。
  11. 完整 JSON Schema 别写太野——虽然支持 anyOf/$defs,但部分旧 Host 的表单生成器未必全支持,关键参数保持简单类型更稳。
  12. 双版本期间日志带协议版本——出问题能快速区分是新核心还是旧兼容分支。
  13. 网关限流维度用 method+name——别只按 IP,否则一个热门 tool 会饿死其他 tool。
  14. SSE 推送代码尽快删除——旧服务端单向推送在新核心已不合法,留着是技术债炸弹。
  15. 监控 tasks/get 的失败率——长任务是用户体验雷区,失败率比 tools/call 更该上告警。

写在最后

MCP 这一刀「拆掉会话」,表面看是删功能,实则是把协议从「能跑的 demo」推向「能扛生产流量的基建」。当 AI 从聊天框走向真实业务流程,连接层的每一分「无状态」,都会变成基础设施的十分「可扩展」。

2026 下半场,谁先把 MCP 跑成无状态、可缓存、可路由、可追踪,谁就先拿到了 agent 规模化的入场券。

本文基于 Anthropic 2026-07-28 第 5 版规范、AWS AgentCore Gateway 与 Cloudflare 官方支持说明整理,代码示例为符合新规范语义的示意实现,落地请以各语言 SDK 正式文档为准。

推荐文章

ElasticSearch 结构
2024-11-18 10:05:24 +0800 CST
使用Python提取图片中的GPS信息
2024-11-18 13:46:22 +0800 CST
阿里云发送短信php
2025-06-16 20:36:07 +0800 CST
JavaScript数组 splice
2024-11-18 20:46:19 +0800 CST
html一份退出酒场的告知书
2024-11-18 18:14:45 +0800 CST
Go 1.23 中的新包:unique
2024-11-18 12:32:57 +0800 CST
程序员茄子在线接单