3.2 KiB
standalone-get
Legacy mechanism (2025 handshake era). The 2026-07-28 protocol delivers server-initiated notifications over a
subscriptions/listenstream instead of the standalone GET stream. TODO(maxisbey): unify oncesubscriptions/listenlands (#2901).
Server-initiated notifications/resources/list_changed delivered over the
standalone GET SSE stream of a sessionful Streamable-HTTP connection. The
add_note tool mutates the resource list and emits the notification with no
related request; the client's message_handler receives it on the GET stream,
awaits it on an anyio.Event, then re-lists to observe the change.
Run it
# HTTP only — the standalone GET stream is a Streamable-HTTP feature. The
# client self-hosts the server on a free port, runs, then tears it down.
uv run python -m stories.standalone_get.client --http --legacy
# same, against the lowlevel-API server variant
uv run python -m stories.standalone_get.client --http --legacy --server server_lowlevel
# against a server you run yourself
uv run python -m stories.standalone_get.server --http --port 8000 &
SERVER_PID=$!
uv run python -m stories.standalone_get.client --http http://127.0.0.1:8000/mcp --legacy
kill "$SERVER_PID"
What to look at
client.py—Client(target, mode=mode, message_handler=on_message). Unsolicited notifications have no typed callback, so the catch-allmessage_handleris wired at construction — it (and theanyio.Eventit sets) must exist before the connection does. The notification is not guaranteed to arrive before the tool result (different streams), so the bodyawaits the event, bounded byanyio.fail_after(5).server.py—await ctx.session.send_resource_list_changed().MCPServer.add_resourcedoes not auto-emit (unlike the TypeScript SDK'sregisterResource); the explicit call is the teaching point. Becausesend_*_list_changed()carries norelated_request_id, the only route to the client is the standalone GET stream.
Caveats
- DNS-rebinding protection is disabled via
transport_security=NO_DNS_REBINDbecause the in-process httpx client sends noOriginheader. Drop the kwarg for a real deployment. - Neither
MCPServernor lowlevelServerauto-advertisesresources.listChanged: truein capabilities, andMCPServerexposes no knob to set it. A spec-conformant client that gates on the capability flag would skip the handler. ctx.session.*is the interim path; a later release will shorten it.- Tool-triggered, not timer-driven, for harness determinism. "Server pushes on its own schedule" is not demonstrated.
Spec
List Changed Notification, Streamable HTTP — Listening for Messages
See also
stickynotes/ (list_changed inside a feature capstone), sse_polling/ (the
other GET-stream story — resumability), json_response/ (what happens when the
server can't stream).