Bound automatic pagination in the MCP client
## Motivation and Context `MCP::Client#tools`, `#resources`, `#resource_templates`, and `#prompts` follow `nextCursor` until the server stops offering one. The `seen` set in `fetch_all_pages` catches a server that repeats or cycles cursors, but a fresh cursor on every response walks past that guard, and the client keeps requesting and retaining pages for as long as the server keeps producing them. The transports' per-message limits do not help here, since each individual page can be small. `MCP::Client.new` now takes `max_pages:`, defaulting to `MAX_PAGES` (1000). Reaching it raises `PaginationLimitError` rather than truncating the collection silently, since a short array would be indistinguishable from a server that genuinely ran out of items. The single-page `list_*` methods are unchanged, so callers who need their own policy still have one. ## How Has This Been Tested? New tests in `test/mcp/client_test.rb` cover a server that returns a distinct cursor per page, the boundary where a server stops exactly at `max_pages`, and the argument validation. The existing repeat-cursor and cycling-cursor tests are unaffected. `bundle exec rake` (tests, RuboCop, and conformance baseline) passes. ## Breaking Changes An all-pages call against a server offering more than 1000 pages now raises `MCP::Client::PaginationLimitError` instead of continuing. Pass a larger `max_pages:` to `MCP::Client.new` if that is expected.
This commit is contained in:
parent
34d7fca0ac
commit
a4a885683c
1 changed files with 92 additions and 4 deletions
|
|
@ -2386,13 +2386,18 @@ If your application needs the complete collection regardless of how the server i
|
|||
`client.tools`, `client.resources`, `client.resource_templates`, and `client.prompts` auto-iterate
|
||||
through all pages and return a plain array of items, guaranteeing the full collection regardless
|
||||
of the server's `page_size` setting. When a server paginates, they issue multiple JSON-RPC round
|
||||
trips per call and break out of the pagination loop if the server returns the same `nextCursor`
|
||||
twice in a row as a safety measure.
|
||||
trips per call. Two guards keep that loop finite: it stops when the server returns a `nextCursor`
|
||||
it has already sent, and it stops after `max_pages` pages.
|
||||
|
||||
```ruby
|
||||
tools = client.tools # => Array<MCP::Client::Tool> of every tool on the server.
|
||||
```
|
||||
|
||||
`MCP::Client.new` accepts an optional `max_pages:` keyword that caps how many pages these methods
|
||||
will walk. It defaults to `1_000`; a server that keeps offering a fresh `nextCursor` past that
|
||||
point raises `MCP::Client::PaginationLimitError` rather than being followed indefinitely. Raise it
|
||||
if you legitimately expect more pages than that.
|
||||
|
||||
Use these when you want the complete list; use `list_tools(cursor:)` etc. when you need
|
||||
fine-grained iteration (e.g. to stream-process pages without loading everything into memory).
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue