A deploy that changes the tool set never reaches a running session: tools/list_changed is neither declared nor emitted #118
Labels
No labels
blocked
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
waiting-on-julian
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
jlxq0/matrix-mcp#118
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A
matrix-mcpdeploy that adds or removes a tool does not reach any session that is already running. Observed 2026-08-25 onv0.10.3, which addeddownload_attachmenttoCHANNEL_TOOLS: the tool was absent from two separate live sessions whilewhoamireturned a bot mxid and an unchanged device id, so the mount was healthy throughout and nothing surfaced. The workaround was to call the full/mcpmount over HTTP with the same bearer token; the alternative is a restart, which costs the session's context.This nearly produced a false negative reported as "the release does not work". What prevented it was that the tool's absence had been recorded before the rollout, so absence afterwards carried no information.
What is actually missing
Two things, and they are separate:
The capability is not declared.
get_infobuildsServerCapabilities::builder().enable_tools()for both mounts (src/mcp.rs:7009,src/mcp.rs:7020). rmcp'senable_tools()leavestools.listChangedunset;enable_tool_list_changed()is what sets it totrue(rmcp 1.7model/capabilities.rs:454). A client is entitled to ignore a notification from a server that never advertised it.Nothing ever emits it. There is no
notifications/tools/list_changedanywhere insrc/— grep returns the twoenable_toolslines and nothing else. rmcp has the type (ServerNotification::ToolListChangedNotification,model.rs:1437), so this is a call that was never written rather than a gap in the SDK.Proposed change
Declare
listChanged: trueon both mounts, and emit the notification fromon_initialized— the point where a session registers, including the handshake replay a client performs after the pod is replaced. Emitting unconditionally on every registration is simpler than detecting that the set changed, and a re-list is cheap. That is the moment a session that survived a deploy is reachable again.What is not established
Whether Claude Code re-lists on receiving it. The MCP spec says a client may re-fetch; it does not have to. If Claude Code caches the tool list for the session's lifetime regardless, declaring the capability and emitting the notification changes nothing observable, and this issue closes as "not fixable from our side" rather than as done. Establish that before building on it.
Acceptance
Not "the notification is emitted", and not "the capability is declared" — both are greppable and neither is the property.
A session running against
/channelbefore a deploy, still running after it, calling a tool that did not exist when it connected and getting a result. The negative control is the same session before the change: it must fail, which it does today and which is the whole reason this issue exists.If Claude Code turns out not to re-list, say so on this issue with what was observed, and close it. A recorded negative is worth more than the workaround being rediscovered next release.
Provenance
Found during #111's acceptance run against
v0.10.3(sha256:81e26f67…), and recorded in the mantis repo'sAGENTS.mdatdf9761das an operational pitfall. This issue is the server-side half.From the Claude Code MCP docs, "Dynamic tool updates":
So the client half is not a may in practice: it refreshes. Since v2.1.214 a transient failure during that refresh keeps the previously discovered tools rather than replacing them with an empty list.
That raises the odds on the fix without settling it, because of a wrinkle specific to us. Two statements from the same page, both about the v2 runtime, which the fleet is on at 2.1.245:
list_changednotifications from a server on the newer protocol revision over a stream it holds open.Read together, our
/channelmount cannot be on the newer revision or it would not be a channel at all — so the held-open-stream path described there is not the path our notifications take.What that does not mean is that there is no path.
notifications/claude/channeldemonstrably reaches a live session on the mount we have, so a server-to-client notification transport already works on the older revision. The question narrows to whether the client's refresh handler fires fornotifications/tools/list_changedarriving that way. That is the empirical question the acceptance above already frames, and this is the reason a negative result would be plausible rather than evidence of a broken emit.Rule out
MCP_DISCOVERY_CACHEbefore trusting any result. Remote HTTP servers can serve a cached tool list from a previous session instead of connecting. It is off by default from v2.1.238 and the fleet is past that, so it should not be a factor — but a session showingcached … · 7 toolsforchannelin/mcpis a second, independent way a stale list survives a deploy, and it would be indistinguishable from the defect this issue describes. A negative result measured against a cached list means nothing.Research by the mantis session.
Next up. Triaged 2026-08-31: this is one of three I would take before anything else in my repositories.
It cost real time on 2026-08-29 and 30, in three separate confusions that all looked like different faults.
Lucy's
send_emailschema showed nobody_htmlagainst a pod that already carried it, and only a restart made the parameter visible. Mantis's m365 mount read two tools after a deploy and that was taken as the fix having failed, until somebody noticed every session predated the pod. A third session started after the account switch had a connector the others did not.Each of those was diagnosed from scratch. The general shape is that a running session's tool list is a snapshot of when it connected, and nothing anywhere says so.