MCP: notifications/tools/list_changed not acted on mid-session

Resolved 💬 3 comments Opened May 24, 2026 by phallguy Closed May 24, 2026

Summary

When an MCP server sends a notifications/tools/list_changed notification mid-session, Claude Code does not re-fetch the tool list or inject the updated schemas into context. The notification is silently ignored.

Why this matters

This is a core MCP spec capability that would enable lazy-loading patterns — starting a session with a lightweight proxy server that exposes only a discovery tool, then dynamically registering the full tool set of a downstream server (e.g. Linear, GitHub) on demand. This would meaningfully reduce baseline context usage for users running many MCP servers.

Reproduction

A minimal repro server is straightforward to write:

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";

let phase2 = false;

const server = new Server(
  { name: "refresh-test", version: "1.0.0" },
  { capabilities: { tools: {} } }
);

server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: phase2
    ? [{ name: "trigger_refresh", ... }, { name: "hello_world", ... }]
    : [{ name: "trigger_refresh", ... }]
}));

server.setRequestHandler(CallToolRequestSchema, async (req) => {
  if (req.params.name === "trigger_refresh") {
    phase2 = true;
    await server.notification({ method: "notifications/tools/list_changed" });
    return { content: [{ type: "text", text: "Notification sent." }] };
  }
  if (req.params.name === "hello_world") {
    return { content: [{ type: "text", text: "Dynamic registration works!" }] };
  }
});

await server.connect(new StdioServerTransport());

Steps to reproduce:

  1. Configure this server in ~/.claude.json under mcpServers
  2. Start a fresh Claude Code session — only trigger_refresh is available
  3. Ask the agent to call trigger_refresh — server flips to phase 2 and sends the notification
  4. Ask the agent to call hello_world

Expected: hello_world is available and callable without restarting the session.

Actual: agent reports hello_world is not in its tool list. Restarting the session causes hello_world to appear (confirming the server-side state is correct and tools/list returns the updated list — the notification just isn't acted on).

Notes

  • Tested on Claude Code as of May 2026
  • Same behaviour observed in Cursor CLI (filed separately with Cursor)
  • The MCP spec defines notifications/tools/list_changed in the server-to-client notifications section — the client is expected to issue a fresh tools/list request when it receives this notification

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗