Model Context Protocol 迎来诞生以来最大规模修订,五大核心变更将深刻改变 MCP 生态的开发范式。

1. MCP 2026-07-28 协议变更总览

MCP(Model Context Protocol)自发布以来一直是 AI Agent 与外部工具交互的事实标准。2026-07-28 版本带来了协议诞生以来最大规模的修订,涉及传输层、会话模型、SDK 分层、诊断能力和配置机制五个维度。以下是核心变更速览:

变更项影响级别涉及范围
Streamable HTTP 统一端点Breaking所有传输层实现
无状态会话模型BreakingServer 初始化与状态管理
SDK Tier 体系新增SDK 选型与依赖管理
mcp_server_errors 事件新增诊断与错误报告
workflowSizeGuideline 配置键新增动态工作流资源管理

其中前两项属于 Breaking Changes,现有 MCP Server 和 Client 如果不做适配将无法与新版协议兼容。Claude Code v2.1.219 已率先支持新版协议特性,Claude Opus 5 的发布也进一步推动了生态对新协议的采纳——同价位下 2.5x Fast Mode 的能力提升使得实时 MCP 交互的延迟敏感度大幅降低,让 Streamable HTTP 的优势更加明显。

2. Streamable HTTP 迁移:从 stdio 到统一端点

2.1 为什么废弃 stdio/SSE 双通道

旧版 MCP 协议提供两种传输方式:stdio(通过标准输入输出通信)和 SSE(Server-Sent Events 长连接)。这两种方式各自有明显的局限性:

  • stdio:进程绑定,无法跨网络部署,调试困难,且不支持多客户端并发连接
  • SSE:需要独立的 HTTP 服务器,配置繁琐,连接管理复杂,且与 HTTP/2 不兼容

Streamable HTTP 是新版协议引入的统一传输方案,用一个 HTTP 端点同时支持请求-响应和流式推送。它的核心优势在于:

  1. 单一端点:所有 MCP 交互通过一个 HTTP POST 端点完成,包括初始化、工具调用、资源读取和流式通知
  2. 网络原生:支持跨机器部署、负载均衡和代理转发,天然适配云原生架构
  3. HTTP/2 兼容:利用多路复用特性,在同一 TCP 连接上并行处理多个 MCP 会话
  4. 渐进式流式:通过 Transfer-Encoding: chunked 实现流式响应,适用于长时间运行的工具调用

2.2 传输层对比

旧模型(stdio + SSE 双通道):

  Client ──stdio──> MCP Server Process
  Client ──SSE────> MCP HTTP Server (独立进程)

新模型(Streamable HTTP 统一端点):

  Client ──HTTP POST──> /mcp (单一端点,支持请求/响应 + 流式推送)

3. 无状态会话改造指南

3.1 旧版有状态模型的问题

旧版 MCP 在 initialize 握手后会维持一个长期会话状态,Server 在内存中保存客户端能力、协商结果等上下文信息。这种设计导致以下问题:

  • Server 进程重启后所有会话丢失,客户端必须重新初始化
  • 多实例部署时无法共享会话状态
  • 内存泄漏风险:长期运行的服务器中积累的会话状态难以回收

3.2 新版无状态模型

新版协议中,initialize 握手完成后不再维持会话状态。每次请求携带完整的上下文信息,Server 可以根据请求内容独立处理。这意味着:

  • Server 无状态:每个请求都是自包含的,便于水平扩展
  • 初始化结果可缓存:客户端可以将 initialize 的响应缓存到本地,后续请求中复用
  • 容错性提升:Server 重启对客户端透明,无需重新握手

改造的关键点在于将原本依赖内存状态的数据改为显式传递或外部存储。

4. SDK Tier 体系详解

新版 MCP 引入了 SDK Tier 分层体系,将 SDK 按功能丰富度划分为三个层级:

Tier名称适用场景核心能力
Core核心层轻量级工具接入基础 transport、tool 定义、JSON-RPC
Standard标准层大多数生产场景Core + 资源管理、提示词模板、采样支持、日志
Enterprise企业层复杂企业集成Standard + 认证授权、审计日志、限流策略、多租户

选择建议:

  • 如果你的 MCP Server 只暴露 1-3 个简单工具,Core 层即可满足需求,依赖包体积最小
  • 如果需要暴露资源、提示词模板或日志能力,选择 Standard
  • 如果涉及企业内部系统对接,需要鉴权和审计,则应选择 Enterprise

SDK Tier 之间向下兼容,即 Enterprise SDK 可以运行 Core 层的所有功能。

5. 新增诊断事件 mcp_server_errors

5.1 问题背景

在 Claude Desktop 等宿主环境中,用户可能在配置文件中声明多个 MCP Server,但其中部分 Server 因依赖缺失、版本不匹配或配置错误而启动失败。旧版协议中,这类启动失败通常是静默的,用户需要手动检查日志才能发现问题。

5.2 新事件机制

mcp_server_errors 是一个在宿主启动时触发的诊断事件,用于报告被跳过或启动失败的 MCP 配置。事件结构如下:

{
  "event": "mcp_server_errors",
  "timestamp": "2026-07-28T10:00:00Z",
  "errors": [
    {
      "serverName": "my-postgres-tools",
      "configPath": "~/.claude/mcp_servers.json",
      "errorType": "STARTUP_FAILURE",
      "message": "Failed to connect to PostgreSQL: connection refused",
      "severity": "ERROR"
    },
    {
      "serverName": "legacy-filesystem-tools",
      "configPath": "~/.claude/mcp_servers.json",
      "errorType": "SKIPPED",
      "message": "Transport type 'stdio' is deprecated, server skipped",
      "severity": "WARNING"
    }
  ]
}

宿主客户端可以监听此事件,在 UI 中向用户展示友好的错误提示,而非让问题静默失败。这对于企业级部署中管理数十个 MCP Server 的场景尤为重要。

6. 完整迁移代码示例(Python MCP Server)

以下代码展示如何将一个旧版 stdio MCP Server 迁移为 Streamable HTTP 方式。代码可直接复制运行。

6.1 旧版 stdio 实现(迁移前)

# old_server.py - 旧版 stdio MCP Server
import json
import sys
from mcp.server.stdio import stdio_server

@stdio_server()
async def serve():
    async with asyncio.TaskGroup() as tg:
        # 在 stdio 模式下,通过标准输入输出通信
        # Server 进程由 Claude Desktop 启动和管理
        pass

async def handle_tool_call(name: str, arguments: dict):
    if name == "get_weather":
        city = arguments.get("city", "Beijing")
        return {"temperature": 28, "city": city}
    elif name == "calculate":
        expression = arguments.get("expression", "")
        try:
            result = eval(expression)
            return {"result": result}
        except Exception as e:
            return {"error": str(e)}

6.2 新版 Streamable HTTP 实现(迁移后)

# new_server.py - 新版 Streamable HTTP MCP Server
import asyncio
import json
from mcp.server.streamable_http import streamable_http_server
from mcp.types import Tool, TextContent

# 定义工具列表
TOOLS = [
    Tool(
        name="get_weather",
        description="获取指定城市的天气信息",
        inputSchema={
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "城市名称"
                }
            },
            "required": ["city"]
        }
    ),
    Tool(
        name="calculate",
        description="执行数学表达式计算",
        inputSchema={
            "type": "object",
            "properties": {
                "expression": {
                    "type": "string",
                    "description": "数学表达式,如 '2 + 3 * 4'"
                }
            },
            "required": ["expression"]
        }
    ),
]

async def handle_request(method: str, params: dict | None) -> dict | None:
    """处理 MCP JSON-RPC 请求(无状态)"""
    if method == "initialize":
        return {
            "protocolVersion": "2026-07-28",
            "capabilities": {
                "tools": {"listChanged": False}
            },
            "serverInfo": {
                "name": "weather-calculator",
                "version": "2.0.0"
            }
        }

    elif method == "tools/list":
        return {"tools": TOOLS}

    elif method == "tools/call":
        tool_name = params.get("name") if params else None
        arguments = params.get("arguments", {}) if params else {}

        if tool_name == "get_weather":
            city = arguments.get("city", "Beijing")
            return {
                "content": [
                    TextContent(
                        type="text",
                        text=json.dumps({
                            "city": city,
                            "temperature": 28,
                            "condition": "sunny",
                            "humidity": 65
                        }, ensure_ascii=False)
                    )
                ]
            }

        elif tool_name == "calculate":
            expression = arguments.get("expression", "")
            try:
                # 注意:生产环境应使用安全的表达式解析器
                result = eval(expression, {"__builtins__": {}}, {})
                return {
                    "content": [
                        TextContent(
                            type="text",
                            text=f"计算结果: {expression} = {result}"
                        )
                    ]
                }
            except Exception as e:
                return {
                    "content": [
                        TextContent(
                            type="text",
                            text=f"计算错误: {str(e)}"
                        ),
                        TextContent(
                            type="text",
                            text="请检查表达式格式是否正确"
                        )
                    ],
                    "isError": True
                }

    return None

async def main():
    """启动 Streamable HTTP MCP Server"""
    server = streamable_http_server(
        host="0.0.0.0",
        port=8765,
        endpoint="/mcp",
        request_handler=handle_request,
    )
    print("MCP Streamable HTTP Server 启动于 http://localhost:8765/mcp")
    print("支持的协议版本: 2026-07-28")
    print("可用工具: get_weather, calculate")
    await server.serve()

if __name__ == "__main__":
    asyncio.run(main())

6.3 对应的 Claude Desktop 配置

{
  "mcpServers": {
    "weather-calculator": {
      "type": "streamable-http",
      "url": "http://localhost:8765/mcp"
    }
  }
}

6.4 迁移要点总结

迁移项旧版新版
传输方式stdio_server()streamable_http_server()
服务器形态子进程独立 HTTP 服务
状态管理内存中维持会话每次请求自包含
部署方式Claude Desktop 启动任意 HTTP 服务器
多客户端不支持天然支持

7. 向后兼容策略

如果你维护的 MCP Server 需要同时服务旧版和新版客户端,建议采用以下兼容策略:

双传输层并行:在同一个 Server 中同时暴露 stdio 和 Streamable HTTP 两个端点,根据客户端类型自动路由。

async def main():
    # 同时启动 stdio 和 HTTP 端点
    http_server = streamable_http_server(
        host="0.0.0.0",
        port=8765,
        endpoint="/mcp",
        request_handler=handle_request,
    )
    stdio_task = asyncio.create_task(stdio_serve(handle_request))

    await http_server.serve()

协议版本协商:在 initialize 响应中根据客户端声明的协议版本动态调整行为。如果客户端发送的是旧版本号(如 2024-11-05),则回退到有状态模式。

async def handle_request(method: str, params: dict | None) -> dict:
    if method == "initialize":
        client_version = params.get("protocolVersion", "2024-11-05")
        if client_version.startswith("2024"):
            # 兼容旧版客户端:启用有状态模式
            return {
                "protocolVersion": "2024-11-05",
                "capabilities": {"statefulSession": True},
                "serverInfo": {"name": "compatible-server", "version": "2.0.0"}
            }
        else:
            # 新版客户端:无状态模式
            return {
                "protocolVersion": "2026-07-28",
                "capabilities": {"tools": {"listChanged": False}},
                "serverInfo": {"name": "compatible-server", "version": "2.0.0"}
            }

渐进式迁移路线图

  1. 第一阶段:部署双端点 Server,新旧客户端均可正常工作
  2. 第二阶段:在 mcp_server_errors 事件中标记仍在使用 stdio 的客户端
  3. 第三阶段:当旧版客户端比例低于 5% 时,移除 stdio 端点
  4. 第四阶段:全面切换到 Streamable HTTP + 无状态模式

8. 常见问题 FAQ

Q1: 迁移到 Streamable HTTP 后,本地开发的 MCP Server 怎么调试?

新版 SDK 提供了内置的调试模式,可以通过 --debug 标志启动。启用后会在控制台输出详细的请求/响应日志,并通过 /debug 端点暴露健康检查和请求历史。同时,Claude Code artifacts 现在可以通过 MCP connectors 变成 live apps,这意味着你可以在 Claude Code 中直接调试 MCP Server 的实时行为,而不需要额外的 HTTP 客户端工具。

Q2: 无状态会话是否意味着所有状态都必须外部化?

不完全是。initialize 阶段的协商结果(如客户端能力声明)仍然可以缓存在 Server 端,但缓存不应影响请求的正确性。换句话说,即使缓存丢失,Server 也能根据请求中的信息正确处理。需要外部化的是那些影响业务逻辑的状态,例如用户的认证 token、对话上下文等。

Q3: workflowSizeGuideline 配置键具体有什么用?

workflowSizeGuideline 是新增的配置键,用于向 Claude 等 AI Agent 提供动态工作流的大小建议。当 MCP Server 暴露的工具链较长或单次调用涉及大量数据传输时,可以通过此配置指导 Agent 控制并发请求数量和分批策略。例如:

{
  "workflowSizeGuideline": {
    "maxConcurrentTools": 5,
    "maxPayloadSize": "10MB",
    "recommendedBatchSize": 3
  }
}

这有助于 Agent 在复杂工作流中避免资源耗尽和超时。

Q4: Claude Opus 5 的 2.5x Fast Mode 对 MCP 开发有什么实际影响?

Fast Mode 的提升显著降低了 MCP 交互的感知延迟。以前在 stdio 模式下,工具调用的序列化/反序列化开销相对不明显;但在 Streamable HTTP 模式下,网络往返时间成为瓶颈。Opus 5 的 2.5x 加速让即使经过网络传输的工具调用也能保持流畅的用户体验,这使得 Streamable HTTP 在实际使用中不再有明显的速度劣势。

Q5: 旧版的 MCP Server 配置文件需要修改吗?

如果你的 MCP Server 是由 Claude Desktop 通过 stdio 启动的,需要将配置文件中的 type"stdio" 改为 "streamable-http",并添加 url 字段指向新的 HTTP 端点。对于由 Claude Code 使用的 MCP Server,同样需要更新 mcp_servers.json 中的传输配置。


总结:MCP 2026-07-28 协议升级是一次全面的架构演进。Streamable HTTP 统一端点消除了传输层的分裂,无状态会话模型为水平扩展扫清了障碍,SDK Tier 体系让开发者能按需选择合适的复杂度,诊断事件和配置机制的完善则提升了企业级部署的可运维性。建议所有 MCP Server 维护者在 2026 年 Q3 内完成迁移评估,并利用双端点兼容策略平滑过渡。