核心摘要

MCP 2026-07-28 不是 2025 协议的小幅更新,而是进入现代无状态时代:不再使用 initialize 握手、协议级 Session ID、GET Event Stream 和 SSE Resume。每个请求声明 Protocol Version、Client Identity 与 Capability;Server 提供 server/discover;Server-to-client Request 改为 Multi Round-Trip Request Result;可选能力进入协商式 Extension。升级时必须建立 Dual-era 兼容层,不能把它当成一次 Header 改名。

目录

  1. 版本时间线
  2. 现代无状态模型
  3. Streamable HTTP 变化
  4. Multi Round-Trip Request
  5. OAuth 授权变化
  6. Skills 与 Tasks 扩展
  7. Tool 契约与 Cache Hint
  8. 可运行的请求校验器
  9. Dual-era 迁移方案
  10. 一致性与滥用测试
  11. 常见问题
  12. 一手资料

版本时间线

所有 MCP 结论都必须放在固定 Revision 下阅读。2025 某个版本新加入的能力,可能在 2026 被修改、弃用或移除。

版本 高影响变化
2025-03-26 引入 Streamable HTTP、OAuth 授权框架、Tool Annotation 与 JSON-RPC Batching
2025-06-18 移除 JSON-RPC Batching;增加 Structured Tool Output、Protected Resource Metadata、Resource Indicator 与 Elicitation
2025-11-25 增加 OIDC Discovery、Incremental Scope Consent、Client ID Metadata Documents、URL Elicitation 与实验性 Tasks
2026-07-28 移除初始化与协议 Session;增加逐请求 Metadata、server/discover、MRTR、subscriptions/listen、必需 resultType、Cache Hint 与协商式 Extension

这段历史说明了一条工程规则:MCP Version 是 Wire Contract 的组成部分,不是文档元数据。它必须与 SDK、Transport 和 Authorization Profile 版本一起保存。

现代无状态模型

MCP 把 2026-07-28 及之后版本称为 Modern;到 2025-11-25 为止的版本通过 initialize 建立状态,被称为 Legacy。

每个现代请求都包含以下 _meta 字段:

  • io.modelcontextprotocol/protocolVersion
  • io.modelcontextprotocol/clientCapabilities
  • 推荐提供 io.modelcontextprotocol/clientInfo

每个 Result 都包含 resultType。普通结果使用 "complete",MRTR 使用 "input_required",协商后的 Extension 可以加入 "task" 等值。

Server 必须实现 server/discover,发布支持的版本、Capability 和 Identity。Client 可以在普通请求前调用它,也可以先发送首选版本,在收到 UnsupportedProtocolVersionError(-32022)后协商。

sequenceDiagram participant C as Modern Client participant S as MCP Server C->>S: server/discover 携带逐请求 _meta S-->>C: Version、Identity、Capability C->>S: tools/list 携带已选版本 S-->>C: resultType complete 与 Cache Hint C->>S: tools/call 携带已选版本 S-->>C: complete、input_required 或协商后的 task

Stateless 不代表实现不能保存业务状态,而是协议状态不再隐式绑定 Connection 或 Mcp-Session-Id。需要连续性的 Tool 应返回服务端生成的显式 Handle,并通过后续调用参数接收它。

Streamable HTTP 变化

现代 Streamable HTTP 使用一个 Endpoint,每条 JSON-RPC Request 或 Notification 单独发送一次 POST。响应是单个 JSON Object,或绑定当前请求的 SSE Stream。

2026-07-28 移除了:

  • GET Stream Endpoint
  • Mcp-Session-Id
  • SSE Event ID 与 Last-Event-ID Replay
  • 独立的 Server-initiated JSON-RPC Request

新增或强制要求:

  • 每个 POST 都有 MCP-Protocol-Version
  • HTTP Header 版本与请求正文 _meta 版本一致
  • Request 带 Mcp-Method
  • tools/call、resources/read、prompts/get 带 Mcp-Name
  • 关闭当前请求 SSE Response Stream 即表示取消
  • 通过 subscriptions/listen 接收主动订阅的长期变更通知

如果执行中的 SSE Response 断开,Client 不能恢复原 Stream。它必须判断逻辑操作是否适合重新发起,创建新的 JSON-RPC ID,并依赖应用级 Idempotency 防止副作用重复。

Transport Security 仍要求校验 Origin;非法 Origin 必须返回 HTTP 403。本地 Server 应绑定 Loopback,而不是全部网卡。

Multi Round-Trip Request

MRTR 取代过去用于 Sampling、Elicitation 与 Roots 的独立 Server-initiated Request。

当 Server 需要额外输入时:

  1. 返回 resultType: "input_required"
  2. inputRequests 包含一个或多个交互请求
  3. 可选的不透明 requestState 保留服务端关联信息
  4. Client 收集经过批准的响应
  5. Client 使用新的 JSON-RPC ID、inputResponses 与 requestState 重试原 Method

Client 必须按照正常信任与同意机制处理其中的 Model Sampling、User Elicitation 或 Roots Access。MRTR 只改变消息流,不会向 Server 授予这些能力。

需要验证:

  • 每个 Input-request Key 唯一且可识别
  • Retry 使用新 Request ID
  • requestState 按不透明、有界数据处理
  • 重复或已满足的 Key 被拒绝或去重
  • Cancellation 与 Deadline 覆盖完整逻辑操作

OAuth 授权变化

Authorization 对整个 MCP 仍是可选能力。支持授权的 HTTP 实现应遵循 MCP Profile;stdio 实现应从环境获取凭证,而不是执行 HTTP OAuth Flow。

受保护的远程 MCP Server 应遵循:

  1. MCP Server 充当 OAuth Resource Server
  2. 发布 RFC 9728 Protected Resource Metadata
  3. Client 发现并校验 Authorization Server Metadata
  4. Client 获得 Client ID
  5. Authorization 与 Token Request 携带 RFC 8707 resource
  6. 每个 MCP HTTP Request 携带 Authorization: Bearer ...
  7. Server 校验 Issuer、Audience、Expiry、Signature 与 Scope

Client 注册优先级

MCP 2026-07-28 定义的推荐顺序是:

  1. 已存在时使用 Pre-registered Credential
  2. Authorization Server 声明支持时使用 Client ID Metadata Documents
  3. 使用已弃用的 RFC 7591 Dynamic Client Registration 作为兼容回退
  4. 由用户提供 Client 信息

持久化 Client Credential 必须按 Authorization Server Issuer 保存,Issuer 变化后不能复用。Client ID Metadata Document Identifier 是由 Client 自己托管的 HTTPS URL,遵循独立的校验规则。

Scope 与 Issuer 校验

WWW-Authenticate 中存在 Scope 时,应把它视为当前操作的权威需求。Runtime 返回带 insufficient_scope 的 403 时可以触发 Step-up Authorization,但 Client 应请求“新需求与已有 Grant”的并集。

Authorization Server 应返回 RFC 9207 iss,Client 必须把存在的值与跳转前记录的 Issuer 比较。Resource Server 必须拒绝并非签发给自身 Canonical Resource 的 Token。除非 Token Exchange 或其他显式委派设计允许,否则绝不能把收到的 Token 转发给下游服务。

Skills 与 Tasks 扩展

MCP 2026-07-28 引入 extensions Capability Map。只有所需参与方声明支持时,Extension 才能使用。

Skills

io.modelcontextprotocol/skills 通过 Resources 发布 Agent Skills:

  • skills/list 枚举 Skill Entry
  • skills/get 返回单个 Entry
  • resources/read 读取 SKILL.md 与 Supporting File
  • 可选的 resources/directory/read 列举目录子项

Skill Identity 是 Originating Server Identity 与 Skill URI 的二元组。File Digest 在 Acting Window 内保护完整性,但不能证明 Publisher 可信。激活 Nested Skill 需要新的用户同意。

Tasks

io.modelcontextprotocol/tasks 当前扩展 tools/call。Client 声明支持后,Server 可以返回带持久 Task Handle 的 resultType: "task"。Client 随后使用:

  • tasks/get 轮询
  • tasks/update 回答未完成 Input Request
  • tasks/cancel 请求取消

是否创建 Task 由 Server 决定。只有 tasks/get 已能查询到 Task 时,才能返回 Handle。Task ID、TTL、Polling Interval、Authorization 和 Terminal Result 都需要持久存储与 Tenant Isolation。

Tool 契约与 Cache Hint

现代 Tool Descriptor 使用 JSON Schema,并可声明 outputSchema。如果声明了 Output Schema,Server 必须返回符合它的 structuredContent,Client 应执行校验。为了兼容旧版本,Structured Result 还应提供序列化后的 Text Content。

Tool Annotation 仍然只是 Hint,不是安全控制。Read-only、Destructive、Idempotent 与 Open-world 声明不能取代服务端授权或副作用校验。

List 与 Read Result 现在携带:

  • ttlMs:毫秒级 Freshness Hint
  • cacheScope:"public" 或 "private"

Cache Key 仍需包含 Protocol Version、Authorization Context、Origin、Method、Name/URI、Cursor 与相关 Argument。Freshness Hint 不代表 Private Data 可以共享缓存。

x-mcp-header JSON Schema Annotation 可以把指定的原始 Tool Parameter 映射为 Mcp-Param-* HTTP Header。Client 必须拒绝非法 Annotation,也不应把 Secret 或个人信息映射进 Header。

可运行的请求校验器

下面的 Go 标准库程序构造并校验一条现代 tools/list 请求。生产 Client 还要生成匹配的 HTTP Header,并校验完整 Schema;这个示例把逐请求 Metadata 不变量变成可执行检查。

go
package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
)

const protocolVersion = "2026-07-28"

type ClientInfo struct {
	Name    string `json:"name"`
	Version string `json:"version"`
}

type Meta struct {
	ProtocolVersion    string         `json:"io.modelcontextprotocol/protocolVersion"`
	ClientInfo         ClientInfo     `json:"io.modelcontextprotocol/clientInfo"`
	ClientCapabilities map[string]any `json:"io.modelcontextprotocol/clientCapabilities"`
}

type Params struct {
	Cursor string `json:"cursor,omitempty"`
	Meta   Meta   `json:"_meta"`
}

type Request struct {
	JSONRPC string `json:"jsonrpc"`
	ID      int    `json:"id"`
	Method  string `json:"method"`
	Params  Params `json:"params"`
}

func validateRequest(request Request, headerVersion string) error {
	if request.JSONRPC != "2.0" {
		return errors.New("jsonrpc must be 2.0")
	}
	if request.ID == 0 || request.Method == "" {
		return errors.New("request id and method are required")
	}
	if request.Params.Meta.ProtocolVersion != protocolVersion {
		return fmt.Errorf(
			"unsupported protocol version %q",
			request.Params.Meta.ProtocolVersion,
		)
	}
	if headerVersion != request.Params.Meta.ProtocolVersion {
		return errors.New("MCP-Protocol-Version header mismatch")
	}
	if request.Params.Meta.ClientInfo.Name == "" {
		return errors.New("clientInfo.name is required by local policy")
	}
	if request.Params.Meta.ClientCapabilities == nil {
		return errors.New("clientCapabilities must be present")
	}
	return nil
}

func main() {
	request := Request{
		JSONRPC: "2.0",
		ID:      1,
		Method:  "tools/list",
		Params: Params{
			Meta: Meta{
				ProtocolVersion: protocolVersion,
				ClientInfo: ClientInfo{
					Name:    "example-client",
					Version: "1.0.0",
				},
				ClientCapabilities: map[string]any{
					"extensions": map[string]any{},
				},
			},
		},
	}

	if err := validateRequest(request, protocolVersion); err != nil {
		log.Fatal(err)
	}
	body, err := json.MarshalIndent(request, "", "  ")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(body))
}

该请求还需要以下 HTTP Header:

http
POST /mcp HTTP/1.1
Content-Type: application/json
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/list

调用 tools/call 时还要根据 params.name 添加 Mcp-Name。HTTP Version 与 Body Version 必须一致。

Dual-era 迁移方案

1. 盘点真实行为

记录每个 Client 和 Server 的 Protocol Revision、SDK Version、Transport、Authorization Profile、Extension、Session 使用、Server-initiated Request、Streaming 与 Retry 行为。不能仅根据 Package Version 推断支持范围。

2. 建立协议边界

集中处理 Version Detection、Request Metadata、Header、Result Decoding 与 Transport Behavior。业务 Tool 不应感知 Peer 属于 Modern 还是 Legacy。

3. 实现现代行为

增加 server/discover、逐请求 Metadata、必需 HTTP Header、resultType、Request-scoped Streaming、MRTR、Subscription Stream、Cache Hint 与选定 Extension。

4. 隔离 Legacy 行为

Dual-era 实现只能在 Transport-specific Probe 判定对端是 Legacy Server 后,才回退到 initialize 与旧 Streamable HTTP。按 stdio Process 或 HTTP Origin 缓存 Era,假设失效时重新探测。

5. 移除隐式 Session State

用显式、服务端生成并作为普通参数传递的 Handle 替代 Mcp-Session-Id 状态。每个 Handle 都要绑定 Identity、Tenant、Expiry 与 Operation Class。

6. Shadow 与 Canary

对两条路径回放脱敏的一致性语料,比较逻辑结果、授权决策、Stream 行为、Retry 与副作用。只向小比例流量启用 Modern Mode,并保留独立回滚。

7. 以证据淘汰 Legacy

测量真实 Client Version 与 Negotiation Failure。公布停止支持时间,返回可操作错误;只有受支持流量达到约定阈值后,才删除 Legacy Code。

一致性与滥用测试

范围 必测项目
Versioning 支持版本、Unsupported Version List、Body/Header Mismatch
Lifecycle 无 initialize 的现代请求、Legacy Fallback、Ambiguous Error
Transport JSON Response、SSE Response、Close-as-cancel、无 Replay
MRTR 新 Request ID、不透明 State、重复 Key、用户拒绝输入
Subscription Opt-in Type、Subscription ID、Disconnect Cleanup
Authorization Metadata Discovery、Resource/Audience、Issuer Binding、Scope Step-up
Tools Schema Validation、Output Validation、Annotation Distrust、Deterministic List
Caching TTL Expiry、Private Scope、Auth-aware Key、List-change Invalidation
Skills Origin + URI Identity、Digest Mismatch、Nested Consent、Path Traversal
Tasks Capability Gate、Durable Creation、Poll Interval、Tenant Isolation、Cancellation
Side Effect Idempotency、Broken Stream Retry、Duplicate Request Protection

必须用真实 SDK 组合运行测试矩阵。只验证 Schema,不能证明 Proxy、Cancellation、Authentication 或重复副作用安全。

常见问题

2026 Client 可以发送 initialize 做兼容吗?

Dual-era Client 可以按 Transport-specific Rule 探测并回退;Modern-only Client 不使用 initialize。不要在同一执行路径上同时试探性发送 Modern 与 Legacy Lifecycle Message。

Stateless MCP 会移除全部服务端状态吗?

不会。它移除的是隐式协议 Session State。Server 仍可保存 Business State、Job、Subscription、Cache 或显式 Handle,但这些对象必须遵循正常的 Identity、Authorization、Expiry 与 Lifecycle Rule。

SSE 被移除了吗?

没有。Streamable HTTP 仍可返回绑定请求的 SSE Stream,subscriptions/listen 也使用长期 SSE Response。被移除的是独立 GET Stream、协议 Session,以及通过 Event ID 恢复 SSE。

Cache Hint 可以跨用户信任吗?

只有结果公开且完整 Cache Key 与授权无关时才可以。cacheScope: "private" 不能进入共享缓存;Public Data 仍需包含 Version、Origin、Method、Name、Cursor 与 Argument 维度。

Skill 是可执行代码吗?

Skill 是包含指令与配套 Resource 的目录。它可以引用 Script,但是否以及如何执行由 Host 决定。MCP Skills Extension 只负责传输文件,不会绕过用户同意、Sandbox 或 Tool Authorization。

总结

MCP 2026-07-28 建立了更清晰的无状态协议,但它也是实际的兼容边界。现代请求自带 Version 与 Capability,HTTP Stream 绑定单次请求,额外交互使用 MRTR,Skills 与 Tasks 等可选系统通过 Extension 协商。迁移必须包含明确 Era Detection、严格 OAuth Binding、幂等重试与完整一致性矩阵。

相关资源

一手资料