subscriptions
Client-side subscriptions/listen driver (2026-07-28, SEP-2575).
listen() opens the stream as an async context manager: entering waits for
the server's acknowledgment, iteration yields typed change events, a graceful
server close ends the loop, and an abrupt drop raises SubscriptionLost.
There is no replay and no automatic re-listen: a client that re-opens a
subscription refetches what it depends on.
listen
async
listen(
session: ClientSession,
*,
tools_list_changed: bool = False,
prompts_list_changed: bool = False,
resources_list_changed: bool = False,
resource_subscriptions: Sequence[str] = (),
on_event: OnEvent | None = None
) -> AsyncIterator[Subscription]
Open one subscriptions/listen stream on session (2026-07-28 only).
Entering sends the request and returns once the server's acknowledgment
arrives; exiting ends the subscription. on_event is awaited before each
event is returned - the seam Client.listen uses to finish cache eviction
before the consumer can refetch.
Raises:
| Type | Description |
|---|---|
ListenNotSupportedError
|
negotiated version predates 2026-07-28. |
MCPError
|
the server rejected the request, or the connection failed pre-ack. |
SubscriptionLost
|
the stream ended before it was acknowledged. |
TimeoutError
|
the session's read timeout elapsed before the acknowledgment. |
Source code in src/mcp-client/mcp_client/client/subscriptions.py
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | |
ListenNotSupportedError
Bases: RuntimeError
subscriptions/listen requires a 2026-07-28 connection.
Source code in src/mcp-client/mcp_client/client/subscriptions.py
59 60 61 62 63 64 65 66 67 68 | |
ListenRoute
Package-internal demux state for one listen stream, fed synchronously in receive order by the session.
Source code in src/mcp-client/mcp_client/client/subscriptions.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | |
set_acked
set_acked(honored: SubscriptionFilter) -> None
Record the acknowledged filter; the first ack wins.
Source code in src/mcp-client/mcp_client/client/subscriptions.py
87 88 89 90 91 92 | |
deliver
deliver(event: ServerEvent) -> None
Queue an event within the honored filter, deduplicated against the backlog.
Any ResourceUpdated is admitted once URI subscriptions were honored at
all: the spec allows the stamped URI to be a sub-resource of a subscribed one.
Source code in src/mcp-client/mcp_client/client/subscriptions.py
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | |
settle
settle(
end: _SubscriptionEnd, error: MCPError | None = None
) -> None
Record the stream's end; the first reason wins and wakes both waiters.
Source code in src/mcp-client/mcp_client/client/subscriptions.py
120 121 122 123 124 125 126 | |
next_event
async
next_event() -> ServerEvent | _SubscriptionEnd
Peek the next pending event, or the stream's end once the backlog drains.
A "local" end short-circuits the backlog; the other endings drain it first, so a graceful close never swallows events that preceded it.
Source code in src/mcp-client/mcp_client/client/subscriptions.py
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | |
consume
consume(event: ServerEvent) -> None
Remove a peeked event from the backlog.
Source code in src/mcp-client/mcp_client/client/subscriptions.py
146 147 148 | |
OnEvent
module-attribute
OnEvent = Callable[[ServerEvent], Awaitable[None]]
Per-event barrier awaited before a Subscription returns each event to its consumer.
Subscription
One open subscriptions/listen stream: an async iterator of typed events.
Produced by listen() / Client.listen(), not constructed directly.
Source code in src/mcp-client/mcp_client/client/subscriptions.py
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | |
subscription_id
instance-attribute
subscription_id = subscription_id
The listen request's JSON-RPC id, stamped into every frame's _meta.
honored
instance-attribute
honored = honored
The subset of the requested filter the server agreed to deliver.
__anext__
async
__anext__() -> ServerEvent
Yield the next change event; the loop ends when the stream does.
Raises:
| Type | Description |
|---|---|
SubscriptionLost
|
the stream dropped without the server's graceful close. |
Source code in src/mcp-client/mcp_client/client/subscriptions.py
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | |
SubscriptionLost
Bases: RuntimeError
The stream ended without the server's graceful close; re-listen and refetch.
Source code in src/mcp-client/mcp_client/client/subscriptions.py
71 72 | |
Classes
ListenNotSupportedError—subscriptions/listenrequires a 2026-07-28 connection.ListenRoute— Package-internal demux state for one listen stream, fed synchronously in receive order by the session.PromptsListChanged— The server's prompt list changed.ResourcesListChanged— The server's resource list changed.ResourceUpdated— The resource aturichanged and may need to be read again.Subscription— One opensubscriptions/listenstream: an async iterator of typed events.SubscriptionLost— The stream ended without the server's graceful close; re-listen and refetch.ToolsListChanged— The server's tool list changed.
Functions
listen— Open onesubscriptions/listenstream onsession(2026-07-28 only).
Attributes
OnEvent— Per-event barrier awaited before aSubscriptionreturns each event to its consumer.ServerEvent— An event a server publishes for delivery to listen subscribers.