Skip to content

feat(tools-list): check deterministic tools/list ordering on the 2026-07-28 wire - #492

Open
AmirK-S wants to merge 1 commit into
modelcontextprotocol:mainfrom
AmirK-S:tools-list-deterministic-order
Open

feat(tools-list): check deterministic tools/list ordering on the 2026-07-28 wire#492
AmirK-S wants to merge 1 commit into
modelcontextprotocol:mainfrom
AmirK-S:tools-list-deterministic-order

Conversation

@AmirK-S

@AmirK-S AmirK-S commented Sep 6, 2026

Copy link
Copy Markdown

Discussion: #491.

Requirement

docs/specification/2026-07-28/server/tools.mdx, "Capabilities", lines 71 to 74:

Servers SHOULD return tools in a deterministic order (i.e., the same ordering across requests when the underlying set of tools has not changed). Deterministic ordering enables clients to reliably cache the tool list and improves LLM prompt cache hit rates when tools are included in model context.

https://modelcontextprotocol.io/specification/2026-07-28/server/tools#capabilities

New in 2026-07-28 (absent from 2025-11-25), introduced by modelcontextprotocol/modelcontextprotocol#2516 (not a SEP, so no src/seps/ row). No scenario exercised it before this PR.

What changes

One check added to the existing tools-list scenario (src/scenarios/server/tools.ts), no new scenario, no change to requirements/*.yaml, no src/seps/ row since the sentence does not come from a SEP.

Check Keyword Severity Stimulus Outcome
tools-list-deterministic-order SHOULD WARNING three consecutive tools/list requests, from the 2026-07-28 wire on (source.introducedIn: '2026-07-28', a literal since the revision is published and dated) SUCCESS when the three name sequences are identical; WARNING when the same multiset of names comes back in a different order (first divergent probe and index in errorMessage, the three orders in details.orders); untestable under the #248 policy (Not testable: ..., details.untestable: true, WARNING severity) when the multiset changed between probes, since the spec scopes the SHOULD to an unchanged set; INFO when no probe saw two tools

The helper buildToolsListDeterministicOrderCheck(snapshots) is exported and unit-tested, following buildToolsNameFormatCheck. A failure of a repeated tools/list request is reported as untestable on the new check (via untestableCheck()) instead of turning tools-list itself red. The neighbouring MUST NOT on connection-invariance is deliberately left out, following #332.

Prove it passes and fails

  • Passing: all-scenarios.test.ts already runs tools-list against the everything-server on both wires; on 2026-07-28 the new check is SUCCESS.
  • Failing: examples/servers/typescript/tools-list-rotated-order.ts speaks the sessionless 2026-07-28 wire, advertises the same four tools and rotates the list by one position on every tools/list. The new negative.test.ts case asserts WARNING on tools-list-deterministic-order and SUCCESS on tools-list against it.
node dist/index.js server --url http://localhost:3124/mcp --scenario tools-list --spec-version 2026-07-28
[tools-list                    ] SUCCESS Server lists available tools with valid structure
[tools-name-format             ] SUCCESS Tool names are 1-64 characters and match ^[A-Za-z0-9_./-]+$
[tools-list-deterministic-order] WARNING Consecutive tools/list requests return the same tools in the same order
[wire-schema-valid             ] SUCCESS Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version
Passed: 3/3, 0 failed, 1 warnings

Runs against real SDKs

typescript-sdk main as of 2026-09-05 (5119ee7fd779), npm start -- sdk typescript-sdk --mode server --scenario tools-list --spec-version 2026-07-28:


Passed: 4/4, 0 failed, 0 warnings

python-sdk main as of 2026-09-05 (7bb486a10fa6), npm start -- sdk python-sdk --mode server --scenario tools-list --spec-version 2026-07-28:

[server] [09/05/26 20:20:35] INFO     Starting MCP Everything Server on     server.py:805
[server] [09/05/26 20:20:36] INFO     Created new          streamable_http_manager.py:325
[server] [09/05/26 20:20:37] INFO     StreamableHTTP       streamable_http_manager.py:166
Passed: 4/4, 0 failed, 0 warnings

Local CI

npm run check and npm run build pass. npm test: 44 files, 536 passed, 0 failed (524 on main plus the 12 added here). The three "Unhandled Rejection" entries vitest reports are present on main before this change.

Notes for review

  • Three probes rather than two, so that a shuffling server cannot pass by repeating one order by chance as easily; happy to change the count.
  • The set-changed case is reported as untestable rather than skipped, per the Standardize how scenarios report setup/execution failures #248 policy, and rather than as a violation, because the spec text itself carves it out. This is where Add SEP-2567 (sessionless Streamable HTTP) conformance coverage #332's sampling concern applied to connection-invariance; here the carve-out is normative, not heuristic. It still surfaces as a WARNING, which CI treats as a failure; SKIPPED or a retry until the set is stable are the alternatives if you prefer.
  • requirements/2026-07-28.yaml lists tools-list as scored and is frozen at scenario granularity, so this check raises the bar for a shipped revision. The requirement is 2026-07-28 text, so I left the file untouched; see tools-list: cover the 2026-07-28 SHOULD on deterministic tools/list ordering #491 for the question, and I will follow whatever you decide.
  • The new check id will appear in untracked in src/seps/traceability.json at the next refresh, for lack of a yaml row.

AI disclosure

Per AI_POLICY.md: this PR, the fixture and the tests were written primarily by Claude Code, pointed at this one SHOULD as AGENTS.md asks, under my direction. Review replies may be AI-assisted as well.

…-07-28 wire

The 2026-07-28 revision adds to server/tools.mdx: "Servers SHOULD return
tools in a deterministic order (i.e., the same ordering across requests
when the underlying set of tools has not changed)." Nothing in the suite
exercised it.

Add a tools-list-deterministic-order check to the existing tools-list
scenario. From the 2026-07-28 wire on, the scenario takes two more
consecutive tools/list snapshots and compares the three name sequences.
Same multiset of names, different order is WARNING (SHOULD). A set that
changed between probes is reported as untestable rather than as a
violation, because the spec scopes the SHOULD to an unchanged set. Fewer
than two tools on every probe is INFO. The check carries
source.introducedIn '2026-07-28', written as a literal since that revision
is published and dated, so runners drop it on earlier wires.

Prove it fails: examples/servers/typescript/tools-list-rotated-order.ts
advertises the same four tools and rotates the list by one position per
call; a negative.test.ts case asserts WARNING while tools-list itself
still passes. Unit tests cover the helper that builds the check.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BjeC3sCvfHRpdEPz2x41B2
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