Skip to content

fix(mcp): emit the cache hints 2026-07-28 requires on tools/list - #685

Merged
coseto6125 merged 2 commits into
mainfrom
chore/deps-refresh-0810
Aug 7, 2026
Merged

coseto6125 merged 2 commits into
mainfrom
chore/deps-refresh-0810

Conversation

@coseto6125

Copy link
Copy Markdown
Owner

What

ecp mcp serve hand-writes ServerHandler::list_tools, and
ListToolsResult::with_all_items leaves ttlMs / cacheScope unset. Protocol
2026-07-28 made both required on tools/list (SEP-2549 CacheableResult),
so a spec-strict client rejects the response before it ever reaches a tool call:

SdkError: Invalid result for tools/list: [
  { "expected": "number", "path": ["ttlMs"], "message": "expected number, received undefined" },
  { "code": "invalid_value", "values": ["public","private"], "path": ["cacheScope"] }
]

server/discover succeeds first, which makes it read like a client bug until you
look at the wire. rmcp only strips resultType for legacy peers — nothing fills
these in.

rmcp 3.1.1 fixed this for servers generated from #[tool_handler]
(rust-sdk#1120).
This server does not use the macro, so the upstream fix does not reach it — it is
the hand-written case the issue names as the workaround.

Why 60 s / public

The tool set is derived from the clap tree once in EcpMcpServer::new and never
changes while the process lives, so any TTL up to the session length would be
honest, and there is no per-user data in it. 60 s matches rmcp's own conformance
server and keeps a session that outlives an ecp upgrade from calling a
subcommand the new binary dropped. Peers older than 2026-07-28 predate both
fields and keep the legacy wire shape, matching how the macro gates them.

Dependency refresh

  • cargo update — rkyv 0.8.18, rmcp 3.1.1, clap 4.6.6, blake3 1.8.6, bytecheck
    0.8.3, ptr_meta 0.3.2, rancor 0.1.3, zerocopy 0.8.56 and the rest of the tree.
  • rmcp = "3" → "3.1" — this change uses RequestContext::protocol_version()
    and the ListToolsResult cache-hint builders, both 3.1.
  • taiki-e/install-action v2.85.8 → v2.85.10 — tool-manifest updates only
    (cargo-nextest 0.9.143 among them).
  • harden-runner v2.20.1 and codeql-action v4.37.6 from chore(deps): bump the all-minor-patch group with 6 updates #684 are already the
    newest releases. Neither changelog is actionable here: harden-runner's changes
    are block-mode and AWS CodeBuild (these workflows run egress-policy: audit),
    and codeql-action 4.37.6 only moves the default config-file path, which this
    repo does not set.
  • cc stays on 1.2.67 rather than 1.4.1: tree-sitter-sequel 0.3.11 pins
    cc = "~1.2.1", so nothing in the tree can move past 1.2.x until that grammar
    relaxes it.

Tests

server::tests cover the wire shape directly — serialized ttlMs / cacheScope
present for 2026-07-28 and for a version newer than any this build knows, and
absent for 2025-11-25 / 2025-06-18 / 2024-11-05 and for an unnegotiated
peer. Verified they fail without the fix (ttlMs comes back Null).

Local: cargo fmt --all --check and
cargo clippy --workspace --all-targets --all-features -- -D warnings clean;
ecp-core, ecp-mcp, ecp-cli (1281) and ecp-analyzer (2515) test suites all green.

`ListToolsResult::with_all_items` leaves `ttlMs` and `cacheScope` unset,
and rmcp only strips `resultType` for legacy peers — nothing fills these
in. Protocol 2026-07-28 made both fields required on `tools/list`
(SEP-2549 `CacheableResult`), so a strict client rejects the response
before it reaches a tool call: the TypeScript SDK 2.0.0 client fails with
`Invalid result for tools/list: expected number, received undefined` at
`ttlMs`. `server/discover` succeeds first, which makes it read like a
client bug until you look at the wire.

rmcp 3.1.1 fixes this for servers built from `#[tool_handler]`
(modelcontextprotocol/rust-sdk#1120). This server hand-writes
`ServerHandler::list_tools`, so the macro fix does not reach it.

The tool set is derived from the clap tree once in `EcpMcpServer::new`
and never changes while the process lives, so the hint is public and any
TTL up to the session length would be honest; 60s matches rmcp's own
conformance server and keeps a session that outlives an `ecp` upgrade
from calling a subcommand the new binary dropped. Peers older than
2026-07-28 predate both fields and keep the legacy wire shape, matching
how the macro gates them.

Alongside: `cargo update` (rkyv 0.8.18, rmcp 3.1.1, clap 4.6.6, blake3
1.8.6 and their transitive set), and `taiki-e/install-action` to v2.85.10
— tool-manifest updates only, cargo-nextest 0.9.143 among them.
clippy::items_after_test_module (-D warnings in CI) rejects any item
declared after a `#[cfg(test)] mod`.
@coseto6125
coseto6125 enabled auto-merge (squash) August 7, 2026 18:53
@coseto6125 coseto6125 added the merge-queue Opt-in to Mergify merge queue label Aug 7, 2026
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor
ecp impact cache (0 symbols) — internal, used by ecp dev pr-analyze

[]

@github-actions github-actions Bot added the ecp:risk-low ecp signal label Aug 7, 2026
@coseto6125
coseto6125 merged commit d22c0ed into main Aug 7, 2026
18 checks passed
@coseto6125
coseto6125 deleted the chore/deps-refresh-0810 branch August 7, 2026 19:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ecp:risk-low ecp signal merge-queue Opt-in to Mergify merge queue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant