examples/stories/resources/README.md
Expose data by URI: a static resource (config://app) and an RFC-6570
template (greeting://{name}). One @mcp.resource() decorator handles both —
the SDK infers static-vs-template from whether the URI contains {...}. The
client lists resources, lists templates, then reads each.
# stdio (default — the client spawns the server as a subprocess)
uv run python -m stories.resources.client
# HTTP — the client self-hosts the server on a free port, runs, then tears it down
uv run python -m stories.resources.client --http
# same, against the lowlevel-API server variant
uv run python -m stories.resources.client --http --server server_lowlevel
client.py async with Client(target, mode=mode) as client: — the one line
every client example exists to teach. target is anything Client()
accepts (an in-process server, a transport, or an HTTP URL) and mode= is
always explicit; the rest of the story is the body of that async with.server.py app_config vs greeting — a URI with no {} registers a
static resource (appears in resources/list); a URI with {name} registers
a template (appears only in resources/templates/list) and the placeholder
must match the function parameter name.server_lowlevel.py read_resource — without MCPServer you own the URI
dispatch yourself, including raising MCPError(code=INVALID_PARAMS, ...) for
unknown URIs (matches what MCPServer sends).client.py isinstance(entry, TextResourceContents) — contents is a list
of TextResourceContents | BlobResourceContents; narrow before reading
.text.Subscriptions. Per-URI resources/subscribe is a 2025-era RPC being replaced
by subscriptions/listen in 2026-07-28; neither is shown in this story. See
stickynotes/ for list_changed notifications.
stickynotes/ (list-changed notifications), pagination/ (cursor over a long
resource list).