Skip to content

Add list_all_* helpers that drain pagination on the client#2658

Open
adityasingh2400 wants to merge 1 commit into
modelcontextprotocol:mainfrom
adityasingh2400:feat-client-list-all-paginated-helpers-2556
Open

Add list_all_* helpers that drain pagination on the client#2658
adityasingh2400 wants to merge 1 commit into
modelcontextprotocol:mainfrom
adityasingh2400:feat-client-list-all-paginated-helpers-2556

Conversation

@adityasingh2400
Copy link
Copy Markdown

Closes #2556.

Summary

  • Add list_all_tools / list_all_prompts / list_all_resources / list_all_resource_templates on Client. Each walks next_cursor until exhausted and returns the combined list.
  • Add iter_all_tools / iter_all_prompts / iter_all_resources / iter_all_resource_templates async iterators, for streaming consumers that don't want to materialize every page in memory.
  • Update the docstrings on the single-page list_* methods to say so plainly and point at the new drains.
  • Switch ClientSessionGroup._aggregate_components to drain pagination so multi-server aggregators don't silently drop pages past the first (this was specifically called out in the issue as the scenario where high tool counts are most likely).

Existing tests that mocked the session's list_tools / list_resources / list_prompts now set next_cursor=None on the mock return values so the new drain loop terminates after a single page.

Why

The single-page list_* methods are easy to misuse, which is the whole point of the issue:

Connected Claude Code to an AWS Bedrock AgentCore Gateway with 31 tools registered across 7 targets. Only 14 showed up. The gateway returns 14 on page 0 with a nextCursor, then 17 on page 1. Claude Code calls tools/list once and drops the cursor.

The existing primitives are kept; this just adds a drain helper next to them so downstream client code can get the "give me everything" behavior in one call instead of writing the loop themselves.

Test plan

  • uv run pytest tests/client/test_list_all_pagination.py tests/client/test_session_group.py tests/client/test_list_methods_cursor.py (25 passed)
  • uv run pytest tests/client/ (208 passed, 1 xfailed)
  • uv run pytest tests/ (1180 passed, 98 skipped, 1 xfailed)
  • uv run ruff check . && uv run ruff format --check . (clean)
  • uv run pyright src/mcp/ tests/client/test_list_all_pagination.py tests/client/test_session_group.py (0 errors)
  • 100% coverage on src/mcp/client/client.py and src/mcp/client/session_group.py via tests/client/

New tests cover:

  • Multi-page drain across 2 and 3 pages for tools, prompts, resources, and resource templates.
  • The cursor sent on subsequent requests matches the next_cursor returned by the previous page.
  • Single-page and empty-server cases.
  • iter_all_tools yields one tool at a time and pages lazily.
  • ClientSessionGroup aggregates across paginated list_tools calls and supplies the cursor on the follow-up request.

Notes

I went with Client helpers only and left ClientSession as the single-page primitive (matches what the issue suggested as the conservative call). Happy to also add session-level helpers if you'd prefer that.

Currently Client.list_tools / list_prompts / list_resources /
list_resource_templates return a single page and the caller has to loop
on next_cursor manually. Add list_all_tools / list_all_prompts /
list_all_resources / list_all_resource_templates that walk next_cursor
until exhausted, plus iter_all_* async iterators for streaming
consumers. The single-page methods get a docstring update pointing at
the new drains. ClientSessionGroup switches its tool/prompt/resource
aggregation to the drain helper so its consumers always see the full
collection across multi-page servers.

Implements the helper maxisbey endorsed in modelcontextprotocol#2556.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add list_all_* helpers to drain pagination

1 participant