Skip to content

fix(mcp): follow tools/list pagination instead of silently truncating#5833

Merged
waleedlatif1 merged 2 commits into
stagingfrom
fix/mcp-tools-pagination
Jul 22, 2026
Merged

fix(mcp): follow tools/list pagination instead of silently truncating#5833
waleedlatif1 merged 2 commits into
stagingfrom
fix/mcp-tools-pagination

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • The MCP SDK's listTools() returns a single page. A server that paginates its tool list via nextCursor was silently truncated to page one — its later tools just never appeared, with no error.
  • Now follows the cursor, bounded by four independent budgets — 50 pages / 1000 tools / 5 MB / 60 s aggregate wall-clock — plus a repeated-cursor guard (a page cap alone can't stop a server that returns a fresh cursor with zero new tools forever within budget). Caps live in MCP_CLIENT_CONSTANTS.
  • Partial results are kept: if a later page fails, the tools already collected are returned; only a page-one failure throws. Truncation is logged with the reason.
  • Matches LibreChat's capped-cursor-loop pattern; grounded in the MCP pagination spec (missing nextCursor = end of results, opaque cursors).

Deliberately scoped to pagination only. Legacy HTTP+SSE transport fallback is a separate, larger change (restructures the connect path + a real header-auth-on-SSE-GET footgun + needs a real legacy-SSE server to validate against) — recommended as its own PR, not bundled here.

Type of Change

  • Bug fix (silent truncation)

Testing

  • 3 new client tests: multi-page aggregation across nextCursor, repeated-cursor loop guard stops early, later-page failure returns partial results. All 19 client tests green; tsc + biome clean.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

The SDK's listTools() returns a single page; a server that paginates via
nextCursor was silently truncated to page one. Follow the cursor bounded by
four independent budgets (50 pages / 1000 tools / 5 MB / 60s aggregate
wall-clock) plus a repeated-cursor guard — a page cap alone can't stop a server
returning a fresh cursor with no new tools. Partial results from earlier pages
are kept when a later page fails; only a page-one failure throws. Matches the
LibreChat capped-cursor-loop pattern; caps live in MCP_CLIENT_CONSTANTS.
@vercel

vercel Bot commented Jul 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jul 22, 2026 1:20am

Request Review

@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes core MCP discovery behavior and error semantics (partial vs throw), affecting every code path that lists tools, though bounds limit abuse and tests cover edge cases.

Overview
Fixes silent truncation of MCP tool discovery when servers return nextCursor: McpClient.listTools() now walks pages and merges results instead of using a single SDK listTools() call.

Pagination is bounded by new MCP_CLIENT_CONSTANTS limits (50 pages, 1000 tools, 5 MB, 60s aggregate) with a repeated-cursor guard; hits log a truncation reason. Per-page timeouts use remaining wall-clock budget (maxTotalTimeout is no longer fixed at 60s for every call in a multi-page run).

Partial success: if page 1+ succeeds and a later page errors, collected tools are returned (including []); only a first-page failure still throws. Tests cover multi-page aggregation, loop guard, partial/empty partial, and first-page failure.

Reviewed by Cursor Bugbot for commit 57abaec. Configure here.

@greptile-apps

greptile-apps Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds complete, bounded pagination for MCP tool discovery. The main changes are:

  • Follows opaque nextCursor values across tool-list pages.
  • Limits discovery by time, page count, tool count, payload bytes, and repeated cursors.
  • Keeps partial results when a later page fails.
  • Measures payload size using UTF-8 bytes.
  • Adds tests for pagination, cursor loops, and page failures.

Confidence Score: 5/5

This looks safe to merge.

  • The empty-page partial-result fix now tracks completed page responses.
  • Non-ASCII payloads are counted using their UTF-8 byte size.
  • No blocking issue remains in the updated code.

Important Files Changed

Filename Overview
apps/sim/lib/mcp/client.ts Adds bounded cursor pagination, partial-result handling, UTF-8 payload accounting, and truncation logging.
apps/sim/lib/mcp/client.test.ts Adds coverage for multi-page results, repeated cursors, partial failures, empty successful pages, and first-page failures.
apps/sim/lib/mcp/utils.ts Defines limits for pages, tools, and aggregate payload bytes.

Reviews (2): Last reviewed commit: "fix(mcp): count UTF-8 bytes, keep empty ..." | Re-trigger Greptile

Comment thread apps/sim/lib/mcp/client.ts Outdated
Comment thread apps/sim/lib/mcp/client.ts Outdated
Comment thread apps/sim/lib/mcp/client.ts
…curately

Review fixes on the tools/list pagination loop:
- Buffer.byteLength(..., 'utf8') instead of .length so non-ASCII schemas can't
  overshoot the 5 MB budget by counting UTF-16 code units.
- Track pagesFetched (not tools.length) for the partial-success decision, so a
  valid-but-empty first page followed by a failing page returns [] instead of
  throwing and marking the server unhealthy.
- Explicit reachedEnd/page-cap distinction so a natural finish on exactly
  MAX_PAGES isn't mislogged as truncated.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 57abaec. Configure here.

@waleedlatif1
waleedlatif1 merged commit 943d184 into staging Jul 22, 2026
20 checks passed
@waleedlatif1
waleedlatif1 deleted the fix/mcp-tools-pagination branch July 22, 2026 02:33
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.

1 participant