Skip to content

fix(mcp): emit SEP-2549 cache hints on tools/list for 2026-07-28 peers - #1187

Merged
skakri merged 1 commit into
mainfrom
chore/rmcp-bump
Aug 16, 2026
Merged

skakri merged 1 commit into
mainfrom
chore/rmcp-bump

Conversation

@skakri

@skakri skakri commented Aug 16, 2026

Copy link
Copy Markdown
Member

Problem

Clients that negotiate MCP protocol version 2026-07-28 require ttlMs and cacheScope on list results (SEP-2549) and reject a tools/list response without them:

Invalid result for tools/list:
  ttlMs: Invalid input: expected number, received undefined
  cacheScope: Invalid option: expected one of "public"|"private"

Because the rejection happens at tools/list, the server connects with no tools at all — every session against a strict 2026-07-28 client is bricked.

Fix

The hand-written ServerHandler::list_tools now emits immediately-stale public cache hints (ttlMs: 0, cacheScope: "public") when the negotiated protocol version is 2026-07-28 or newer, and keeps the pre-SEP-2549 wire shape for legacy peers that may reject unknown fields. This mirrors what rmcp's #[tool_handler] macro does since 3.1.1 (modelcontextprotocol/rust-sdk#1120) — the macro fix doesn't reach hand-written handlers, so the gate is applied at our handler.

ttlMs: 0 deliberately opts out of client-side caching: the catalog is static per binary, not per server identity — hot-upgrade (SIGUSR1 exec) and version bumps can change it with no client-visible signal, and the only fetch it would save is one local stdio round trip per session. A real TTL should only land together with tools/listChanged wiring.

Also bumps rmcp 3.0.1 → 3.1.2.

Verification

  • Two new tests drive tools/list through a real in-process client/server pair (rmcp client feature as a dev-dependency, scoped out of the production feature set by resolver 3), asserting the hints are present for a 2026-07-28 peer and absent for a legacy peer; the positive test fails if the gate is reverted.
  • Full rag-rat-mcp suite green under nextest and cargo test; clippy --no-default-features and default-features legs clean under -D warnings; nightly rustfmt applied.

Clients that negotiate MCP protocol 2026-07-28 require `ttlMs` and
`cacheScope` on list results (SEP-2549). The hand-written `list_tools`
handler left both unset, so strict clients rejected the tools/list
response outright and the server connected with no tools at all.

Emit immediately-stale public hints (`ttlMs: 0`, `cacheScope: public`)
when the negotiated version is 2026-07-28 or newer — preserving the
pre-SEP-2549 no-caching behavior — and keep the old wire shape for
legacy peers, mirroring what rmcp's `#[tool_handler]` macro does since
rmcp 3.1.1. Also bumps rmcp 3.0.1 -> 3.1.2.

Covered by an in-process client/server test pair asserting the hints
are present for a 2026-07-28 peer and absent for a legacy one.
@github-actions

Copy link
Copy Markdown
Contributor

SCIP oracle — resolution report

Heuristic→compiler edge resolution per corpus. Δ compares resolved-after to the main baseline (only when the corpus profile + tool version match).

corpus tool edges resolved (heuristic → compiler) precision recall monikers Δ vs main
c-libuv scip-clang 12894 37.9% → 48.6% 90.2% 55.3% 679 — (no baseline)
cpp-yaml scip-clang 9423 43.2% → 72.9% 82.5% 40.9% 1056 — (no baseline)
py-django scip-python 12937 28.8% → 73.5% 96.7% 84.1% 3701 — (no baseline)
py-rich scip-python 8383 27.6% → 92.3% 95.0% 81.3% 1196 — (no baseline)
rust-time rust-analyzer 11040 37.6% → 59.1% 72.7% 83.6% 574 — (no baseline)
ts-rxjs scip-typescript 7875 39.6% → 94.9% 87.3% 77.4% 631 — (no baseline)

resolved = Exact/Syntactic + compiler upgrades + resolved-external, over edge candidates with a callee range. precision/recall are the oracle eval metrics.

@codecov

codecov Bot commented Aug 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@github-actions

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Projectrag-rat
Branchchore/rmcp-bump
Testbedubuntu-latest

⚠️ WARNING: No Threshold found!

Without a Threshold, no Alerts will ever be generated.

Click here to create a new Threshold
For more information, see the Threshold documentation.
To only post results if a Threshold exists, set the --ci-only-thresholds flag.

Click to view all benchmark results
BenchmarkEstimated Cyclescycles x 1e6Instructionsinstructions x 1e6L1 Hitshits x 1e6LL Hitshits x 1e6RAM Hitshits x 1e3Total read+writereads/writes x 1e6
rag_pipeline::pipeline::index cargo_resolver:resolver_config()📈 view plot
⚠️ NO THRESHOLD
1,952.53 x 1e6📈 view plot
⚠️ NO THRESHOLD
1,233.57 x 1e6📈 view plot
⚠️ NO THRESHOLD
1,714.18 x 1e6📈 view plot
⚠️ NO THRESHOLD
38.64 x 1e6📈 view plot
⚠️ NO THRESHOLD
1,290.64 x 1e3📈 view plot
⚠️ NO THRESHOLD
1,754.11 x 1e6
rag_pipeline::pipeline::query_cold cargo_resolver:resolver_built_config()📈 view plot
⚠️ NO THRESHOLD
340.60 x 1e6📈 view plot
⚠️ NO THRESHOLD
226.81 x 1e6📈 view plot
⚠️ NO THRESHOLD
323.73 x 1e6📈 view plot
⚠️ NO THRESHOLD
3.15 x 1e6📈 view plot
⚠️ NO THRESHOLD
31.66 x 1e3📈 view plot
⚠️ NO THRESHOLD
326.92 x 1e6
rag_pipeline::pipeline::query_warm cargo_resolver:resolver_index()📈 view plot
⚠️ NO THRESHOLD
314.11 x 1e6📈 view plot
⚠️ NO THRESHOLD
208.79 x 1e6📈 view plot
⚠️ NO THRESHOLD
298.39 x 1e6📈 view plot
⚠️ NO THRESHOLD
2.91 x 1e6📈 view plot
⚠️ NO THRESHOLD
32.98 x 1e3📈 view plot
⚠️ NO THRESHOLD
301.34 x 1e6
🐰 View full continuous benchmarking report in Bencher

@github-actions

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Projectrag-rat
Branchchore/rmcp-bump
Testbedubuntu-latest
Click to view all benchmark results
BenchmarkLatencyBenchmark Result
seconds (s)
(Result Δ%)
Upper Boundary
seconds (s)
(Limit %)
index_time/full_rebuild_cargo📈 view plot
🚷 view threshold
5.93 s
(+6.23%)Baseline: 5.58 s
6.32 s
(93.83%)
🐰 View full continuous benchmarking report in Bencher

@skakri
skakri merged commit b1160f1 into main Aug 16, 2026
29 checks passed
@skakri
skakri deleted the chore/rmcp-bump branch August 16, 2026 22:39
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