MCP: tools list is not refreshed on notifications/tools/list_changed (stale tools until session restart)

Status Closed — duplicate
Reported on v2.1.215
Maintainer reply None cached
Activity 1 comment · opened Jul 21, 2026 · closed Aug 15, 2026

Summary

Claude Code caches the MCP tools/list result at connection time and never refreshes it, even when the MCP server explicitly sends a notifications/tools/list_changed notification. Tools added to a server after the session started remain invisible for the whole session. The only workaround is to start a brand new chat.

This defeats much of the purpose of an MCP aggregating gateway, whose main value is that backends can be added and removed at runtime without restarting any client.

Environment

  • Claude Code: 2.1.215
  • OS: Windows 11 Pro (10.0.28000)
  • MCP server: MCPJungle v0.4.5 (aggregating gateway), transport streamable_http, endpoint http://127.0.0.1:18080/mcp
  • Server capabilities as reported in initialize: {"tools":{"listChanged":true}}

Expected behavior

Per the MCP specification, a server that declares tools.listChanged: true may send notifications/tools/list_changed when its tool set changes. A client receiving this notification is expected to re-issue tools/list, so newly available tools become usable in the current session.

Actual behavior

The notification is delivered by the server but has no effect on the client: the tool set stays frozen at whatever it was when the session connected. New tools are not callable until the user opens a new chat.

Verification that the server side is correct

The notification really is sent — measured directly, bypassing Claude Code, with plain curl against the same gateway endpoint the client uses.

  1. Open a session and complete the handshake:
SESSION=$(curl -s -i -X POST http://127.0.0.1:18080/mcp \
  -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"probe","version":"1"}}}' \
  | tr -d '\r' | grep -i '^Mcp-Session-Id:' | cut -d' ' -f2)

curl -s -X POST http://127.0.0.1:18080/mcp \
  -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
  -H "Mcp-Session-Id: $SESSION" -d '{"jsonrpc":"2.0","method":"notifications/initialized"}'
  1. Listen on the SSE channel:
timeout 40 curl -s -N -X GET http://127.0.0.1:18080/mcp \
  -H "Accept: text/event-stream" -H "Mcp-Session-Id: $SESSION" > sse-out.txt
  1. While the listener is running, register a new backend server in the gateway.

Result: 12 notifications arrived (one per tool exposed by the newly registered server):

event: message
data: {"jsonrpc":"2.0","method":"notifications/tools/list_changed","params":{}}
... (12 total)

Control run: the same listener with no registry change produced 0 notifications over 20 seconds — so the server is not spamming, it emits strictly on actual change.

Conclusion: the gateway declares listChanged: true and does deliver the notification. The client does not act on it.

Steps to reproduce

  1. Connect Claude Code to an MCP server that declares tools.listChanged: true (any aggregating gateway; MCPJungle v0.4.5 was used here).
  2. Start a Claude Code session and confirm the current tool list.
  3. Without touching Claude Code, add a new backend/tool to that MCP server, so it emits notifications/tools/list_changed.
  4. In the same session, try to use the new tool, or search for it.

Expected: the new tool becomes available in the running session.
Actual: the tool is not found; it only appears after starting a new chat.

Additional notes

  • Calling the new tool through a direct JSON-RPC tools/call to the gateway (outside the client's tool layer) works fine, which confirms the gateway and its routing are healthy — only the client's cached tool list is stale.
  • This matters most for gateways that manage backends dynamically. In our setup, 1C databases are connected to a proxy at arbitrary times under user-chosen channel names, and the gateway registers each one automatically. Every such addition currently requires every open agent session to be restarted before the new database can be used.

Suggested fix

Subscribe to notifications/tools/list_changed on servers that advertise tools.listChanged: true, and re-issue tools/list when it fires (debounced — as shown above, a single registration can emit one notification per tool).

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗