Skip to main content
subscriptions/listen 会从服务器到客户端打开一个长期存在的通知流。与一次性请求不同,该流会保持打开状态并持续发送通知,直到客户端取消它。它取代了原先的 resources/subscribe RPC 和 HTTP GET 端点。

打开流

客户端发送一个带有 notifications 过滤器的 subscriptions/listen 请求,用于指定希望接收哪些事件类型。服务器 不得 发送客户端未明确请求的通知类型。

通知过滤器

所有字段都是可选的。省略某个字段等同于不订阅该通知类型。

确认

服务器 必须 将 notifications/subscriptions/acknowledged 作为第一条消息发送, 并在 _meta 中通过 io.modelcontextprotocol/subscriptionId 携带订阅的 ID, 且在此之前 不得 发送该订阅的任何通知。在 stdio 场景下,所有订阅共享同一通道, 这种顺序是按订阅 ID 定义的,而不是按通道定义的:属于其他订阅的消息 可以 在此之前交错出现。 确认响应中的 notifications 字段反映了服务器同意遵守的子集。 服务器不支持的通知类型会被省略。
客户端 应该 将已确认的过滤器与其请求内容进行比对,并优雅地处理任何不受支持的类型。

接收通知

在流上发送的所有通知都会在 _meta 中携带 io.modelcontextprotocol/subscriptionId,用于标识打开该流的 subscriptions/listen 请求。此值是 subscriptions/listen 请求的 JSON-RPC ID。在上面的示例中,请求使用了 "id": 1,因此确认消息和所有后续通知都会携带订阅 ID 1。在 stdio 中,所有消息共享同一通道,客户端 必须 使用此字段将通知与其来源订阅相关联。

多个并发订阅

客户端 可以 同时拥有多个活跃订阅——例如,一个监听工具列表变更,另一个监听资源更新。每个订阅都由其 subscriptions/listen 请求的 JSON-RPC 请求 ID 标识,并且流上的每条通知都会在 io.modelcontextprotocol/subscriptionId 中携带该 ID,以便客户端对它们进行解复用。

取消

订阅在以下情况下结束:
  • 客户端取消订阅——关闭 SSE 流(HTTP),或发送引用 subscriptions/listen 请求 ID 的 notifications/cancelled(stdio)。
  • 服务器将其拆除(例如,在关闭期间)——它 应该 发送成功的 subscriptions/listen 响应,以表示正常结束(请参见优雅关闭),然后关闭流。
  • 底层传输关闭(HTTP 超时、TCP 断开、stdio 进程退出)。

优雅关闭

当服务器主动结束订阅时(例如,在关闭期间),它 应该 在关闭流之前, 使用完成结果响应原始的 subscriptions/listen 请求。除了标准结果字段和订阅元数据之外, 该结果不携带任何特定于方法的数据。这是对长期请求的 JSON-RPC 响应,通过其 id 进行关联, 并表示订阅已正常结束——不同于突然的传输断开,后者不携带任何响应。
与流上的其他消息一样,该响应在 _meta 中携带 io.modelcontextprotocol/subscriptionId,用于标识它关闭的是哪一个 订阅。该值与原始 subscriptions/listen 请求的 JSON-RPC id 相匹配。 收到此响应的客户端会知道订阅已正常关闭;而没有该响应就关闭的 传输则表示一次意外断开,客户端 可以 将其视为重新连接的触发条件。 在 stdio 中,如果连接被终止后又重新建立, 客户端 必须 重新发送 subscriptions/listen 以重新建立其 订阅——服务器不会在重连之间保留任何订阅状态。 完整规则请参见 取消。