examples/stories/standalone_get/README.md
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.
# 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"
client.py — Client(target, mode=mode, message_handler=on_message).
Unsolicited notifications have no typed callback, so the catch-all
message_handler is wired at construction — it (and the anyio.Event it
sets) must exist before the connection does. The notification is not
guaranteed to arrive before the tool result (different streams), so the body
awaits the event, bounded by anyio.fail_after(5).server.py — await ctx.session.send_resource_list_changed().
MCPServer.add_resource does not auto-emit (unlike the TypeScript SDK's
registerResource); the explicit call is the teaching point. Because
send_*_list_changed() carries no related_request_id, the only route to the
client is the standalone GET stream.transport_security=NO_DNS_REBIND
because the in-process httpx client sends no Origin header. Drop the kwarg
for a real deployment.MCPServer nor lowlevel Server auto-advertises
resources.listChanged: true in capabilities, and MCPServer exposes 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.List Changed Notification, Streamable HTTP — Listening for Messages
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).