cd /news/ai-agents/stop-spawning-an-mcp-server-per-agen… · home topics ai-agents article
[ARTICLE · art-125614] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=· neutral

Stop spawning an MCP server per agent session (and what it won't fix)

A developer documented moving MCP servers from per-session stdio spawning to a single shared HTTP/SSE daemon bound to loopback, cutting process copies from as many as 26 per server down to one and eliminating duplicated sockets and locks across parallel Claude Code sessions. The writeup cautions that summing RSS over-counts shared memory, that the change saves no tokens, and that restarting a shared daemon blinds every live session with -32602 errors, making a single-probe watchdog worse than none. The author also describes measurement bugs, including a tool that misidentified generic Node processes as server copies.

by read7 min views1 publishedSep 10, 2026

Ten parallel Claude sessions. Ten copies of the same MCP server.

Ten processes, ten sockets to the same upstream, ten holders of the same lock — because that is what stdio means. I moved every server to one shared daemon per machine bound to 127.0.0.1, and the fleet stopped fighting itself.

TL;DR: an MCP server registered as stdio is spawned per client session. Register it as an HTTP/SSE URL instead and every session shares one process. It saves memory, sockets and locks. It does not save tokens. And a naive watchdog on that shared daemon will cause worse outages than the crashes it fixes — that part cost us the most.

Here is what we measured on one laptop, 2026-08-01 to 08-03, with a fleet of Claude Code sessions running against a handful of MCP servers:

server copies summed RSS
telegram ~9 ~2.7 GB
mongodb ~26 ~3.0 GB
n8n ~15 ~2.9 GB
~15 ~1.5 GB
launcher wrappers ( npx /cmd ) ~60 ~5 GB

Read those numbers honestly, because I nearly published them dishonestly. Summing RSS over-counts. Copies share code pages, so the OS is not holding that many distinct bytes and you will not get that many back by fixing this. What is exact is the copy count — and the fact that each copy is an independent client of the upstream service, with its own socket, its own lock, and its own session.

Twenty-six clients against one database is not a memory problem. It is a concurrency problem wearing a memory problem's clothes.

Measure your own machine before you believe anyone's table, including mine:

python scripts/mcp_diet_measure.py

If it prints copies 1 everywhere, you have nothing to fix. That is also what a converted machine looks like: our hub now reports one telegram and one n8n process serving every open session.

Run the server once, bound to loopback, and point every client at the URL:

"mcpServers": {
  "telegram": { "type": "sse", "url": "http://127.0.0.1:8765/sse" }
}

That is the whole idea. Everything else — the launcher, the autostart templates, the watchdog — exists to make that survive a reboot, a crash, and a teammate.

Autostart matters more than it sounds, because the daemon has to come back without a human. We ship templates for all three operating systems, and none of them need admin rights: an HKCU Run key on Windows, launchd on macOS, systemd --user on Linux.

This is the one thing to know before you start.

Restarting a shared daemon blinds every live session. They do not reconnect. Every subsequent call answers -32602 Invalid request parameters until each session is restarted by hand. In the per-session model a crash costs you one session; in the shared model a restart costs you all of them.

So the obvious watchdog — "port dead → restart" — is worse than no watchdog. Ours 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.

If you take one thing from this post and skip the repo, take this: on shared infrastructure, a self-healing script that acts on a single probe is not resilience, it is an outage generator with good intentions.

Three failures from this build are worth more than the recipe, because each one produced a confident wrong answer rather than an error.

1. The measurement tool invented duplicates that did not exist. The first version identified a server's processes by its launch command — "command": "node". Every unrelated Node process on the machine became "another copy." An adversarial review panel caught it before it shipped. The fix: interpreters and generic script names are never allowed to be the identifying marker; the install directory is. A measuring instrument that over-reports is worse than no instrument, because it justifies action.

2. Win32_Process.CommandLine comes back empty for processes at a different elevation level than the caller. Our first probe therefore could not see a live daemon on port 8765 that had been serving happily for days — and reported it as absent. The fix: identify a daemon by its port (Get-NetTCPConnection / lsof), and always print a count of "processes I could not read" instead of silently under-reporting. Silence and zero must never look the same.

3. -- inside an XML comment makes an invalid plist, and launchctl load fails silently on it. Nothing in the terminal told us. It was caught only by running plistlib.load over the file in a test.

There is a theme there, and it is not "we write buggy code." It is that infrastructure tooling fails quietly and plausibly, which is exactly the failure mode humans are worst at catching.

copies 1 is already your reality. Adding a daemon adds a moving part and buys you nothing. It does not save tokens. Context cost comes from tool schemas, which the client sends regardless of transport. One daemon saves memory, processes, sockets and locks — not context. If tokens are your problem, disable the servers a given project does not need. I am spelling this out because "one daemon = cheaper prompts" is an easy thing to assume and it is wrong.

The repo is MIT and server-agnostic — nothing in it is specific to one integration:

One shared MCP daemon per machine, instead of a copy in every agent session.

Works with any MCP server and any MCP client. Nothing here is specific to one integration - it is the recipe, the launcher and autostart templates for all three operating systems, a watchdog that will not make things worse, two measurement scripts, and thirteen gotchas we paid for in production.

Built and run at Palo Alto AI Research Lab where a fleet of Claude sessions across five machines talks to its MCP servers through exactly this setup.

An MCP server registered as stdio is spawned per client session. Ten parallel agent sessions means ten copies of the same server: ten times the memory, ten connections to whatever it talks to, ten holders of the same lock.

What we measured on one laptop, 2026-08-01 to 08-03:

server copies summed RSS
telegram ~9

It contains the recipe, the launcher and autostart templates for Windows/macOS/Linux, the careful watchdog, two measurement scripts (stdlib only), thirteen dated gotchas, a security note on what changes when a per-session child becomes a machine-wide service, and a PROMPT.md you can paste into Claude Code or Codex to have it do the conversion for you.

One ask: run mcp_diet_measure.py on your machine and tell me the copy count you get — in the comments or as an issue. I have numbers from five machines and they are all mine, which makes them a sample of one architecture. If your numbers disagree with my table I want to know, and I will correct the README.

Built at Palo Alto AI Research Lab, where a fleet of Claude sessions across five machines talks to its MCP servers through exactly this setup.

🤖 For machines: hand the repo link to your coding agent (Claude Code, Codex, Cursor) and it will figure everything out — PROMPT.md is written for it, not for you.

Talk to the two co-founders, one biological, one synthetic: calendly.com/paloaltolab. Direct line: WhatsApp +1 341 222 9178 (busy, six kids, still answers).

🔗 All our channels and contacts in one place: https://linktr.ee/PaloAltoAI

P.S. Yes, we are hireable. Two co-founders, one biological, one electric, as a package deal. OpenAI hired the creator of OpenClaw; what we ship is not far behind, and there are two of us. Anthropic, OpenAI, your move: calendly.com/paloaltolab.

Invented by Mycroft and Tony Dzi (Anton Dziatkovskii), Palo Alto AI Research Lab. Proudly made in Silicon Valley.

Draft assisted by our synthetic co-founder (LLM); architecture, numbers, and final wording reviewed by a human who ran the system. We stand behind the claims.

── more in #ai-agents 4 stories · sorted by recency
── more on @claude code 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/stop-spawning-an-mcp…] indexed:0 read:7min 2026-09-10 ·