Repository navigation
fix(server): MCP list tools clamp an oversized limit instead of failing - #30976
MarcoDotIO wants to merge 12 commits into
Conversation
…ling Codex hides a tool parameter's `maximum` from the model, so an agent that asks t3_project_list for `limit: 200` got InvalidParams and had to retry. The limit now clamps to 100 on decode, as t3_thread_read does, and `nextCursor` pages through the rest. Values below 1 still fail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
t3_queue (list) and t3_preview_list had the same hidden bound as t3_project_list: Codex never shows the model a parameter's `maximum`, so `limit` above 100 (queue) or 50 (preview tabs) failed the call with InvalidParams. Both now clamp on decode with clampedPositiveInt, and `nextCursor` pages through the rest. Values below 1 still fail. t3_worktree_list and t3_thread_search are left alone: their limit schemas are shared with RPCs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — Oversized MCP list limits now clamp to existing page-size caps instead of failing validation. Default page sizes, access controls, and handlers remain unchanged, keeping the change narrowly bounded. You can add or adjust custom eligibility rules. Learn more. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. Walkthrough
Merge Risk:
|
# Conflicts: # apps/server/src/provider/agentContextBudget.json
# Conflicts: # apps/server/src/provider/agentContextBudget.json
# Conflicts: # apps/server/src/provider/agentContextBudget.json
# Conflicts: # apps/server/src/provider/agentContextBudget.json
|
Note Written by Merged current
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem
Three MCP list tools reject a
limitabove a maximum the model never sees:t3_project_list(100),t3_queuewithaction: "list"(100), andt3_preview_list(50). The Codex harness does not show the model a tool parameter'smaximum, and these fields have no description. An agent cannot know about the bound until the call fails with-32602: Invalid parameters for tool '<tool>': Expected a value between 1 and 100(or 50) and it has to retry. #22901 fixed this fort3_thread_read's page sizes, and #27814 does the same fort3_thread_list.Call path: an agent calls, for example,
t3_queuewith{ action: "list", limit: 200 }.McpServerdecodes the arguments against the tool's parameter schema (apps/server/src/mcp/toolkits/{project,thread,previewControls}/tools.ts). TheSchema.Int.check(isBetween({ minimum: 1, maximum: N }))refinement fails, so the handler never runs.Change
limitparameters usesclampedPositiveInt(N), the helpert3_thread_readalready uses:clampedPositiveInt(100)fort3_project_listandt3_queue,clampedPositiveInt(50)fort3_preview_list. A value above the maximum decodes to the maximum, and each tool's existingnextCursorpages through the rest. 0 and negative values still fail.clampedPositiveIntinpackages/contracts/src/orchestratorMcp.tsis now exported so the server toolkits can use it. Its body is unchanged.The in-tree callers of
t3_project_list,t3 threadin the CLI (listAllProjects) and remote delegation's project lookup, already passlimit: 100, so they behave the same.Deliberately out of scope:
t3_worktree_listandt3_thread_searchhave the same pattern, but theirlimitschemas are shared with RPCs (VcsListRefsInput,OrchestrationSearchThreadsInput). Clamping there would change RPC behaviour too.t3_thread_listis covered by #27814.Scope and approval
This is a small, focused fix for one underlying problem: MCP-only list tools fail on a bound the model cannot see. It applies the clamp that #22901 merged for
t3_thread_readto the three remaining MCP-only tools with that bound, one parameter each. Behavior and result shapes stay the same for every value that worked before.Verification
Added two table tests to
apps/server/src/mcp/McpHttpServer.test.ts, each run for all three tools through the real MCP server decode path:clamps a $tool limit above its maximum instead of rejecting the call: twice the maximum reaches the handler as the maximum, andlimit: 7stays 7.still rejects a $tool limit below its minimum:limit: 0still fails, and the handler is not called.With the source files reverted to
upstream/main:(The below-minimum cases also fail there, only because main's error wording differs; main does reject 0.)
With the fix:
tsc --noEmitpasses inpackages/contractsandapps/server. Lint and format pass onpackages/contracts/srcandapps/server/src/mcp, and knip passes in the commit hook.The clamped schemas no longer list
maximum, so the MCP tool list shrinks:agentContextBudget.jsonrecordsmcpToolListJsonBytes49806 → 49765 (against current main) (AgentContextBudget.test.tspasses). I did not addlimitdescriptions, so agent context does not grow.Not checked: a live Codex session calling these tools.
Proved with table tests through the real MCP decode path that fail on
mainand pass with the fix.Created with Claude Opus 5.5 in the Claude Code desktop app, and reviewed by GPT 6.1 Sol in Codex CLI.
🤖 Generated with Claude Code