What it does
The `notifications/tools/list_changed` notification is sent by the server to the client whenever the set of available tools changes at runtime. This covers a range of state transitions: a server may dynamically register or deregister tools in response to user authentication, resource availability, feature flags, or external system state changes. The notification carries no payload — it is a pure signal whose only meaning is "your cached tool list is stale; fetch again." Upon receiving this notification, the client must issue a fresh `tools/list` request to obtain the updated inventory. Clients that maintain a local cache of tool definitions are required to invalidate and refresh that cache before dispatching any subsequent tool call, since acting on a stale list risks calling tools that no longer exist or missing newly available ones. Capability gating is strict: the server must advertise `tools.listChanged: true` inside its `capabilities` object during the `initialize` handshake. If that capability is absent, the server must not emit this notification, and a well-behaved client may safely ignore or log-warn any unexpected instance it receives. There are no delivery-order guarantees relative to in-flight tool calls — a client must handle the case where a `tools/call` response arrives after the notification but before the re-list completes.
When to use
When tools are added, removed, or renamed.
When NOT to use
For every internal state change.
Notes
Capability must be declared at initialize
The server declares `tools.listChanged: true` in its `ServerCapabilities` during the `initialize` handshake. If this field is missing or false, emitting the notification is a protocol violation. Clients that receive it without the capability being declared should log a warning and optionally re-list defensively, but must not crash or disconnect.
Race condition with in-flight tool calls
No ordering guarantee exists between this notification and responses to concurrent `tools/call` requests. A tool call dispatched before the notification arrives may still succeed if the server processes it before removing the tool, or may return an error if the tool was already deregistered. Clients must treat an unexpected `method not found` or tool-not-available error as a soft signal to trigger a re-list rather than a hard failure.
Cache invalidation is the receiver's responsibility
The notification itself contains no diff — no list of added or removed tool names. The client owns the re-list cycle entirely: it must call `tools/list` (handling pagination via `cursor` if the tool set is large) and replace its entire cached inventory atomically. Partial or incremental updates are not supported by the protocol.
SDK differences in handling
Higher-level SDKs (e.g., the official TypeScript MCP SDK) wire this notification to an internal event emitter and automatically trigger a re-list, exposing the result via a reactive tool-list observable. Lower-level or custom clients must handle the `notifications/tools/list_changed` method name explicitly in their notification dispatch table and implement the re-list loop manually.
Examples
Tools changed
{ "method": "notifications/tools/list_changed" }