You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
MCP client advertises roots capability but drops server-initiated requests #59
The MCP client declares roots in its client capabilities during the handshake, but the inbound message handler treats every message as a response and silently drops server-initiated requests. A server that trusts the advertisement and calls roots/list never gets a reply — it just waits until its own timeout.
Details
Capabilities sent on both transports (src/mcp/client.ts:244 and :315 on main):
The stdio read path (_flush, src/mcp/client.ts:460-462):
if(typeofmsg.id!=="number")continue;// ignore notifications from serverconstp=this._pending.get(msg.id);if(!p)continue;// <- server-initiated request lands here and is dropped
An inbound roots/list request carries an id, matches no entry in _pending, and falls out at the second continue. No response is ever written, and there's no branch anywhere that inspects msg.method on an inbound message — so no server-initiated request of any kind can be served, not just roots.
Effect: a well-behaved server that checks client capabilities and asks for roots blocks for its full request timeout on the very first exchange.
Why it's worth fixing
roots is how a server learns which workspace the client is operating in. Servers that scope their state per-project need it. I ran into this from the other side: agentmemory's MCP tools take a project argument with no way to discover the right value (rohitg00/agentmemory#1225), and roots is the standard mechanism that would solve it — except a server can't rely on it here, because the capability is advertised but not served.
Advertising a capability that isn't implemented is also worse than not advertising it: a server that feature-detects correctly is punished with a hang, while one that ignores capabilities works fine.
Two ways to fix
Implement it. Handle inbound requests in _flush by branching on msg.method, and answer roots/list with the current projectRoot as a file:// URI. Small, and it makes the existing advertisement true.
Stop advertising it. Drop roots from the two capability objects. One line, and it makes servers fall back to whatever they do for clients without roots.
Either is correct; (1) is more useful, (2) is the honest minimum. Happy to send a PR for whichever you prefer.
Note
Unrelated to #58, which is open against src/mcp/client.ts — that change is confined to _request and the timeout constants and doesn't touch _flush.
Activity