[BUG] MCP tools/list and resources/list rejected as invalid when optional ttlMs/cacheScope cache hints are omitted (protocol 2026-07-28)

Status Open
Reported on v2.1.237
Maintainer reply None cached
Activity 0 comments · opened Aug 20, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet (closest related: #88075, same MCP 2026-07-28 rollout, different field — elicitation, not cache hints; #88049, same failure class — one bad field silently drops an entire server's tools — different trigger)
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code (2.1.237)

What's Wrong?

When an MCP server negotiates protocol version 2026-07-28 and its tools/list or resources/list response omits the optional ttlMs/cacheScope cache-hint fields, Claude Code's client-side validator rejects the entire response as invalid:

tools/list failed (Invalid result for tools/list: [
  { "path": ["ttlMs"], "code": "invalid_type", "message": "Invalid input: expected number, received undefined" },
  { "path": ["cacheScope"], "code": "invalid_value", "message": "Invalid option: expected one of \"public\"|\"private\"" }
])

It retries 4 times (250ms/500ms/1000ms/1000ms backoff), then gives up permanently for the session: "Failed to fetch tools". Every tool from that server then silently disappears — no error is ever surfaced to the user or to the model. The agent has no indication the server ever existed; it just has fewer tools than its own configuration grants it.

Confirmed this isn't a broken/misbehaving server: the identical server (an rmcp-based Rust MCP server, v3.1.2) served the exact same unmodified response successfully to a different MCP client (Goose) within minutes of the Claude Code failures — same binary, same tool set, same missing fields, different client, no error.

Also confirmed ttlMs/cacheScope are meant to be optional, not required: in rmcp 3.1.2 (the reference Rust SDK), both fields are Option<T> with #[serde(skip_serializing_if = "Option::is_none")], and the crate's own test suite has a dedicated, passing test (cache_hints_are_omitted_when_absent) asserting that a tools/list response with the fields fully absent is valid and expected. Claude Code's validator disagrees with the reference SDK's own test suite on this point.

What Should Happen?

ttlMs and cacheScope should be treated as optional cache hints. When absent, Claude Code should treat the response the same as it would if the fields were present with "no caching hint" (i.e., don't cache, or use existing defaults) — not reject the entire tools/list/resources/list response and permanently drop the server's tools for the session.

Error Messages/Logs

From ~/.cache/claude-cli-nodejs/<project>/mcp-logs-<server>/*.jsonl (genericized; full field names/messages are exact, server name/session IDs redacted as they're local identifiers, not part of the bug):

{"debug":"Connection established with capabilities: {\"hasTools\":true,...,\"negotiatedProtocolVersion\":\"2026-07-28\"}"}
{"debug":"resources/list failed (Invalid result for resources/list: [{\"expected\":\"number\",\"code\":\"invalid_type\",\"path\":[\"ttlMs\"],\"message\":\"Invalid input: expected number, received undefined\"},{\"code\":\"invalid_value\",\"values\":[\"public\",\"private\"],\"path\":[\"cacheScope\"],\"message\":\"Invalid option: expected one of \\\"public\\\"|\\\"private\\\"\"}]); retrying in 250ms"}
{"debug":"tools/list failed (Invalid result for tools/list: [... same shape ...]); retrying in 500ms"}
{"error":"Failed to fetch resources: Invalid result for resources/list: [... same shape ...]"}
{"error":"Failed to fetch tools: Invalid result for tools/list: [... same shape ...]"}

Steps to Reproduce

Minimal, SDK-agnostic repro: any MCP stdio server that negotiates 2026-07-28 and replies to tools/list with exactly

{ "resultType": "complete", "tools": [ { "name": "example", "inputSchema": { "type": "object" } } ] }

(i.e. no ttlMs/cacheScope keys at all) triggers the identical validation error — no Rust/rmcp required to reproduce it. Register such a server (~/.claude.json mcpServers or .mcp.json), start a session, and check ~/.cache/claude-cli-nodejs/<project>/mcp-logs-<server-name>/*.jsonl: Connection established (protocol 2026-07-28) is immediately followed by tools/list failed / resources/list failed, then Failed to fetch tools / Failed to fetch resources. None of that server's tools are ever available in the session — no error is shown in the transcript or to the model; the tools are simply absent.

Claude Model

Not sure / Multiple models

(Not relevant to root cause — this happens at MCP connection/tool-list time, before any model sees the tool set.)

Is this a regression?

Yes, this worked in a previous version

Directly tested, not inferred: I ran the CLI binary for v2.1.39 against the exact same live aptu-coder server (unmodified, same process) that fails on v2.1.236/v2.1.237. The old client connects and lists all 7 tools cleanly — no tools/list failed, no resources/list failed, no protocol-version field even present in its connection log (that mechanism didn't exist yet):

Successfully connected to stdio server in 234ms
Connection established with capabilities: {"hasTools":true,"hasResources":true,"serverVersion":{"name":"aptu-coder","version":"0.29.0"}}

Same server, same point in time, only the client binary differs. This confirms the failure is a client-side regression, not something that depends on server state.

Update (2026-08-20): Confirmed and resolved server-side in aptu-coder 0.29.1 (clouatre-labs/aptu-coder#1393, #1395) by explicitly setting ttlMs/cacheScope on tools/list and resources/list responses. This restores the tool/resource surface in Claude Code, confirming the root cause and that no other factor is involved — but it required a server-side workaround for fields the reference SDK (rmcp) treats as optional. The validator behavior described above still needs fixing so servers following the SDK's documented optional-field contract aren't forced to add explicit cache hints just to remain visible to Claude Code.

Last Working Version

v2.1.39 confirmed working (tested directly, per above). A separate, already-filed issue (#88075) places the 2026-07-28 protocol rollout at v2.1.235 (2026-08-18); the exact last-working version between 2.1.39 and 2.1.234 is not narrowed further.

Claude Code Version

2.1.237 (Claude Code)

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux (Ubuntu 24.04.4 LTS)

Terminal/Shell

Other (Kitty terminal — TERM=xterm-kitty, zsh shell)

View original on GitHub ↗