PrefectHQ/fastmcp · error · RuntimeError
[{self.name}] Reached auto-pagination limit ({max_pages} pag
Error message
[{self.name}] Reached auto-pagination limit ({max_pages} pages) for list_tools. Use list_tools_mcp() with cursor for manual pagination, or increase max_pages. What it means
FastMCP's client `list_tools()` auto-paginates through the server's tool list, following `nextCursor` for up to `max_pages` iterations (default 250). If the cursor chain has not terminated by then, the for-else branch raises `RuntimeError`. This prevents unbounded loops when a server exposes very large tool catalogs or has broken pagination.
Source
Thrown at fastmcp_slim/fastmcp/client/mixins/tools.py:135
all_tools: list[mcp_types.Tool] = []
cursor: str | None = None
seen_cursors: set[str] = set()
for _ in range(max_pages):
result = await self.list_tools_mcp(cursor=cursor, cache_mode=cache_mode)
all_tools.extend(result.tools)
if not result.next_cursor:
break
if result.next_cursor in seen_cursors:
logger.warning(
f"[{self.name}] Server returned duplicate pagination cursor"
f" {result.next_cursor!r} for list_tools; stopping pagination"
)
break
seen_cursors.add(result.next_cursor)
cursor = result.next_cursor
else:
raise RuntimeError(
f"[{self.name}] Reached auto-pagination limit"
f" ({max_pages} pages) for list_tools."
" Use list_tools_mcp() with cursor for manual pagination,"
" or increase max_pages."
)
return all_tools
# --- Call Tool ---
async def call_tool_mcp(
self: Client,
name: str,
arguments: dict[str, Any],
progress_handler: ProgressHandler | None = None,
timeout: datetime.timedelta | float | int | None = None,
meta: dict[str, Any] | None = None,
) -> mcp_types.CallToolResult:View on GitHub (pinned to 1f02114297)
Solutions
- Use `client.list_tools_mcp(cursor=...)` and iterate manually until `result.next_cursor is None`.
- Increase the limit: `client.list_tools(max_pages=...)`.
- Diagnose the server: if the same cursor repeats, it's a server-side pagination bug to fix or filter around.
- Reduce the number of tools registered on the server.
Example fix
// before
tools = await client.list_tools() # RuntimeError after 250 pages
// after
result = await client.list_tools_mcp()
tools = result.tools
while result.next_cursor is not None:
result = await client.list_tools_mcp(cursor=result.next_cursor)
tools.extend(result.tools) Defensive patterns
Strategy: try-catch
Validate before calling
# Probe pagination health before the auto-paginating call
first = await client.list_tools_mcp()
if first.next_cursor is not None and len(first.tools) < 10:
print("Server pages are small; prefer manual pagination or larger max_pages") Try / catch
try:
tools = await client.list_tools()
except RuntimeError as e:
if "auto-pagination limit" not in str(e):
raise
page = await client.list_tools_mcp()
tools = page.tools
cursor = page.next_cursor
while cursor is not None:
page = await client.list_tools_mcp(cursor=cursor)
tools.extend(page.tools)
cursor = page.next_cursor Prevention
- Use list_tools_mcp() with an explicit loop when aggregating tools through proxies
- Pass an explicit max_pages sized to the expected page count
- Detect repeating cursors and stop instead of looping indefinitely
- Trim the server's registered tool count when practical
When it happens
Trigger: Calling `client.list_tools()` against a server exposing more than 250 pages of tools, or a server whose `nextCursor` never becomes None (regenerated or repeated cursors).
Common situations: A proxy/gateway aggregating tools from many upstream servers with small page sizes; third-party MCP servers with non-terminating pagination; test servers that always return a cursor.
Related errors
- [{self.name}] Reached auto-pagination limit ({max_pages} pag
- [{self.name}] Reached auto-pagination limit ({max_pages} pag
- [{self.name}] Reached auto-pagination limit ({max_pages} pag
- INVALID_PARAMS
- {msg or "Tool '{name}' returned an error"}
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/ffac514952c54f50.
Report an issue: GitHub.