协议世代

社区译文;来源: MCP 80041ab0

MCP 的 2026-07-28 修订对协议做了大量改动。因此 Inspector 把协议世代(legacy 或 modern,即该修订之前或自该修订起)当作与传输方式正交的、逐服务器的一等设置:同一个 HTTP URL 既可以作为 legacy 服务器检查,也可以作为 modern 服务器检查。若干标签页会根据生效的世代渲染出明显不同的 UI 与流量。

Protocol Era 设置

每个服务器都带有一个 protocolEra,取值为 legacy、auto 或 modern。在 web 客户端中它位于 Server Settings;在 catalog 或配置文件中它是 protocolEra 字段;CLI 和 TUI 从同一文件读取它,而它们的 --protocol-era <legacy|auto|modern> flag 可在单次运行中覆盖它。

世代Inspector 在连接时的行为
legacy默认值。 直接 initialize,完全不做探测。
auto先探测 server/discover,遇到任何非 modern 结果都回退到 initialize。
modern精确固定为 2026-07-28。没有回退,因此非 modern 服务器会显式失败。
为什么默认是 legacy 而不是 auto。 调试工具绝不能自动探测。server/discover 探测会在沉默的 legacy stdio 服务器上卡住,而且会污染你本想来读的录制对话。选择加入 auto 或 modern 是一个深思熟虑的动作,因此你在 Protocol 标签页中看到的内容,正是你的服务器在按你的配置行为的客户端那里会看到的内容。

连接后,协商得到的世代会作为徽章显示在 Protocol 标签页的 Messages 标题栏和 Connection Info 中。在 modern 连接上,server/discover 还会提供 capabilities(包括 extensions)、instructions 以及 supportedVersions 列表。服务器的名称和版本以 io.modelcontextprotocol/serverInfo 的形式出现在结果的 _meta 中。

在本地复现各个世代

下面每一节都以一个 Reproduce with … 提示结尾,指向 Inspector 仓库中附带的某个可组合测试服务器的 JSON 配置。请克隆仓库并构建这些测试服务器:

git clone https://github.com/modelcontextprotocol/inspector
cd inspector && npm install && npm run build
cd clients/web && npm run test-servers:build && cd ../..

然后从仓库根目录,用某一节命名的配置启动服务器:

node test-servers/build/server-composable.js --config test-servers/configs/<name>.json

服务器会在 stderr 上打印其 URL。如果配置中的端口已被占用,它会绑定下一个空闲端口,因此请使用打印出来的 URL,而不要假定端口。把该 URL 作为服务器添加到 Inspector 中,并使用该节所述的 Protocol Era。


日志

Legacy

日志是会话作用域的。客户端发送一次 logging/setLevel,服务器便在该会话余下时间里发出不低于该级别的 notifications/message。

Logs 标签页显示一个 Set Active Level 选择器和一个 Set 按钮。选择一个级别,点击 Set,后续的服务器日志便会流入面板。

用 test-servers/configs/logging-legacy-http.json 复现。

Modern

logging/setLevel 已不存在。客户端改为逐请求选择加入:在每个出站请求上打上 _meta["io.modelcontextprotocol/logLevel"]。对于未选择加入的请求,服务器 MUST NOT 发出 notifications/message。

因此 Logs 标签页改为显示一个 Log Level per Request 控件。选定一个级别后,后续每个请求都会带上该标记,可在 Network 标签页的请求体中看到。处理某个请求时发出的日志会随该请求的 SSE 响应流一起返回。

把控件设为 Off,logLevel 键就会被完全省略,因此同一次工具调用完全不产生日志。这种沉默是正确行为,而不是缺陷。

逐服务器默认值是 debug(即在最详细级别选择加入,因为 Inspector 是调试工具);在某个服务器上设置 modernLogLevel: "off" 即可默认退出。

用 test-servers/configs/logging-modern-http.json 复现。


资源订阅

Legacy

在某个资源上点击 Subscribe 会发送 resources/subscribe。Subscriptions 区域会列出该 URI,不带任何流状态装饰。资源变化时,服务器发出 notifications/resources/updated,被订阅条目的"最后更新时间"随之刷新。

用 test-servers/configs/subscriptions-legacy-http.json 复现,它还提供一个 update_resource 工具,让你可以自己驱动通知往返。

Modern

同一个 Subscribe 按钮改为发送 subscriptions/listen,其过滤器携带 resourceSubscriptions 以及适用的 *ListChanged 选择加入项(例如 resourcesListChanged)。当服务器发送 notifications/subscriptions/acknowledged 时,订阅即被确认。

由于订阅现在是一条长期存活的流而非会话标志,Subscriptions 区域的标题栏会多出一个流状态徽章,从 Connecting... 变为 Listening。若流中断,徽章会显示 Reconnecting...,同时 Inspector 重新发送 subscriptions/listen。流彻底关闭后显示 Stream ended。当服务器对一个 listen 只返回普通结果而从不发送确认时,显示 Not acknowledged;此时 Inspector 不会重试。

用 test-servers/configs/subscriptions-modern-http.json 复现。要看到 Not acknowledged 状态,请使用 test-servers/configs/subscriptions-never-acknowledged-http.json。该服务器会确认你的第一次订阅,但拒绝之后每一次 listen,因此订阅第二个资源就会触发该徽章。


任务

任务在各协议世代之间变化最大,包括 Inspector UI 标签页的显示条件 也变了。

Legacy

当服务器声明 capabilities.tasks 时,Tasks 标签页会出现。启用 Run as task 运行一个工具,标签页会列出它,数据由 tasks/list 填充并轮询 tasks/get。完成后的负载通过阻塞的 tasks/result 获取,Cancel 发送 tasks/cancel。

用 test-servers/configs/tasks-legacy-http.json 复现。

Modern

任务是一个扩展(io.modelcontextprotocol/tasks,SEP-2663(英文)),因此该标签页的显示条件是服务器声明该扩展,而不是 capabilities.tasks。

以任务方式运行一个工具后,tools/call 会返回 CreateTaskResult(resultType: "task",可在 Protocol 和 Network 标签页中看到)。Inspector 只轮询 tasks/get;不存在 tasks/list,因此 Refresh 会重新轮询客户端已知的那些句柄。完成的任务会内联其结果,无需阻塞调用 tasks/result。

需要更多信息的任务会转到 input_required,并在待处理请求模态框(web 客户端在任何有请求等待你时会打开的对话框)中呈现一个内嵌的信息征询。回答它会发送携带 inputResponses 的 tasks/update,下一次轮询即完成。

用 test-servers/configs/tasks-modern-http.json 复现(工具为 modern_task 和 modern_input_task)。


多轮工具结果(MRTR)

在 modern 世代,工具可以返回 input_required 而不是最终结果,其中内嵌了一个信息征询、一个采样请求或一个 roots/list 请求。客户端回答该内嵌请求,并在新的 JSON-RPC id 下重试 tools/call,直到调用达到 complete。

Inspector 手动驱动 MRTR,因此每一轮都会暂停在标记为 input_required 的待处理请求模态框,等你作答。Protocol 视图会把整个交互归组为一次 MRTR 对话,而不是互不相关的调用。

test-servers/configs/mrtr-showcase-http.json 在一个 modern 服务器中打包了所有形态:

工具它演练的内容
mrtr_confirm单轮信息征询。
mrtr_two_step两轮信息征询,通过 requestState 串联。
mrtr_sample内嵌的采样请求,路由到 Sampling 面板。
mrtr_roots内嵌的 roots/list,从已配置的 roots 静默作答(无模态框)。
mrtr_edge一轮只有 inputRequests,随后一轮只有 requestState。
mrtr_empty一轮信息征询,然后以空结果完成(无 content,无 structuredContent)。
mrtr_loop永不完成,因此客户端会在其 MRTR_MAX_ROUNDS 上限处停止。
服务器调用 server.elicitInput 的 legacy 模式(测试服务器的 collect_elicitation 预设)在 2026-07-28 连接上会报错,因为那里不允许服务器到客户端的请求。MRTR 是它的 modern 替代方案。


工具:镜像 header 与被排除的工具

SEP-2243(英文) 允许工具用 x-mcp-header 标注某个参数,要求 Streamable HTTP 客户端把该参数的值镜像到一个 Mcp-Param-* 请求 header 中。

Inspector 在 Tools 标签页中呈现这项约定的两方面:

  • 带有合法标注的工具,其详情面板会显示一个 “Mirrored request headers (SEP-2243)” 区域,例如 city -> Mcp-Param-City。
  • 带有非法标注的工具(比如 header 名为 "Bad Header",其中的空格使其不是合法的 RFC 9110 token)会在侧边栏中以删除线出现在 “Excluded (SEP-2243)” 分隔之下,悬停时显示原因。符合规范的客户端 MUST 把这类工具从 tools/list 中丢弃;Inspector 会告诉你它为什么被丢弃,而不是默默隐藏。

用 test-servers/configs/xmcpheader-modern-http.json 复现。

在 modern 连接上,Inspector 会在三个客户端中都自行把 x-mcp-header 参数镜像到 Mcp-Param-* headers。在 web 客户端中,headers 由 Inspector 发起上游请求的 Node 后端添加,因此即使浏览器从不发送它们,它们也能到达服务器。

-32602 错误面板

以 -32602 拒绝的 tools/call 在任一世代都会渲染为一个独立的错误面板:

  • Unknown Tool:消息指出的工具不在服务器的列表中。在服务器的 tools/list 中不存在的任意名称上调用即可复现。
  • Invalid Parameters:其他任何 -32602。用上面配置中的 trigger_invalid_params 工具复现。

两者共用一个错误码,因此 Inspector 通过读取消息来区分它们。其他任何错误码都渲染为一般性失败。


Network 与 Protocol:headers 与错误分类

modern 世代标准化了一组 Mcp-* HTTP headers,并引入了更丰富的 JSON-RPC 错误分类(SEP-2243(英文) / SEP-2575(英文))。两个监控标签页分工如下:

  • Network 标签页是 HTTP 视图:镜像的 Mcp-* headers 会被高亮,哨兵值会被解码。
  • Protocol 标签页是 JSON-RPC 视图:每种规范错误都独立渲染,而不是笼统的失败。

test-servers/configs/modern-network-http.json 提供四个工具,每个类别一个,各自产生真实的 HTTP 状态码加 JSON-RPC 错误体:

工具HTTPJSON-RPC 代码含义
trigger_header_mismatch400-32020缺少或错误了必需的镜像 header。
trigger_missing_capability400-32021请求遗漏了服务器要求的某项客户端能力。
trigger_unsupported_version400-32022不支持的版本;受支持版本在 data.supported 中。
trigger_method_not_found404-32601方法不存在。


取消

在 legacy 连接上,取消一个进行中的工具调用会发送 notifications/cancelled。在 modern Streamable HTTP 连接上,Inspector 改为关闭该请求自己的 SSE 响应流,这就是 2026-07-28 的取消信号。在 stdio 上,取消仍然是 notifications/cancelled。

用 test-servers/configs/cancellation-modern-http.json 复现:运行 slow_task,几秒后点击 Cancel,服务器的终端会打印该任务在停止前推进到了哪一步。


会话

legacy Streamable HTTP 连接可能携带服务器分配的会话 id(Mcp-Session-Id),客户端用 HTTP DELETE 将其拆除。modern 连接是无会话且逐请求的:没有会话 id 时客户端 SDK 不会向服务器发送 DELETE,因此断开完全发生在本地。

legacy 连接还会在 initialize 之后打开一条独立的 GET 通知流,用来承载不属于任何请求的通知。Server Settings 中仅适用于 legacy 的 Suppress Notification Stream 选项会跳过该流,因此你可以检查无法同时服务第二个请求的服务器。modern 连接从不打开该流,因此该选项对它们不适用。

这对你自己的测试服务器有实际影响。逐请求构造的无状态 modern 处理器无法在调用之间保持状态,这正是 test-servers/configs/subscriptions-modern-http.json 与其 legacy 对应物不同、省略了 update_resource 工具的原因:该变更会作用在一个一次性的服务器实例上,下一次读取时不可见。