subscriptions/listen 打开一个从服务器到客户端的长期存在的通知流。与一次性请求不同,该流保持打开并投递通知,直到客户端取消它。它替换了以前的 resources/subscribe RPC 和 HTTP GET 端点。
打开一个流
客户端发送一个带有notifications 过滤器的 subscriptions/listen 请求,指定它想要接收哪些事件类型。服务器**不得(MUST NOT)**发送客户端未显式请求的通知类型。
通知过滤器
所有字段都是可选的。省略一个字段等同于不订阅该通知类型。
确认
服务器**必须(MUST)发送notifications/subscriptions/acknowledged 作为在 _meta 中于 io.modelcontextprotocol/subscriptionId 下携带订阅 ID 的第一条消息,并不得(MUST NOT)在它之前于该订阅上发送任何通知。在 stdio 上,每个订阅共享一个信道,这种排序是按订阅 ID 而非按信道定义的:属于其他订阅的消息可以(MAY)**在它之前交错。
确认中的 notifications 字段反映服务器同意兑现的子集。服务器不支持的通知类型将被省略。
接收通知
流上投递的所有通知都在_meta 中携带 io.modelcontextprotocol/subscriptionId,标识打开该流的 subscriptions/listen 请求。其值是 subscriptions/listen 请求的 JSON-RPC ID。在上面的示例中,请求使用了 "id": 1,因此确认和所有后续通知都携带订阅 ID 1。在 stdio 上,所有消息共享单个信道,客户端**必须(MUST)**使用此字段将通知与其发起的订阅关联起来。
多个并发订阅
客户端**可以(MAY)**并发地拥有多个活动订阅——例如,一个监听工具列表变更,另一个监听资源更新。每个订阅由其subscriptions/listen 请求的 JSON-RPC 请求 ID 标识,流上的每个通知都在 io.modelcontextprotocol/subscriptionId 中携带该 ID,以便客户端可以对它们进行解复用(demultiplex)。
取消
一个订阅在以下情况下结束:- 客户端取消它——关闭 SSE 流(HTTP)或发送引用该
subscriptions/listen请求 ID 的notifications/cancelled(stdio)。 - 服务器拆除它(例如在关闭期间)——它**应当(SHOULD)**发送一个成功的
subscriptions/listen响应以示优雅结束(参见优雅关闭),然后关闭流。 - 底层传输关闭(HTTP 超时、TCP 断开、stdio 进程退出)。
优雅关闭
当服务器主动结束一个订阅时(例如在关闭期间),它**应当(SHOULD)**在关闭流之前以一个完成结果响应原始的subscriptions/listen 请求。该结果除标准结果字段和订阅元数据之外不携带任何特定于方法的数据。这是对该长期存在请求的 JSON-RPC 响应,由其 id 关联,并示意该订阅优雅地结束——与不携带响应的突然传输断开相对。
_meta 中携带 io.modelcontextprotocol/subscriptionId,标识它关闭的是哪个订阅。其值与发起的 subscriptions/listen 请求的 JSON-RPC id 匹配。
收到此响应的客户端知道该订阅干净地关闭了;一个不带它就关闭的传输表示一次意外断开,客户端**可以(MAY)**将其视为重连的触发条件。
在 stdio 上,如果连接被终止然后重新建立,客户端**必须(MUST)**重新发送 subscriptions/listen 以重新建立其订阅——服务器在重连之间不持有任何订阅状态。
完整规则参见取消。