anthropics / anthropics/claude-code

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

Aperta
#88,128 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub
area:mcp bug has repro platform:linux
Lingua principale
Python
Stelle
145k
Fork
23.1k
Metriche di merge delle PR
Metriche PR in attesa

Descrizione

### 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` 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//mcp-logs-/*.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

```json
{ "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//mcp-logs-/*.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](https://github.com/clouatre-labs/aptu-coder/pull/1393), [#1395](https://github.com/clouatre-labs/aptu-coder/pull/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)

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Direzione di ricerca

Start by reproducing the issue with a minimal MCP stdio server using the `tools/list` and `resources/list` entry points, then trace validation for protocol version `2026-07-28`. Done means responses omitting `ttlMs` and `cacheScope` are accepted and the server's tools and resources remain available without retries or silent removal.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Ambito
api, cli
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Attiva
Chiarezza
Abbastanza chiara
Idoneità per principianti
48/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.