主题
订阅
subscriptions/listen 会打开一条从服务端到客户端的长期通知流。与一次性请求不同,该流会保持打开并持续投递通知,直到客户端取消它。它取代了原先的 resources/subscribe RPC 和 HTTP GET 端点。
打开流
客户端发送 subscriptions/listen 请求,并附带一个 notifications 过滤器,指定它希望接收哪些事件类型。服务端 MUST NOT(不得)发送客户端未显式请求的通知类型。
json
{
"jsonrpc": "2.0",
"id": 1,
"method": "subscriptions/listen",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "ExampleClient",
"version": "1.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {}
},
"notifications": {
"toolsListChanged": true,
"resourceSubscriptions": ["file:///project/config.json"]
}
}
}通知过滤器
| Field | Type | Description |
|---|---|---|
toolsListChanged | boolean | Receive notifications/tools/list_changed when tools change |
promptsListChanged | boolean | Receive notifications/prompts/list_changed when prompts change |
resourcesListChanged | boolean | Receive notifications/resources/list_changed when list changes |
resourceSubscriptions | string[] | Receive notifications/resources/updated for these resource URIs |
所有字段均为可选。省略某个字段等同于不订阅该通知类型。
确认
服务端 MUST(必须)将 notifications/subscriptions/acknowledged 作为第一条消息发送,并在 _meta 中的 io.modelcontextprotocol/subscriptionId 下携带该订阅的 ID,且 MUST NOT(不得)在此之前在该订阅上发送任何通知。在 stdio 上,所有订阅共享同一个通道,因此该顺序是按订阅 ID 而非按通道定义的:属于其他订阅的消息 MAY(可以)在此之前交错出现。
确认消息中的 notifications 字段反映服务端同意履行的子集。服务端不支持的通知类型会被省略。
json
{
"jsonrpc": "2.0",
"method": "notifications/subscriptions/acknowledged",
"params": {
"_meta": {
"io.modelcontextprotocol/subscriptionId": 1
},
"notifications": {
"toolsListChanged": true,
"resourceSubscriptions": ["file:///project/config.json"]
}
}
}客户端 SHOULD(应该)将确认的过滤器与其请求的内容进行核对,并优雅地处理任何不支持的类型。
接收通知
流上投递的所有通知都在 _meta 中携带 io.modelcontextprotocol/subscriptionId,用于标识打开该流的 subscriptions/listen 请求。该值是 subscriptions/listen 请求的 JSON-RPC ID。在上面的示例中,请求使用了 "id": 1,因此确认消息及所有后续通知都携带订阅 ID 1。在 stdio 上,所有消息共享单一通道,客户端 MUST(必须)使用该字段将通知与其来源订阅关联起来。
json
{
"jsonrpc": "2.0",
"method": "notifications/resources/updated",
"params": {
"_meta": {
"io.modelcontextprotocol/subscriptionId": 1
},
"uri": "file:///project/config.json"
}
}多个并发订阅
客户端 MAY(可以)同时拥有多个活动订阅——例如,一个监听工具列表变更,另一个监听资源更新。每个订阅由其 subscriptions/listen 请求的 JSON-RPC 请求 ID 标识,流上的每条通知都在 io.modelcontextprotocol/subscriptionId 中携带该 ID,以便客户端对其进行解复用。
取消
订阅在以下情况下结束:
- 客户端取消它——关闭 SSE 流(HTTP)或发送引用
subscriptions/listen请求 ID 的notifications/cancelled(stdio)。 - 服务端将其拆除(例如在关闭期间)——它 SHOULD(应该)发送一个成功的
subscriptions/listen响应以表示优雅结束(参见优雅关闭),然后关闭流。 - 底层传输关闭(HTTP 超时、TCP 断开、stdio 进程退出)。
优雅关闭
当服务端主动结束订阅时(例如在关闭期间),它 SHOULD(应该)在关闭流之前,对最初的 subscriptions/listen 请求返回一个完成结果。该结果除标准结果字段和订阅元数据外,不携带任何方法特定的数据。这是对该长期存活请求的 JSON-RPC 响应,通过其 id 进行关联,表示订阅已优雅结束——与之相对的是突发的传输中断,后者不携带任何响应。
json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "complete",
"_meta": {
"io.modelcontextprotocol/subscriptionId": 1
}
}
}与流上的其他每条消息一样,该响应在 _meta 中携带 io.modelcontextprotocol/subscriptionId,标识它关闭的是哪个订阅。该值与发起 subscriptions/listen 请求的 JSON-RPC id 相匹配。
收到此响应的客户端便知道订阅已干净地关闭;若传输关闭时未收到该响应,则表示意外断开,客户端 MAY(可以)将其视为触发重连的信号。
在 stdio 上,如果连接被终止后又重新建立,客户端 MUST(必须)重新发送 subscriptions/listen 以重新建立其订阅——服务端不会跨重连保留任何订阅状态。
完整规则见取消。