Skip to content

fix: sort list_all() output in ToolRouter and PromptRouter for deterministic ordering#665

Open
p4fg wants to merge 1 commit intomodelcontextprotocol:mainfrom
p4fg:fix/deterministic-list-all-ordering
Open

fix: sort list_all() output in ToolRouter and PromptRouter for deterministic ordering#665
p4fg wants to merge 1 commit intomodelcontextprotocol:mainfrom
p4fg:fix/deterministic-list-all-ordering

Conversation

@p4fg
Copy link

@p4fg p4fg commented Feb 16, 2026

ToolRouter::list_all() and PromptRouter::list_all() iterate over a HashMap, which returns items in non-deterministic order. Since list_all() backs the tools/list and prompts/list MCP protocol
responses, this causes MCP clients to receive differently-ordered results across calls and process restarts, leading to suspected intermittent tool discovery failures.

This pull request sorts the output alphabetically by name to guarantee stable ordering.

Motivation and Context

MCP servers with more than a handful of tools can experience intermittent tool discovery failures in clients (e.g. Claude Code, Claude Desktop). The root cause is that HashMap iteration order is
randomized across process restarts (and potentially within a process), so every tools/list or prompts/list response returns the same set of items but in a different order.

This causes:

  • Client-side caching/diffing to see spurious diffs, triggering unnecessary tool catalog rebuilds
  • LLM tool selection instability when the tool list is re-injected into context in a different order
  • Difficult debugging since the same server behaves differently across restarts

Related: anthropics/claude-code#2682

How Has This Been Tested?

  • Added test_tool_router_list_all_is_sorted and test_prompt_router_list_all_is_sorted tests
  • Verified both tests fail without the fix (ran 10 iterations each to account for non-determinism — tool router test failed 9/10, prompt router test failed 10/10)
  • Verified both tests pass consistently with the fix (10/10 each)
  • All existing tests continue to pass

Breaking Changes

None. The output type and contents of list_all() are unchanged — only the ordering is now guaranteed to be sorted alphabetically by name.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

The fix sorts the collected Vec by name before returning. This is preferred over switching to IndexMap (insertion-order) because it provides a canonical alphabetical ordering regardless of how
tools/prompts are registered, with negligible performance cost for typical tool counts.

The IntoIterator impl on both routers also uses HashMap iteration, but it is not used in any protocol-facing context, so it was left unchanged to avoid a breaking API change.

…inistic ordering

ToolRouter::list_all() and PromptRouter::list_all() iterate over a
HashMap, which returns items in non-deterministic order. Since list_all()
backs the tools/list and prompts/list MCP protocol responses, this causes
MCP clients to receive differently-ordered results across calls and
process restarts, leading to intermittent tool discovery failures.

Sort the output alphabetically by name to guarantee stable ordering.
@github-actions github-actions bot added T-test Testing related changes T-core Core library changes T-handler Handler implementation changes labels Feb 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-core Core library changes T-handler Handler implementation changes T-test Testing related changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant