What is the tools list_changed notification, and when should a server send it?
Quick Answer
notifications/tools/list_changed tells a client that the server's set of available tools has changed — a tool was added, removed, or had its definition modified — and the client should call tools/list again to refresh its cached copy. A server should only send this if it declared the tools.listChanged capability during initialization, and only when tools genuinely change at runtime (e.g., a server that dynamically exposes different tools depending on which account the user authenticated as, or one that adds tools once a slow initial setup step completes). A server whose tool set is fixed for its whole lifetime never needs to send it at all.
Detailed Answer
Not every server needs dynamic tools. But the ones that do need a way to tell the client its cached list is stale.
Example scenario
A server that wraps a project-management API might expose different tools depending on the workspace the user is authenticated into: create_ticket, assign_ticket, and, only for admins, delete_workspace. If the user re-authenticates into a workspace with different permissions, the tool set legitimately changes mid-session.
// Server -> Client, after tools change
{"jsonrpc": "2.0", "method": "notifications/tools/list_changed"}
// Client reacts by re-fetching
{"jsonrpc": "2.0", "id": 12, "method": "tools/list"}
Preconditions for sending it
- The server must have declared
"capabilities": {"tools": {"listChanged": true}}duringinitialize. Sending the notification without declaring support for it is a spec violation the client isn't obligated to react to. - It should only fire on a genuine change, not speculatively or on a timer. Spamming this notification defeats its purpose — the client would end up re-fetching constantly for no reason — and can cause visible UI churn in hosts that refresh a tool picker on receipt.
When you don't need it at all
A server with a static tool set never needs to send this notification. That's the common case for most single-purpose servers, like a Postgres server that always exposes query and list_tables. It shouldn't declare listChanged: true for a capability it never actually uses. Declaring a capability you don't implement is arguably worse than not declaring it, since it invites a client to expect behavior that never arrives.