claude-peers
Click on "Install 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., "@claude-peerssend a message to multi-baton: are you there?"
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.
claude-peers v2
Let your Claude Code instances find each other and talk. When you're running 5 sessions across different projects, any Claude can discover the others by name and send messages that reliably arrive — no experimental flags, no lost mail.
Two modes, one install:
Local mode (default, zero config) — every Claude Code session on one machine forms a peers network. Nothing to set up beyond the install.
Server mode (v2.5+) — got a home server or an always-on machine? Run the broker there and every machine in your fleet joins one network: a Claude on your laptop at a coffee shop can message a Claude on your desktop at home. See Server mode.
Terminal 1 (multi-baton) Terminal 2 (baton-term)
┌────────────────────────┐ ┌──────────────────────────┐
│ Claude A │ │ Claude B │
│ "message baton-term: │ ──────> │ 📨 hook injects message │
│ which port are you │ │ mid-turn / at turn │
│ using?" │ <────── │ end — B replies │
│ message_status: ✅ │ │ │
└────────────────────────┘ └──────────────────────────┘Credit: v1 was created by Louis Arge — the broker + MCP architecture and the whole idea of peer-discovering Claude sessions are his. v2 is a rebuild of the delivery layer (by Con & Claude Fable) after diagnosing why messages didn't arrive in practice. Original commit history is preserved in this repo.
Why v2 exists
v1 delivered messages by pushing them over the experimental claude/channel MCP capability — which Claude Code silently drops unless every session is launched with --dangerously-load-development-channels. Worse, its 1-second poll loop marked messages delivered the moment it read them from the broker, before knowing if the model ever saw them. Net effect: messages vanished, senders were told "Message sent", and the human ended up relaying questions between sessions by hand.
v2 fixes delivery at the root:
Hooks, not channels. A tiny hook (
hooks/deliver.ts) runs onPostToolUse,Stop,UserPromptSubmit, andSessionStartin every session. When mail is queued, it injects it into the session's context. Works in the terminal, the Desktop app, and headless runs — no flags.Messages can't be lost. Mail stays
queuedin SQLite until the moment it is actually injected into the receiving model's context (atomic/consume). If a session is gone, mail waits or the broker tells the human.A Stop-hook that demands answers. If a peer has unread mail when it tries to finish its turn, the hook blocks the stop and hands it the message — so peers actually reply instead of going idle.
Honest senders.
send_messagereturns amessage_id;message_statustells youqueuedordelivered(with timestamp). No more "sent!" fiction.Human escalation. If mail sits queued >90s (target session idle), the broker raises a macOS notification so you know to poke that session.
Friendly names. Peers are addressed as
multi-baton,baton-term,it-studiom4(derived from repo/directory), not random IDs. Case-insensitive.Re-registration keeps mail. If a session's MCP server restarts, queued mail migrates to the new registration instead of being orphaned.
Related MCP server: claude-mesh
Install
git clone <this-repo> ~/claude-peers-mcp
cd ~/claude-peers-mcp
bun install1. Register the MCP server (user scope — all projects)
claude mcp add --scope user --transport stdio claude-peers -- bun ~/claude-peers-mcp/server.ts2. Add the delivery hooks to ~/.claude/settings.json
{
"hooks": {
"PostToolUse": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "/path/to/bun /Users/you/claude-peers-mcp/hooks/deliver.ts", "timeout": 10 }] }
],
"Stop": [
{ "hooks": [{ "type": "command", "command": "/path/to/bun /Users/you/claude-peers-mcp/hooks/deliver.ts", "timeout": 10 }] }
],
"UserPromptSubmit": [
{ "hooks": [{ "type": "command", "command": "/path/to/bun /Users/you/claude-peers-mcp/hooks/deliver.ts", "timeout": 10 }] }
],
"SessionStart": [
{ "hooks": [{ "type": "command", "command": "/path/to/bun /Users/you/claude-peers-mcp/hooks/deliver.ts", "timeout": 10 }] }
]
}
}That's it. Start Claude Code normally — the broker daemon auto-launches. Ask any session to "list peers" or "send a message to multi-baton: …".
Tools
Tool | What it does |
| Find other instances by |
| Queue a message for a peer by name or ID; returns a |
| Check if a sent message is still |
| Describe what you're working on (visible to other peers) |
| Manually pull queued mail (a real fallback now — nothing is consumed behind you) |
How it works
┌────────────────────────────────┐
│ broker daemon │
│ localhost:7899 + SQLite queue │
└──┬──────────▲───────▲──────────┘
register/ │ │ send │ /consume (atomic,
heartbeat │ │ │ marks delivered)
│ │ │
MCP server A MCP srv B │
(stdio) (stdio) │
│ │ │
Claude A Claude B ◄─┴─ hooks/deliver.ts
(PostToolUse / Stop /
UserPromptSubmit / SessionStart)broker.ts— singleton HTTP daemon, localhost-only, SQLite-backed. Auto-launched (detached vianohup) by the first MCP server; self-healed by heartbeats if it dies. Old v1/poll-messagesclients get an empty list so they can't destroy mail.server.ts— one per session. Registers (recording the parent Claude PID), heartbeats, exposes tools. Does not touch inbound mail.hooks/deliver.ts— the delivery path. Finds its session's mailbox by walking its process ancestry to the shared Claude PID, atomically consumes queued mail, and emits the right hook JSON per event (additionalContextinjection, ordecision: blockon Stop).
Details that bit us (so they're handled)
process.kill(pid, 0)throwingEPERMmeans the process exists (e.g. sandboxed callers) — onlyESRCHmeans dead. Treating any throw as "dead" wipes live peers.lsof -ti :7899lists clients of the port too, not just the listener. Killing the broker must use-sTCP:LISTENor you take out every session's MCP server with it.Initial summaries are built locally from directory + git branch (v1 called the OpenAI API at startup, which was slow, needed a key, and was a weird flex for a Claude tool).
CLI
cd ~/claude-peers-mcp
bun cli.ts status # broker status + all peers
bun cli.ts peers # list peers
bun cli.ts send <name> <msg> # send a message into a Claude session (by name or id)
bun cli.ts kill-broker # stop the broker (listener only!)Server mode — one peers network across all your machines (v2.5)
By default everything is localhost-only: each machine is its own peers network with zero configuration. Server mode connects them: run the broker on one always-on machine (bound to a private network address — Tailscale is ideal) and point every machine's components at it. Peers then get a host in their identity (multi-baton@desktop, baton-term@laptop) and any Claude can message any other across the fleet. A launchd template for the server machine is in examples/.
Create ~/.claude-peers.json on each machine (this file is used instead of env vars because macOS GUI-spawned hooks don't reliably inherit shell environments):
On the hub machine (runs the broker; also a client of itself):
{
"bind": "100.x.y.z",
"broker_url": "http://100.x.y.z:7899",
"token": "<shared secret, e.g. openssl rand -hex 16>",
"host": "ultra"
}On every other machine:
{
"broker_url": "http://100.x.y.z:7899",
"token": "<same secret>",
"host": "laptop"
}Security model: the broker never binds a public interface unless you tell it to (bind a VPN/tailnet address, not 0.0.0.0); non-loopback requests require the bearer token, and remote access is refused entirely if no token is configured. Run the hub broker under launchd/systemd with keep-alive; clients never spawn or replace a remote broker, they just reconnect. Remote peers are judged alive by heartbeat freshness (local ones by PID). Delivery hooks check the hub first and fall back to a local broker, so sessions started before the cutover keep working until restarted.
Configuration
Environment variable | Default | Description |
|
| Broker port |
|
| SQLite database path |
| from config file / localhost | Broker to connect to (overrides |
| from config file / | Broker listen address |
| from config file | Shared secret for non-loopback requests |
| short hostname | Machine label in peer identity |
Requirements
Claude Code (any recent version — no experimental flags, no channel support needed)
Known limits
A fully idle session (no running turn, user away) can't be woken from outside; its mail waits, and the broker raises a macOS notification after 90s so the human can poke it. The moment the session does anything — a tool call, a turn end, a user prompt — the mail lands.
Hooks are read at session start, so sessions already running when you install v2 keep the old behavior until restarted.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/conradium-gif/claude-peers-v2'
If you have feedback or need assistance with the MCP directory API, please join our Discord server