Repository navigation
fix: Deterministic MCP Tool Order for a Stable Prompt Prefix - #17097
Closed
Shabonasar wants to merge 1 commit into
Closed
Shabonasar wants to merge 1 commit into
Shabonasar wants to merge 1 commit into
Conversation
Providers serialize the tools parameter ahead of the system prompt, so any reordering of MCP tools invalidates the prompt prefix cache from position 0. Selecting the same servers in a different order, or a catalog returning tool keys in a different order, produced a different tools array. - loadEphemeralAgent and loadAddedAgent materialize selected and spec-pinned MCP servers, and the tools of each server, in code-unit order - mcp_all expansion iterates tool names in the same order - MCPManager.getInstructions returns servers by name, so MCP instructions in the system prompt keep a stable order - explicit agent.tools and the order of non-MCP groups are unchanged Tests: unit coverage for permutations, shuffled catalog keys, similar names, duplicates, empty and failed servers, spec merge; toolOrderStability.test.ts captures provider payloads through createRun for OpenAI, an OpenAI-compatible endpoint, Anthropic, Bedrock and Google.
7 of 8 tasks
Shabonasar
marked this pull request as draft
October 14, 2026 16:44
Author
|
Closing: sorting alone does not keep the prefix stable, because enabling an MCP server mid-conversation still changes |
Author
|
Tracked in #17102; the name ordering moves into the stable-tools PR for MCP servers selected mid-chat. |
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
Continuation of #16369. Providers serialize the
toolsparameter ahead of the system prompt, so the tool list is the very first thing a prefix cache (vLLM/SGLang automatic prefix caching, OpenAI automatic caching, Anthropic and Bedrock breakpoints, Gemini implicit caching) has to match. Any reordering of tools invalidates the cache from position 0, including the whole conversation history.Today the MCP part of
toolsfollows the order in which servers were selected in the chat picker and the key order of the server tool catalog. Selecting the same servers in a different order, a different spec/picker merge, or a reconnect that returns tools in a different order produces a differenttoolsarray for the same agent, so conversations that should share a prefix do not, and a single conversation can lose its cache between turns.What changes
sortNames(packages/api/src/mcp/utils.ts): code-unit ascending order, independent of locale.loadEphemeralAgentandloadAddedAgentmaterialize picker-selected and spec-pinned MCP servers, and the tools of each server, in that order. The sorted server list is also what is published toephemeralAgent.mcp, which the instruction path reads.mcp_allexpansion inloadToolDefinitionsiterates server tools by name.MCPManager.getInstructionsreturns servers by name, so MCP server instructions in the system prompt keep a stable order.Intentionally unchanged: the explicit
toolslist of a saved agent (the author's order is preserved), and the order of non-MCP groups (MCP,tool_search, actions, built-ins, registered tools). Sorting happens only inside the MCP group.Testing
agents/load.spec.ts(every permutation of the picker, shuffled catalog keys, similar namesA/a/a_b, duplicates, empty server, failed server placeholder, merge withspec.mcpServers),tools/definitions.spec.ts(mcp_allexpansion),mcp/__tests__/utils.test.ts,mcp/__tests__/MCPManager.test.ts(identical instructions text for any requested order), updatedagents/__tests__/load.spec.ts.agents/__tests__/toolOrderStability.test.ts(30 tests). RealloadEphemeralAgent,loadToolDefinitions,initializeAgentregistrations,MCPManager.formatInstructionsForContext,applyContextToAgentandcreateRun; the serialized provider request is captured before it leaves the process. Mixed tool set: four MCP servers, deferred tools withtool_search, an action,file_search,web_search, code execution, memory, file authoring and a self-spawnsubagent. Providers: OpenAI, an OpenAI-compatible endpoint, Anthropic and Bedrock with prompt caching, Google. Serializedtoolsandsystemare byte-identical across three picker orders, a reversed catalog key order and a repeated turn; the order of non-MCP groups is pinned by an explicit list. With sorting disabled, 25 of the 30 tests fail.src/agents,src/tools,src/mcpwith MongoDB, all passing except suites that need Redis or outbound network; api agents controllers and services passing;tsc --noEmitclean; eslint and prettier clean on touched files.Next
Part of the series started in #16369: context toggled mid-conversation (artifacts, project context, memory) delivered as
<context_update>history events, then deferred loading for MCP servers selected in the chat so thetoolsparameter stays fixed when a server is enabled mid-conversation.Related: #16369, #16877.
Type of change