Skip to main content
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 a subscriptions/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.
{
  "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"]
    }
  }
}

Notification Filter

FieldTypeDescription
toolsListChangedbooleanReceive notifications/tools/list_changed when tools change
promptsListChangedbooleanReceive notifications/prompts/list_changed when prompts change
resourcesListChangedbooleanReceive notifications/resources/list_changed when list changes
resourceSubscriptionsstring[]Receive notifications/resources/updated for these resource URIs
All fields are optional. Omitting a field is equivalent to not subscribing to that notification type.

Acknowledgment

The server MUST send notifications/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.
{
  "jsonrpc": "2.0",
  "method": "notifications/subscriptions/acknowledged",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/subscriptionId": 1
    },
    "notifications": {
      "toolsListChanged": true,
      "resourceSubscriptions": ["file:///project/config.json"]
    }
  }
}
The client SHOULD check the acknowledged filter against what it requested and handle any unsupported types gracefully.

Receiving Notifications

All notifications delivered on the stream carry io.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.
{
  "jsonrpc": "2.0",
  "method": "notifications/resources/updated",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/subscriptionId": 1
    },
    "uri": "file:///project/config.json"
  }
}

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 its subscriptions/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/cancelled referencing the subscriptions/listen request ID (stdio).
  • The server tears it down (e.g., during shutdown) — it SHOULD send the empty subscriptions/listen response 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 original subscriptions/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.
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "resultType": "complete",
    "_meta": {
      "io.modelcontextprotocol/subscriptionId": 1
    }
  }
}
Like every other message on the stream, the response carries 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.