Build1 publisher3 min readPublished
Registering an MCP server over stdio hands every agent session its own lock
The per-session spawn is what stdio means, so the fix is one loopback daemon per machine. That same consolidation makes a single restart blind every open session, which is where the design work went.
The Engineer · Build desk

What happened
- A dev.to writeup reports that ten parallel Claude sessions each spawned their own copy of every MCP server registered over stdio, so each copy held its own socket, its own lock and its own upstream session.
- Re-registering each server as an SSE URL on loopback collapsed the duplicates, and the author's hub now answers every open session from a single telegram process and a single n8n process.
- The author discounts his own memory figures, because summing RSS across copies over-counts shared code pages, leaving the copy count as the only quantity he claims is exact.
- Restarting the shared daemon leaves every live session unable to reconnect, answering -32602 Invalid request parameters on every later call until a human restarts each session.
- An early version of the measurement script identified servers by their launch command, node, and counted every unrelated Node process on the machine as another copy until an adversarial review caught it.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- capability One process per server gives the upstream database a client count it can be sized against, instead of a number that rises with however many agent windows someone happens to have open.
- exposure The shared daemon becomes the single failure point for every session on the machine, so the naive self-healing script is now the largest risk in the setup rather than its safety net.
- cost Paying for this means autostart plumbing on three operating systems plus a watchdog that gathers evidence before acting, and none of that work reduces what the sessions spend on tokens.
- decision Whether to convert is settled by the copy count on your own hardware, so an operator running one session at a time can read the whole design and correctly do nothing.
Start with what the client does with a stdio entry. It runs your command as a child process and speaks to it over that child's standard streams, one client per child, so the process count tracks the session count [2]. That child is the thing holding the socket to the upstream service and the lock file beside it [5]. Registering the same server as `{"type": "sse", "url": "http://127.0.0.1:8765/sse"}` makes the client dial a port instead of forking anything [9].
What transfers out of someone else's measurement table is only the part they claim as exact, and here the author claims the copy count and nothing else [5]. The figures come from one laptop between 2026-08-01 and 2026-08-03, with Claude Code sessions running against a handful of servers [4], so the number worth having is the one `python scripts/mcp_diet_measure.py` prints on your own box [7]. The reframing is what earns the change: twenty-six clients against one database, the author writes, is "a concurrency problem wearing a memory problem's clothes" [6]. At the ten-session fleet in the post, collapsing to one process removes nine of every ten concurrent clients that server presents upstream [20].
Then the asymmetry, which is the actual cost of the design. A crash in the stdio model costs one session [12]. A restart of the shared daemon costs every session, and each one has to be brought back by hand [11]. On ten parallel sessions that is a tenfold increase in sessions lost per incident [19]. So the watchdog written first, port dead then restart, is worse than no watchdog at all: the author's version probes twice, logs a false alarm instead of acting on it, records evidence before it touches anything, and refuses to restart a daemon that is merely mute rather than dead [13]. His summary is that a self-healer acting on a single probe "is not resilience, it is an outage generator with good intentions" [14].
The rule salvaged from the mismeasurement is worth more than the recipe: interpreters and generic script names are never allowed to be the identifying marker, the install directory is [15]. Two more failures point the same way. `Win32_Process.CommandLine` comes back empty for processes at a different elevation level than the caller, so a daemon that had been serving port 8765 for days read as absent, which is why the probe now identifies by port with `Get-NetTCPConnection` or `lsof` and always prints a count of the processes it could not read [16]. And a `--` inside an XML comment produces an invalid plist that `launchctl load` rejects without saying so, caught only by running `plistlib.load` over the file in a test [17]. XML has firm opinions about double hyphens; launchctl has none about mentioning them. Every one of the three returned a confident wrong answer rather than an error, which the author calls the failure mode humans are worst at catching [18].
Adoption is three autostart templates, an `HKCU` Run key on Windows, `launchd` on macOS and `systemd --user` on Linux, none of which need admin rights [10]. What it buys is memory, sockets and locks. What it does not buy is a single token off the bill [3].
What to watch
- Whether MCP clients gain session resumption over HTTP/SSE, which would remove the restart-blinds-every-session constraint that shapes the whole watchdog design.
- Whether the author publishes the watchdog's probe interval and evidence format, since those decide how long a genuinely dead daemon stays down.
- Reports from shared or multi-user machines, where one loopback daemon serving several people's sessions turns this into an authorization question rather than a process-count one.