主题
版本管理与兼容性
本页定义了客户端与服务端如何就双方所使用的协议达成一致:协议版本,在每个请求上声明;可选的扩展,通过能力进行协商;以及与更早的、基于握手的协议修订版的互操作性。
不存在协商握手。每个请求都携带其协议版本,服务端独立地接受或拒绝每个请求:
sequenceDiagram
participant Client
participant Server
Client->>Server: request (with `_meta`)
alt server supports requested version
Server-->>Client: result
else version unsupported
Server-->>Client: UnsupportedProtocolVersionError
Note over Client,Server: Client retries with a mutually supported version
end
术语
本页使用以下术语来描述跨协议修订版的互操作性:
- 现代(Modern):以逐请求元数据的形式传递版本、身份与能力的协议版本(修订版
2026-07-28及之后)。 - 传统(Legacy):通过
initialize握手建立会话的协议版本(2025-11-25及之前)。 - 双时代(Dual-era):同时支持现代与传统版本的实现。
协议版本协商
每个请求都在其 _meta 字段中声明所使用的协议版本。在 HTTP 上,该版本还会通过 MCP-Protocol-Version 头 传递。
如果服务端未实现所请求的版本(无论该版本对服务端而言是未知的,还是已知但服务端选择不支持),它 MUST(必须)返回一个 UnsupportedProtocolVersionError,并列出其确实支持的版本:
json
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32022,
"message": "Unsupported protocol version",
"data": {
"supported": ["2026-07-28", "2025-11-25"],
"requested": "1900-01-01"
}
}
}客户端 SHOULD(应该)从 supported 列表中选择一个双方都支持的版本并重试该请求;如果不存在兼容版本,则向用户呈现错误。
服务端 MUST(必须)实现 server/discover。客户端 MAY(可以)在发送任何其他请求之前调用它,以提前获知服务端支持的版本,但并非必须:客户端可以自由地内联调用任何 RPC,并在其首选版本不受支持时处理 UnsupportedProtocolVersionError。
扩展协商
客户端与服务端可以协商对核心协议之外的可选扩展的支持。扩展通过能力中的 extensions 字段进行通告,该字段是扩展标识符到各扩展设置对象的映射。扩展标识符 MUST(必须)遵循 _meta 键命名规则,并带有强制前缀。
以下是一个客户端通告 MCP Apps 扩展(标识为 io.modelcontextprotocol/ui)的示例:
json
{
"capabilities": {
"roots": {},
"extensions": {
"io.modelcontextprotocol/ui": {
"mimeTypes": ["text/html;profile=mcp-app"]
}
}
}
}以下是一个 Tasks 扩展(标识为 io.modelcontextprotocol/tasks)的示例:
json
{
"capabilities": {
"tools": {},
"extensions": {
"io.modelcontextprotocol/tasks": {}
}
}
}每个扩展都规定其设置对象的 schema;空对象表示支持该扩展且无额外设置。
如果一方支持某个扩展而另一方不支持,支持的一方 MUST(必须)要么回退到核心协议行为,要么以适当的错误拒绝该请求。扩展 SHOULD(应该)记录其预期的回退行为。
与基于初始化的版本的向后兼容性
希望同时支持传统客户端(期望 initialize 握手)和现代客户端(使用逐请求元数据)的服务端 MAY(可以)同时实现这两种行为。
需要与这两类服务端互操作的客户端,通过传输特定的机制来检测服务端所属的时代,具体规定见各绑定页面:
- stdio:用
server/discover进行探测,并在遇到任何不属于可识别的现代错误时回退。 - Streamable HTTP:尝试一个现代请求,并在回退之前检查
400 Bad Request的响应体。
在这两种情况下,一个可识别的现代 JSON-RPC 错误(例如 UnsupportedProtocolVersionError)表明这是一个现代服务端:客户端应使用受支持的版本重试,而不是回退。其他任何情况都表明这是一个传统服务端。
时代的判定是服务端的属性,而不是单个请求的属性。客户端 SHOULD(应该)在服务端进程(stdio)或源(HTTP)的生命周期内缓存该结果,并且 MAY(可以)在同一服务端配置的多次重启之间持久化该结果,若缓存的假设之后失效则重新探测。
仅支持现代版本的服务端 SHOULD(应该)在任何传输上、对 initialize 请求返回的任何错误中,列出其支持的协议版本:传统客户端没有向前回退机制,这条消息可能是它们能向用户呈现的唯一诊断信息。
兼容性矩阵
下表汇总了客户端与服务端各时代(era)组合的预期结果:
| Client | Server | Outcome |
|---|---|---|
| Modern | Modern | 可用。server/discover 是可选的;版本不匹配会以 UnsupportedProtocolVersionError 的形式暴露,客户端随后使用双方都支持的版本重试。 |
| Modern | Legacy | 失败。服务端可能以实现自定义的错误拒绝请求、保持静默,甚至按传统语义处理时代不明确的方法。在 stdio 上,客户端 SHOULD(应该)先发送 server/discover 以确定性地失败;随后客户端向用户呈现可操作的错误。 |
| Dual-era | Modern | 可用。stdio 探测返回 DiscoverResult(或 UnsupportedProtocolVersionError);在 HTTP 上,首个现代请求成功或返回现代错误。客户端保持现代。 |
| Dual-era | Legacy | 可用。stdio:探测返回非现代错误或超时,客户端回退到 initialize。HTTP:现代请求返回 4xx 且响应体不是可识别的现代错误,客户端回退到 initialize(并可能进一步回退到已弃用的 HTTP+SSE 传输)。 |
| Legacy | Modern | 失败。stdio:服务端以 JSON-RPC 错误拒绝 initialize;具体错误码由实现定义(initialize 是未知方法,且请求也缺少必需的 _meta 字段)。HTTP:请求缺少必需的请求头,按服务端校验被拒绝并返回 400 Bad Request(使用已弃用的 HTTP+SSE 传输的客户端则在其初始 GET 时失败)。传统客户端没有向前回退机制。 |
| Legacy | Dual-era | 可用。服务端响应 initialize,并按协商的传统修订版为客户端提供服务。 |
| Legacy | Legacy | 按传统修订版可用;不在本文档讨论范围内。 |
双时代 服务端 根据客户端如何开启连接来选择其行为:
- 携带现代逐请求
_meta的请求按本修订版以无状态方式处理。 initialize请求选择传统语义,其作用域为 stdio 进程(stdio)或会话(HTTP),具体由协商的传统协议版本规定。
双时代服务端 MAY(可以)在同一端点或进程上同时服务两个时代。