subscriptions/listen opens a long-lived notification stream from the server to the
client. Unlike one-off requests, the stream stays open and delivers notifications until
the client cancels it. It replaces the former resources/subscribe RPC and the HTTP GET
endpoint.
Opening a Stream
The client sends asubscriptions/listen request with a notifications filter
specifying which event types it wants to receive. The server MUST NOT send
notification types the client has not explicitly requested.
Notification Filter
| 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 |
Acknowledgment
The server MUST sendnotifications/subscriptions/acknowledged as the first message
carrying the subscription’s ID in _meta under io.modelcontextprotocol/subscriptionId,
and MUST NOT send any notification on the
subscription before it. On stdio, where every subscription shares one channel, this
ordering is defined per subscription ID and not per channel: messages belonging to other
subscriptions MAY be interleaved before it.
The notifications field in the acknowledgment reflects the subset the server agreed to
honor. Notification types the server does not support are omitted.
Receiving Notifications
All notifications delivered on the stream carryio.modelcontextprotocol/subscriptionId in _meta, identifying the
subscriptions/listen request that opened the stream. The value is the JSON-RPC ID of
the subscriptions/listen request. In the examples above, the request used "id": 1,
so the acknowledgment and all subsequent notifications carry the subscription ID 1.
On stdio, where all messages
share a single channel, clients MUST use this field to correlate notifications
with their originating subscription.
Multiple Concurrent Subscriptions
A client MAY have multiple active subscriptions concurrently — for example, one listening for tools-list changes and another for resource updates. Each subscription is identified by the JSON-RPC request ID of itssubscriptions/listen request, and every notification on the stream carries
that ID in
io.modelcontextprotocol/subscriptionId so clients can demultiplex them.
Cancellation
A subscription ends when:- The client cancels it — close the SSE stream (HTTP) or send
notifications/cancelledreferencing thesubscriptions/listenrequest ID (stdio). - The server tears it down (e.g., during shutdown) — it SHOULD send the
empty
subscriptions/listenresponse to signal a graceful end (see Graceful Closure), then close the stream. - The underlying transport closes (HTTP timeout, TCP disconnect, stdio process exit).
Graceful Closure
When the server ends a subscription on its own initiative (for example, during shutdown), it SHOULD respond to the originalsubscriptions/listen request
with an empty result before closing the stream. This is the JSON-RPC response to
the long-lived request, correlated by its id, and signals that the subscription
ended gracefully — as opposed to an abrupt transport drop, which carries no
response.
io.modelcontextprotocol/subscriptionId in _meta, identifying which
subscription it closes. The value matches the JSON-RPC id of the originating
subscriptions/listen request.
A client that receives this response knows the subscription closed cleanly; a
transport that closes without it indicates an unexpected disconnect, which the
client MAY treat as a trigger to reconnect.
On stdio, if the connection is terminated and then re-established, the
client MUST re-send subscriptions/listen to re-establish its
subscriptions — the server holds no subscription state across reconnections.
See Cancellation for the full rules.