python-sdk/examples/stories/pagination
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-07-27 23:47:04 +01:00
..
__init__.py Add story-style examples suite (27 stories + harness + CI) (#2957) 2026-06-26 12:02:27 +02:00
client.py Add story-style examples suite (27 stories + harness + CI) (#2957) 2026-06-26 12:02:27 +02:00
README.md Add story-style examples suite (27 stories + harness + CI) (#2957) 2026-06-26 12:02:27 +02:00
server.py Add story-style examples suite (27 stories + harness + CI) (#2957) 2026-06-26 12:02:27 +02:00
server_lowlevel.py Add mcp.types as a permanent alias for mcp_types (#3190) 2026-07-27 23:47:04 +01:00

pagination

Walk a paginated resources/list by hand: feed each result's next_cursor back into list_resources(cursor=...) until it is None. The cursor is an opaque server-chosen string — never parse it, and never terminate on a falsy check (an empty string is a valid cursor under the spec).

Run it

# stdio (default — the client spawns the server as a subprocess)
uv run python -m stories.pagination.client --server server_lowlevel

# HTTP — the client self-hosts the server on a free port, runs, then tears it down
uv run python -m stories.pagination.client --http --server server_lowlevel

Drop --server server_lowlevel (on either transport) to run against the MCPServer variant (single page).

What to look at

  • client.py main — async with Client(target, mode=mode) as client: is the whole connection. The story owns the construction; target is whatever Client() accepts (an in-process server, a transport, or an HTTP URL) and the entry point picks it.
  • client.py — if page.next_cursor is None: break. Termination is key-absent, not falsy; while cursor: would be a spec bug.
  • server_lowlevel.py — the handler owns the cursor encoding (here: an integer offset as a string) and rejects an unrecognised cursor with -32602 Invalid params, the spec-recommended response.
  • server.py — MCPServer's decorator-registered resources are returned in a single page; the inbound cursor is accepted but ignored. The same client loop still terminates correctly after one request.

Caveats

  • No iter_*() helper — Client has no iter_resources() / iter_tools() async-iterator yet; the manual while True loop shown here is the supported pattern.
  • MCPServer is single-page — MCPServer ignores cursor and never sets next_cursor. Whether it grows a page_size= knob or stays single-page by design is open; use the lowlevel server when you need to emit pages today.

Spec

Pagination — server utilities

See also

resources/, tools/, prompts/ — every */list method paginates the same way. Reference test: tests/interaction/lowlevel/test_pagination.py.