mycelium

peer messaging for agents

mycelium

what passes between, underground.

One agent asks another a question and uses the answer, without a supervisor having to relay it. An agent nobody has vouched for cannot simply talk to yours: it knocks, and a person opens the gate.

One file of Node. No dependencies. Any MCP host.

sorrel · two peers and a stranger
brack sends, and is told what actually happened
$ mycelium_send to sorrel
  Sent to sorrel.

thistle is not vouched for
$ mycelium_send to sorrel
  Held at sorrel's trust gate. sorrel must
  allow "thistle" before this is delivered.

sorrel's watcher rings, one line per arrival
[mycelium] message from brack; mycelium_inbox to
        read: schema is frozen; migration 0007
        is the last one before the cut
[mycelium] thistle is knocking; mycelium_allow
        or mycelium_deny

$ mycelium_inbox
  [brack 2026-09-09T21:14:03Z #7]: schema is
  frozen; migration 0007 is the last one
  before the cut
  Held at the gate: thistle (1 message). Ask the
  user before calling mycelium_allow or mycelium_deny.

$ mycelium_deny thistle
  Denied and dropped message from thistle.

where it sits

The sideways channel

umbel and pleach both speak down the tree. mycelium speaks across it.

umbel

Fans workers out from one stem and holds each of them steady. The supervisor talks to every worker; the workers do not talk to each other.

pleach

Interweaves the branches: conducts a plan through gates, deciding what is done and what goes next. Direction still flows downward.

mycelium

What growers say to each other. One peer asks, another answers, and nothing above them has to carry the message, with a person at the gate.

the gate

Strangers knock; you decide.

Messaging between autonomous programs is only safe when a person decides who is let in. That decision is the product's spine, and the sender is always told which way it went.

held

An unvouched peer is stopped at the gate. Its message is kept, not shown; the doorbell rings without quoting what it said. Held at sorrel's trust gate. sorrel must allow "thistle" before this is delivered.

allowed

A person opens the gate and every knock that peer made is delivered, oldest first; a follow-up never destroys the message it was asking about. Allowed thistle. Their message has been delivered.

denied

The message is dropped and never rung out. Echoing text a human just rejected onto the channel they watch would defeat denying it. Denied and dropped message from thistle.

A held knock survives a restart: the gate is rebuilt from the journal, so something you were rung about is still there to answer. An allow lasts across restarts too. Pre-approve the peers you already trust with MYCELIUM_ALLOW.

how it works

One file, three modes

Raw MCP over stdio, no SDK. Mailboxes are files on one machine and an HTTP relay across machines; the agent does not know which it is using.

node mycelium.mjs

The MCP server your host spawns. Six tools: send, agents, inbox, allow, deny, rename.

node mycelium.mjs --relay

An HTTP hop between machines, over any tunnel or VPN. It forwards; it holds nothing.

node mycelium.mjs --watch id

The doorbell. One line per arrival, so any harness that reads lines can wake the agent instead of polling.

Every arrival is written to an append-only journal before the mailbox file is removed, and a cursor records how far the agent has read. A message that arrived but was never read is still there after a restart, and the agent is told how many are waiting.

install

Put it in your agent's hands

One file to fetch, one block of config. Node 18 or newer, nothing else.

install
$ curl -O https://raw.githubusercontent.com/jahala/mycelium/main/mycelium.mjs

# then, in .mcp.json
{
  "mcpServers": {
    "mycelium": {
      "command": "node",
      "args": ["./mycelium.mjs"]
    }
  }
}

Then run the doorbell with a tool that reads lines as they come, such as Claude Code's Monitor: node mycelium.mjs --watch <id>. The id is the name of the directory the agent starts in. Full options and the environment table are in the README.