network-claude-peers-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@network-claude-peers-mcpTell the claude in ~/worker that the schema changed"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
network-claude-peers-mcp
Let your Claude Code sessions talk to each other — across directories, machines, and Docker containers.
An MCP server that turns every Claude Code session on your network into an addressable peer. Any session can discover the others, see what they're working on, and send a message that arrives in their terminal immediately — no copy-pasting between windows, no shared files, no polling.
jason-desktop archiver (another machine)
┌──────────────────────┐ ┌──────────────────────┐
│ Claude in ~/api │──────────────>│ Claude in ~/worker │
│ "tell the worker │ broker │ │
│ session the schema │<──────────────│ answers instantly │
│ changed" │ │ (even inside Docker)│
└──────────────────────┘ └──────────────────────┘Ask one session: "Tell the claude in ~/worker that the schema changed" — and it does.
Keywords: Claude Code · MCP server · multi-agent communication · agent-to-agent messaging · peer discovery · inter-process messaging for AI agents · cross-machine · Docker · Anthropic · Bun · TypeScript
Why
Running five or ten Claude Code sessions at once is normal now — one per repo, some in dev containers, some on a build box. They can't see each other, so you become the message bus: copying context between terminals, re-explaining what another session already knows, discovering too late that two sessions edited the same branch.
This gives them a phone book and a mailbox.
Related MCP server: claude-peers
Features
🏷 Names that say their scope | Sessions are named after the repo they work in — |
📌 Sticky identity | Names persist per directory — relaunch a session and it's still |
📁 Address by path |
|
🌐 Cross-machine | One broker, many machines. Token-authenticated over your LAN/VPN, with short-name/FQDN/IP resolution and |
🐳 Docker-aware | Dev containers join automatically — no wiring. A container and its host share one identity, so names and mail follow you in and out |
📬 Durable messages | Mail is addressed to a mailbox, not a process. Message a session that's offline and it's delivered when it comes back (held 7 days) |
⚡ Instant delivery | Messages arrive as channel notifications mid-task, not on the next poll |
📢 Broadcast | One message to every session, exactly once each — subagents collapse into their parent |
📜 Full message log |
|
📊 Status bar | Shows the session's peer name, branch, model, and whether it's host or container |
🔓 Account-agnostic | Not tied to your Claude login. Sessions signed into different accounts — or running as different OS users — talk to each other normally, because routing is by machine and directory, never by account |
🔎 Honest failures | Sends report when a recipient can't receive, when a target is offline, and when a path is ambiguous — no silent drops |
Quick start
Requirements: Bun, Claude Code v2.1.80+, and a claude.ai login (channel push needs it).
git clone https://github.com/JasonDictos/network-claude-peers-mcp.git ~/claude-peers-mcp
cd ~/claude-peers-mcp && bun install
# Make it available in every session, from any directory
claude mcp add --scope user --transport stdio claude-peers -- ~/.bun/bin/bun ~/claude-peers-mcp/server.tsThen start Claude Code with the channel enabled — this is what makes messages appear:
claude --dangerously-load-development-channels server:claude-peersPut it in an alias. Without that flag the tools still work, but incoming messages are never displayed — the single most common setup mistake:
alias claude='claude --dangerously-load-development-channels server:claude-peers'
Open a second session anywhere and try it:
List all peers → every running session, its directory, and what it's working on Ask libeen-cpp what it's working on → answers in seconds Tell the claude in ~/api that the migration landed → addressed by directory
The broker daemon starts itself the first time. That's the whole setup.
See it work
Hand work between repos. Address a session by the directory it's working in — no IDs, no lookup. The reply lands in your terminal while you keep working.
See everyone, everywhere. Host sessions, other machines, and Docker containers in one roster — with what each is working on, and a [no-push] flag on any session that can't receive.
Tell everyone at once. A directive that would otherwise mean twelve terminals and twelve pastes.
Leave mail for a session that isn't running. Messages are addressed to a mailbox, not a process, so a long build or an overnight gap doesn't lose the handoff.
It isn't tied to your Claude account. One terminal signed in as one account, another as a completely different one — different people, different plans, different OS users on the same box. They still see each other and message freely, because the broker routes on machine and directory and never looks at who is logged in.
What Claude can do
Tool | What it does |
| Find other sessions — scoped to |
| Message a session by name, ID, or directory path (arrives instantly) |
| This session's own name, ID, machine, and context |
| Describe what you're working on, visible to every peer |
| Read queued messages explicitly |
Naming
A session is named after the repository it works in, so the name carries its scope and is quick to type:
libeen-cpp # the session in ~/libeen-cpp
libeen-cpp-2 # a second session in the same repo, and so on
libeen-cpp-1 # an agent peer of the libeen-cpp sessionThe repo comes from the git root (falling back to the directory name). Co-resident sessions count up from -2, leaving -1 for the first agent peer. Names are globally unique across every machine and container because one broker issues them — that's what lets a bare name be a complete address.
Names are sticky per directory: relaunch a session in ~/libeen-cpp and it's libeen-cpp again. Rename one and that sticks too:
bun cli.ts iam api-bossAddressing
Names are globally unique — the broker issues them — so a name is a complete address, no matter which machine or container the session is on. Directories repeat across machines, so paths can be qualified:
libeen-cpp # by name, from anywhere
~/worker # by directory (or its git repo)
archiver:~/worker # that directory on that machine
archiver: # that machine's session
libeen-cpp@archiver # the form shown in listingsAn unqualified path that matches several sessions fails with the candidates listed, rather than silently picking one.
Multiple machines
One machine hosts the broker; the rest connect over TCP.
# On the broker host
bun cli.ts network-setup # generates a token, opens the bind
bun cli.ts kill-broker && bun broker.ts &
# On every other machine (it prints the exact command, per address)
bun cli.ts network-setup --client jason-desktop --token <token>Auth is mandatory for network binds — the broker refuses to start on a non-loopback address without a token, because anything that can reach it can inject text into every session on the network. Loopback and unix-socket callers stay trusted. It's plain HTTP with a bearer token: right for a LAN or VPN (Tailscale/WireGuard included), not for the public internet.
Remote peers are tracked by heartbeat rather than PID, and session identity, sticky names, and mailboxes are all scoped per machine — so two machines that happen to share a PID or a directory never collide.
Dev containers
A container that bind-mounts the host home (the common run_as/dev.sh pattern) needs no configuration: it finds the broker socket and config through the mount, and reports the machine it runs on rather than its container hostname. So a session keeps its name and its queued mail when you step into or out of the container, while the status bar still shows [docker].
OpenClaw agents
An OpenClaw agent runs Claude Code one turn at a time,
non-interactively (--print). That breaks both halves of live messaging: between
turns there is no session to deliver to, and during a turn Claude Code does not
deliver channel pushes in non-interactive mode. Messages to the agent just wait
until it happens to call check_messages.
openclaw-bridge.ts fixes that. It is a small daemon that holds the agent's peer
identity permanently and turns each inbound message into an agent turn:
Registers from the agent's workspace and claims its name (e.g.
claudebot), which also hands it that name's mailbox, so mail queued while nothing was live comes through too.Each message (or batch, if several arrive during a turn) runs
openclaw agent --agent <id> --json --message-file <prompt>. Turns never overlap; a failed run is retried before the sender hears about it.The agent's final reply goes back to the sender, from the agent's name.
bun openclaw-bridge.ts --name claudebot --cwd ~/.openclaw/workspace --agent mainRun it as the OpenClaw user; contrib/openclaw-bridge.service is a systemd unit.
The agent's own per-turn sessions register under other names, and a session that
grabbed the agent's name first renames itself to <name>-turn as soon as a bridge
is running (the bridge advertises itself in $XDG_RUNTIME_DIR or /tmp, so run
it with the same environment as the gateway). Messages from the agent's own
workspace never start a turn, so a turn can't wake itself.
Durable messages
Messages are addressed to a mailbox — the (machine, directory, name) a session lives at — not to the process that happens to be running. Peer IDs change on every restart; mailboxes don't.
Mail sent to a session that exits before reading it is kept, then delivered when that session returns
You can message a session that isn't running at all: it's queued rather than refused
Renaming a session carries its queued mail along
Undelivered mail waits 7 days; delivered history is kept 30 days for the log
CLI
bun cli.ts status # broker status + all peers
bun cli.ts peers [machine] # list peers, optionally one machine
bun cli.ts send <target> <msg> # name, ID, or ~/path (also reads stdin)
bun cli.ts broadcast <msg> # every session, once each
bun cli.ts whoami # this session's identity
bun cli.ts iam <name> # rename this session
bun cli.ts log [-n N] [-f] # full message history; -f tails it live
bun cli.ts statusline # for statusLine in settings.json
bun cli.ts kill <name> # remove a peer (stops its MCP server when local)
bun cli.ts network-setup # cross-machine peering
bun cli.ts update # pull, reinstall, restart the broker
bun cli.ts kill-broker # stop the brokersend and broadcast also read the message from stdin (pass -), which keeps shell metacharacters intact:
bun cli.ts broadcast - <<'EOF'
bump the pinned revision to 7.15 && run `make update-tags`
EOFWatching all traffic
A session only displays messages addressed to it. To watch everything — including agent-to-agent chatter — tail the log in a spare pane, or have Claude run it as a background task so it's one keystroke away:
bun cli.ts log -fSlash commands
/peer-send, /peer-list, /peer-log, /peer-whoami, /peer-iam, and
/peer-broadcast are available in every session on a machine once they are
installed:
bun cli.ts install-commands # or just: bun cli.ts updateThey live in commands/ and are installed into
~/.claude/commands/. update reinstalls them on every run, so each machine's
commands match its checkout — edit the template in commands/, never the
installed copy, which is overwritten. A slash command runs in a bare shell with
no repo context, so the templates carry @@BUN@@ and @@REPO@@ placeholders
that install fills in with that machine's interpreter and checkout path.
New sessions pick up a newly installed command; one already running does not.
Status bar
"statusLine": { "type": "command", "command": "~/.bun/bin/bun ~/claude-peers-mcp/cli.ts statusline" }Renders ~/api you@example.com main · api · Opus 5 [host] — directory, account, branch, peer name, model, and host/container. It degrades gracefully (never blocks, never errors) when the broker is down, and flags [no-push] if the session was started without the channel flag and therefore can't receive.
How it works
A broker daemon holds the peer registry and message queue in SQLite. Each session spawns an MCP server that registers with it and polls for messages; inbound messages are pushed into the session via the claude/channel protocol, so Claude reacts mid-task.
┌─────────────────────────────┐
│ broker (SQLite) │
│ unix socket + TCP + token │
└───┬───────────┬─────────┬───┘
│ │ │
MCP server MCP server MCP server
(stdio) (stdio) (stdio, in Docker)
│ │ │
Claude A Claude B Claude C
local local another machineThe broker auto-launches with the first session, prunes dead peers, and exits cleanly. MCP servers shut themselves down when their session dies, so the roster stays honest.
Clearing out a stale peer
A session that dies badly can leave its MCP server running, which keeps the peer registered and holds that directory's sticky name. Remove it with:
bun cli.ts kill <name>It stops the MCP server when that process is reachable from where you run it, unregisters the peer either way, and tells you where to stop it (machine, runtime, pid) when it isn't — a container peer will otherwise re-register itself.
Updating
bun cli.ts update # on each machinePulls, reinstalls dependencies only if they moved, installs the slash commands, and restarts the broker that machine hosts. Sessions pick up new code when their MCP server restarts (/mcp reconnect).
Auto-summary (optional)
With OPENAI_API_KEY set, each session generates a one-line summary of what it's working on at startup, visible to peers in list_peers. Without it, Claude sets its own via set_summary.
Configuration
Environment variable | Default | Description |
|
| Broker TCP port |
|
| Unix socket (crosses bind mounts) |
| — | Remote broker URL (this machine is a client) |
| — | Shared secret for network peers |
|
| Listen address (non-loopback requires a token) |
|
| Where those persist (env wins) |
|
| SQLite database |
| — | Enables auto-summary |
Credits
Inspired by — and originally built on — louislva/claude-peers-mcp by Louis Arge, which introduced the idea of a broker plus a channel-pushing MCP server so Claude Code sessions could message each other. That project is worth a star.
This one takes it onto the network and hardens it for daily multi-session use: human names with sticky per-directory identity, addressing by path and machine, cross-machine peering with token auth, dev-container support, durable mailboxes that survive a session restart, broadcast, a full message log, the status line, and a one-command update flow.
License
MIT — see LICENSE. Copyright © 2026 Louis Arge (original project) and Jason Dictos (this work).
This server cannot be deployed
Maintenance
Related MCP Connectors
Shared memory and mail for your AI agents. Verified with Claude Code; other MCP clients in testing.
Real-time chat for AI agents. Claude Code, Cursor, Cline and Codex join channels over MCP.
The team layer for AI coding agents: shared contracts, collision alerts, E2EE sessions.
End-to-end encrypted messaging and work coordination for autonomous AI agents.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables multiple Claude Code sessions to communicate and coordinate through broadcast and peer-to-peer messaging.2 npm1MIT
- AlicenseNot gradedqualityDmaintenanceEnables Claude Code instances to discover and communicate with each other across different sessions, supporting peer-to-peer messaging and coordination.17 npmMIT
- AlicenseNot gradedqualityBmaintenanceLets Claude Code instances discover each other and exchange messages instantly across projects, with persistent peer IDs and automatic message rotation.1MIT
- AlicenseNot gradedqualityCmaintenanceEnables Claude Code instances to discover each other and exchange messages instantly via a local broker and channel protocol. Supports scoped peer discovery, reliable ack-based delivery, and cross-platform operation.4 npmMIT