🪢 fix: Paginate MCP tools/list to Load All Tools#67
Open
TomasPalsson wants to merge 1 commit into
Open
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
MCP `tools/list` is cursor-paginated, but LibreChat only ever read the first page. `MCPConnection.fetchTools()` called `client.listTools()` once and discarded `nextCursor`, and `MCPServerInspector` — which builds the agent-facing tool registry at startup and per request — called the raw `client.listTools()` directly. Servers that paginate (e.g. an aggregating gateway exposing hundreds of tools) only ever exposed page one; tools on later pages were never registered, and invoking one returned "This tool's MCP server is temporarily unavailable." - `MCPConnection.fetchTools()` now follows `nextCursor` across pages and concatenates every page's tools, bounded by a configurable page cap (`MCP_TOOLS_LIST_MAX_PAGES`, default 50) and a repeated-cursor guard so a misbehaving server cannot loop forever. Tools already fetched are returned if a later page fails, and the no-throw error contract is unchanged. - `MCPServerInspector.getToolFunctions()` and `fetchServerCapabilities()` now route through `fetchTools()`, so the canonical startup and per-request tool registry is fully paginated too.
35b70e2 to
ae33e21
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
I fixed MCP tool discovery silently truncating to the first page when a server paginates
tools/list.Root cause
tools/listis a cursor-paginated method in the MCP spec, but LibreChat only ever read the first page in two places:MCPConnection.fetchTools(packages/api/src/mcp/connection.ts) calledthis.client.listTools()once and returnedresult.tools, discardingnextCursor.MCPServerInspector(packages/api/src/mcp/registry/MCPServerInspector.ts) — which builds the agent-facing tool registry (config.toolFunctions, consumed byinitializeMCPs→MCPManager.getAppToolFunctions) at startup and per request — called the rawconnection.client.listTools()directly in bothgetToolFunctionsandfetchServerCapabilities.So any server returning more tools than fit in one page only ever exposed page 1. With an aggregating gateway (observed: AWS Bedrock AgentCore Gateway returning 256 tools across 6 pages) only the first ~41 tools were registered; the rest were invisible to the agent, and invoking one failed with
"This tool's MCP server is temporarily unavailable"because it was never in the registry.Approach
fetchToolsnow followsnextCursor, passing{ cursor }tolistToolsfor each page and concatenatingtoolsin order until the server stops returning a cursor. Two defensive guards bound the loop:mcpConfig.TOOLS_LIST_MAX_PAGES(envMCP_TOOLS_LIST_MAX_PAGES, default50, clamped to>= 1). On hitting the cap the loop stops and warns.seenCursorsset — if a server repeats a cursor it already returned (an infinite-loop signature), the loop stops early and warns.MCPServerInspector.getToolFunctionsandfetchServerCapabilitiesnow route throughconnection.fetchTools(), so the canonical startup and per-request tool registry is fully paginated.What is deliberately not changed / out of scope
[].MCPServerInspectorreads the tool list twice at startup (capability summary + tool registry); this double read pre-existed the PR, so collapsing it into one fetch is left as a follow-up.fetchResourcesandfetchPromptsshare the same single-page limitation; left out to keep this PR focused.Changes
packages/api/src/mcp/connection.ts—fetchToolsfollowsnextCursorwith page-cap and repeated-cursor guards, returning already-fetched pages on error.packages/api/src/mcp/mcpConfig.ts— adds typedTOOLS_LIST_MAX_PAGES(envMCP_TOOLS_LIST_MAX_PAGES, default50).packages/api/src/mcp/registry/MCPServerInspector.ts—getToolFunctionsandfetchServerCapabilitiesuse the paginatedfetchTools().fetchTools(including fivemcpConfigmocks that previously omitted the cap).Change Type
Testing
Run from
packages/apion Nodev24.16.0:npx jest src/mcp/__tests__/MCPConnectionFetchTools.test.ts— 8/8 passing. Covers single page, multi-page concat with cursor passthrough, page-cap warn, repeated-cursor warn, empty intermediate page, empty-string cursor, mid-pagination failure (already-fetched pages returned), and first-page failure ([]). Builds a realMCPConnectionand injects a stubclient.listTools, exercising the actual loop.npx jest src/mcp/registry/__tests__/MCPServerInspector.test.ts— passing; inspector now drives the paginated path.npm run test:ci— full@librechat/apisuite green, no regressions.Test Configuration
v24.16.0, Workspace:packages/api