Summary
start_debugging, restart_debugging and attach_to_process have no in-flight guard beyond the session state. restart_debugging refuses only while the session is initializing; a JavaScript launch projects running the moment the child session is adopted (the configured status, #704) while start_debugging is still parked on the js-debug launch barrier's stop window. In that window a concurrent restart_debugging (or a second start_debugging/attach_to_process on the same session) passes the guard, stopProxyPreservingSession disposes the barrier the first call is awaiting, the first call's handshake swallows the rejection, reads running, takes the already-ready path and returns success: true for a proxy that is being torn down; the second call relaunches and also returns success.
Before #704 the same could happen when a continued event flipped a pending launch to running (seen in server logs), so this is a pre-existing approximation made deterministic and shorter (~0.5 s) rather than a new hole. The MCP SDK dispatches tool calls concurrently on every transport, and tool-dispatch.ts has no per-session queue; restartingSessions covers restarts only.
Found by the review of PR #708.
What would help
An explicit in-flight-launch set in DebugLauncher (set on startDebugging entry, cleared in finally, consulted by startDebugging, restartDebugging and attachToProcess) that answers a concurrent call with a clear "a launch is in progress" error instead of relying on the state machine.
Refs #704, #708.
Summary
start_debugging,restart_debuggingandattach_to_processhave no in-flight guard beyond the session state.restart_debuggingrefuses only while the session isinitializing; a JavaScript launch projectsrunningthe moment the child session is adopted (the configured status, #704) whilestart_debuggingis still parked on the js-debug launch barrier's stop window. In that window a concurrentrestart_debugging(or a secondstart_debugging/attach_to_processon the same session) passes the guard,stopProxyPreservingSessiondisposes the barrier the first call is awaiting, the first call's handshake swallows the rejection, readsrunning, takes the already-ready path and returnssuccess: truefor a proxy that is being torn down; the second call relaunches and also returns success.Before #704 the same could happen when a
continuedevent flipped a pending launch torunning(seen in server logs), so this is a pre-existing approximation made deterministic and shorter (~0.5 s) rather than a new hole. The MCP SDK dispatches tool calls concurrently on every transport, andtool-dispatch.tshas no per-session queue;restartingSessionscovers restarts only.Found by the review of PR #708.
What would help
An explicit in-flight-launch set in
DebugLauncher(set onstartDebuggingentry, cleared infinally, consulted bystartDebugging,restartDebuggingandattachToProcess) that answers a concurrent call with a clear "a launch is in progress" error instead of relying on the state machine.Refs #704, #708.