Repository navigation
Description
Summary
state-mcp server processes accumulate heavily on a long-running Copilot development host. One inventory found 422 matching processes arranged under 107 launcher roots. Each bridge used a four-process wrapper chain:
cmd.exe → node npx-cli.js → cmd.exe "squad state-mcp" → node cli-entry.js
The global Copilot MCP config declared duplicate hashed bridge entries, so a single lingering Copilot session could retain roughly eight Squad-related processes. The roots still had live copilot.exe / copilot-runtime.exe parents, so they were not killed as orphans; however, Squad can substantially reduce the amplification and should terminate promptly when its transport closes.
Environment
- Squad CLI
2.0.0-preview.1, installed from the exact published release tarball - Windows 11
- Node.js 22
- CFS-only npm host (
https://packagefeedproxy.microsoft.io/npm/) - Long-running Copilot development host with both global hashed MCP entries and a repo
.mcp.json
Repro
$all = Get-CimInstance Win32_Process
$stateMcp = $all | Where-Object { $_.CommandLine -match 'state-mcp' }
$stateMcp | Measure-Object
$stateMcp | Select-Object ProcessId, ParentProcessId, Name, CommandLineOpen and close multiple Copilot sessions in repositories that have both a repo squad_state declaration and hashed global declarations, then repeat the inventory.
Observed
422 processes matching state-mcp
107 launcher roots
63 distinct live copilot.exe / copilot-runtime.exe parents
The repeated launch shape was:
cmd.exe → node npx-cli.js → cmd.exe → node cli-entry.js
There were no parent-gone roots in the captured snapshot; the process retention begins with lingering host sessions, but duplicate declarations and wrapper processes multiply the footprint.
Expected
- One effective Squad state bridge declaration per project/session.
- Direct launch of the installed CLI entry point without
npx/cmdwrapper layers. - The MCP server exits when stdin/transport closes or its parent session is gone.
- Upgrade removes obsolete duplicate hashed declarations.
Impact / Severity
LOW (host/resource issue). The primary session-lifetime leak is upstream, but Squad currently amplifies every retained session into several extra processes. On a dev box this reached hundreds of Node/cmd processes.
Proposed fix
- Generate a single canonical bridge declaration and remove stale duplicates during upgrade.
- Launch
node <installed-cli-entry> state-mcpdirectly. - Explicitly handle stdin EOF/transport close and terminate the server process tree.
- Add a lifecycle test that starts the stdio server, closes input, and asserts timely exit with no wrapper descendants.
Activity
johannschiffer commentedon Oct 24, 2026
This process tree explosion (
cmd.exe -> node npx-cli.js -> cmd.exe squad.cmd -> node cli-entry.js) is a direct consequence of how Windows command wrappers (.cmdbatch files) interact with Node.js and MCP stdio lifecycles.Root Cause Analysis
Double Batch Wrapper Amplification:
On Windows, invoking
npxresolves tonpx.cmd. In Windows,.cmdfiles cannot be executed directly byCreateProcessWwithout spawning an intermediatecmd.exeshell. Thatcmd.exespawns Node to runnpx-cli.js. In turn,npxresolves@bradygaster/squad-cliand executes its bin entry, which is another.cmdfile (squad.cmd), causing Node to spawn anothercmd.exe, which spawns the finalnode cli-entry.js.Missing
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE:When Copilot or Claude Desktop disconnects from the stdio pipe, only the top-level process receives EOF. Windows
cmd.exedoes not propagate process termination signals downstream to grandchildren unless wrapped in a Win32 Job Object configured withJOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE. As a result, the grandchildren survive as orphaned background processes, holding ports and memory.Recommended Fixes
Bypass the Batch Shell Wrappers (Collapse 4 processes to 1):
Instead of registering
npx -y @bradygaster/squad-cli state-mcp, have the launcher resolve the entry JavaScript file and launchnodedirectly:{ "command": "node", "args": [ "C:\\Users\\...\\AppData\\Local\\npm-cache\\...\\cli.js", "state-mcp" ] }Direct execution of
node.exeeliminates both intermediatecmd.exeshells, collapsing the entire chain into a single process that terminates immediately when stdin closes.Deduplicate Bridge Registration via Normalized Keys:
Copilot MCP config hashing should canonicalize paths (lowercasing drive letters and resolving symlinks/subst drives) so that multiple active editor workspaces do not spawn redundant parallel instances of
state-mcp.Single-Process Paradigm in Modern Toolchains:
For comparison, in Python MCP toolchains (e.g.
uvx pgsafe-mcp,uvx browserbridge-mcp, oruvx crawlengine-mcp),uvxis a compiled Rust binary that executes the target entrypoint directly without shell wrapping, avoiding the multi-tiered batch wrapper leakage observed with npm on Windows.Technical Reference & Native Stdio Architecture
fix(cli): harden squad state bridge
fix(cli): harden squad state bridge
fix(cli): resolvable squad_state bridge spec, doctor bridge probe, ve…