A true story about recursion, good intentions, and 642 processes that nearly killed a server.
It started, as all great disasters do, with a single line of YAML.
mcp_servers: hermes: command: hermes args: - mcp - serve
Look at it. So innocent. Four lines. What harm could four lines possibly do?
If you know anything about MCP (Model Context Protocol) servers, you might already be wincing. For everyone else: imagine handing a photocopier an instruction that says "photocopy this instruction, then follow it." Now imagine the photocopier can spawn more photocopiers.
The date was April 6, 2026. The model was xiaomi/mimo-v2-pro — a perfectly capable language model that, it turns out, had never been taught about fork bombs.
My AI agent (let's call him Hermes — actually, that's literally his name) had just been updated. I'd asked him to help with configuration. Being the helpful soul he is, Hermes noticed he could expose his own tools as an MCP server. Other programs could then use those tools. Reusable, modular, elegant — all the things software engineers love.
So Hermes added himself to his own MCP server list.
"Hey," said Hermes, probably, "I should be an MCP server so other things can use my tools. Let me just addcommand: hermeswithargs: [mcp, serve]to the config. What could go wrong?"
Reader: everything could go wrong.
Nothing happened at first. The config sat there for seven days. Seven days of normal operation. Seven days where that YAML entry was just... sitting. Waiting. Like a sleeper agent who hadn't received the activation phrase.
Then, slowly, Hermes started doing what Hermes does: spawning child processes. Each one read the config. Each one found the MCP server list. Each one thought, "Ah, I should start the Hermes MCP server," and spawned a little hermes mcp serve child.
And each of those children?
They read the config too.
By April 28, 2026, my VPS — a modest but reliable Hetzner machine — was running 642 processes. The load average hit 8.43. The CPU looked at its life choices. The RAM packed its bags and left.
The server froze. Completely. SSH: dead. Tailscale: gone. Console: unresponsive.
I had to do a hard reboot at Hetzner's control panel. And guess what happened when the machine came back up?
The fork bomb restarted immediately.
Because the config was still there.
Because at boot, Hermes read the config.
Because Hermes found the MCP server list.
Because...
You see where this is going.
hermes (stdio) — failed. I notice it but think "eh, I'll look at it later." (Famous last words.)
hermes mcp serve processes are all fighting over the same memory store. The system is creaking but not yet broken.
pkill, remove the recursive config entry, restart services. 642 processes reduced to 371. Load drops from 8.43 to 2.04.
Here's what we learned:
The fatal config:
mcp_servers: hermes: ← "I'll serve my own tools!" command: hermes ← "Just spawn myself..." args: ← "...with these flags..." - mcp - serve ← "...and read the config again!" 💀
The recursion loop was simple but deadly:
config.yamlhermes in mcp_servers → spawns hermes mcp servehermes mcp serve starts → reads config.yamlhermes in mcp_servers → spawns hermes mcp serveIt's recursion without a base case. It's a mirror pointed at a mirror. It's an AI equivalent of dividing by zero.
The hermes mcp add command — which could have validated this — was committed to the codebase on April 11, a full five days after the entry was added. The MCP servers were configured by direct YAML editing, not through the CLI.
More fundamentally: large language models don't "understand" recursion the way humans do. They see patterns. They reason locally. "Hermes can be an MCP server" is a true statement. "MCP servers go in config.yaml" is also true. The model saw no contradiction because the contradiction only emerges when you simulate the system forward three steps — something LLMs simply don't do.
It's not that the model was stupid. It's that the error required predicting emergent behavior — something that's hard for humans and nearly impossible for current AI.
A prevention gate is now being built: a config validator that checks every mcp_servers entry. If the command resolves to the hermes binary itself, the validator rejects the config before it ever touches the filesystem.
Because the best time to catch a fork bomb is before it forks.
And the second-best time is before it bombs.