You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Real clients connect over streamable HTTP (or stdio, once served); the
in-memory client is a maintainer tool for tests and stays there. The examples
now construct Client("http://localhost:8000/mcp") themselves, and the tests
drive the example functions through an in-memory client instead of main().
Copy file name to clipboardExpand all lines: docs/handlers/subscriptions.md
+11-19Lines changed: 11 additions & 19 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -50,29 +50,21 @@ Two things the stream is *not*:
50
50
its content. To narrow that, serve the method with your own handler on the low-level
51
51
`Server` and acknowledge a smaller filter than the client asked for.
52
52
53
-
!!! warning "Not every transport serves the stream"
54
-
`subscriptions/listen` needs a transport that can stream a request's response: streamable
55
-
HTTP, or the in-process `Client(server)` the examples below use. Over stdio (and other
56
-
stream-pair transports) a 2026-07-28 connection rejects it with METHOD_NOT_FOUND, even
57
-
though `server/discover` still advertises the subscription capabilities there. The
58
-
open-stream semantics haven't been built for that transport yet.
53
+
!!! warning "Streamable HTTP only, for now"
54
+
`subscriptions/listen` needs a transport that can stream a request's response, which today
55
+
means streamable HTTP. Over stdio a 2026-07-28 connection rejects the method with
56
+
METHOD_NOT_FOUND, even though `server/discover` advertises the subscription capabilities
57
+
there. Serving it over stdio is planned; the open-stream semantics for that transport are
58
+
not built yet.
59
59
60
60
## Watching the stream
61
61
62
62
On the client, a subscription is one context manager. Entering it sends the request and waits for the server's acknowledgment, so the stream is live by the time the block starts.
63
63
64
-
```python title="client.py" hl_lines="16 20 22"
64
+
```python title="client.py" hl_lines="16 19 29"
65
65
--8<--"docs_src/subscriptions/tutorial003.py"
66
66
```
67
67
68
-
The examples connect in-process with `Client(mcp)`. Against a running server, pass its URL:
69
-
70
-
```python
71
-
asyncdefmain() -> None:
72
-
asyncwith Client("http://localhost:8000/mcp") as client:
73
-
await follow_board(client)
74
-
```
75
-
76
68
Iteration yields four typed events: `ToolsListChanged`, `PromptsListChanged`, `ResourcesListChanged`, and `ResourceUpdated(uri=...)`.
77
69
78
70
An event says *what* changed, never *how*. That is why `follow_board` calls `read_resource` and `list_tools`: the event is a cue to refetch. Read `event.uri` rather than assuming which resource moved, because once you subscribe to any URI the client delivers every `ResourceUpdated` on the stream.
@@ -90,23 +82,23 @@ Two more properties of the handle:
90
82
91
83
Open the subscription first, then start the watcher and get on with your work.
92
84
93
-
`app.py` imports `mcp` and `read_board` from the two files above, which live on disk as `tutorial001.py`and `tutorial003.py`. If you save the three side by side instead, drop the leading dot from those imports.
85
+
`app.py` imports `BOARD` and `read_board` from `client.py`above. If you save the files side by side rather than as a package, drop the leading dot from that import.
0 commit comments