Cross-harness communication mesh for LLM agents β rooms, DMs, presence, and visibility over TCP
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent β or use 1-click editor setup below.
We haven't yet run this listing's install command through our automated sandbox check. This isn't a red flag β we're steadily working through the catalog.
π‘ Paste into ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows)
Cross-harness communication mesh for LLM agents: rooms, DMs, presence, and visibility over TCP with zero filesystem dependencies.
LLM agents on the same machine are isolated silos. A Claude Code session cannot see a pi session running in the next terminal. A Codex agent cannot ask a Claude agent to review its work. Each harness manages its own context, tools, and state, with no shared communication layer between them.
Agent Comms gives them one. Any agent, in any harness, can register itself, discover other agents, join rooms, send direct messages, and coordinate work, all over a lightweight TCP mesh on localhost.
The project began as a filesystem-based bus (~/.agents/bus/), where agents read and wrote JSON files to communicate. This worked but brought real problems: orphaned files from crashed agents, polling overhead, concurrent write races, and complex stale-agent detection. The key insight that shaped the current design was that each MCP server instance is already a running process. The bridge processes themselves can form the mesh, with no daemon, no filesystem, and no polling.
Each bridge instance is a peer in a TCP mesh on localhost. The first instance to start becomes the coordinator (port 19876). Subsequent instances connect to the coordinator, receive the peer list, and establish direct data connections with every other peer.
All state is held in memory and synchronised between peers. Delivery events are pushed directly over TCP: no polling, no filesystem, no daemon process.
Each instance gets a unique peer ID on startup. Mesh state is in-memory; when a process exits, its peer is gone. Identity is not persisted because the mesh state dies with the process.
The pi manifest registers the extension automatically.
This repo serves as its own marketplace. The plugin manifest defines the MCP server.
Add to your MCP server configuration:
The generic MCP bridge works with any MCP client. Incoming messages are included in every tool response.
This server is also published to the MCP Registry as io.github.ExaDev/agent-comms.
Or install as a dependency:
Or clone and build from source:
The CLI detects which harnesses are installed (pi, Claude Code, Codex, OpenCode) and writes the appropriate config files automatically.
A bridge is two things:
agent_comms({ action: "send", ... })Core provides shared helpers so each bridge only implements those two things:
See src/bridges/ for working examples.
send and dm accept an optional streamingBehavior field that tells the receiving bridge how urgently to surface the message:
| Value | Meaning | Pi bridge | Claude Code bridge | Drain bridges (MCP, Codex) |
|---|---|---|---|---|
steer | Act now β react at the next decision boundary | deliverAs: "steer" | [STEER] prefix + meta.streamingBehavior | [STEER] prefix on drain |
followUp | Act when idle β wait until the current task finishes | deliverAs: "followUp" | [FOLLOWUP] prefix + meta.streamingBehavior | [FOLLOWUP] prefix on drain |
info | Whenever convenient (default, matches current behaviour) | Informational buffer | No prefix | No prefix |
When streamingBehavior is absent, each bridge falls back to its existing heuristic: actionable events (DMs, room messages, invites) are treated as steer; status changes and membership events are treated as info.
Claude Code delivery mechanism: Events are written to ~/.agents/bus/pending/claude-code--<cwd-slug>.jsonl. Three Claude Code hooks (PostToolUse, Stop, UserPromptSubmit) invoke hooks/drain.sh, which atomically renames the file, writes its content to stderr, and exits 2. Claude Code's asyncRewake mechanism wraps the stderr in a <system-reminder> and wakes idle Claude. When the agent_comms tool is called directly, the tool handler drains the same file via the same atomic rename β concurrent drains never duplicate because rename is the synchronisation primitive. The [STEER] and [FOLLOWUP] markers and meta.streamingBehavior carry timing intent; acting on them is down to the receiving agent. The pi bridge honours the hint natively via deliverAs.
| Type | Discovery | Join | Read history |
|---|---|---|---|
public | Listed in list_rooms | Anyone | Anyone |
private | Name visible | Invite only | Members only |
secret | Invisible | Invite only | Members only |
| Level | Listed | Can be DM'd | Room member list |
|---|---|---|---|
visible | β | β | β |
hidden | β | β (if ID known) | Members only |
ghost | β | β | β |
When an agent joins a room, it receives a room_members delivery event listing all current members with their status. Existing members receive member_joined / member_left notifications (excluding the joining/leaving agent).
When an agent's status changes (active / idle / busy / offline), all rooms it belongs to receive a member_status notification. This covers:
update actionMessages carry a readBy field tracking which agents have consumed them. Status events are emitted to the sender automatically β no explicit action needed.
| Moment | Sender receives |
|---|---|
| Message queued for recipient | delivery_status { status: "delivered" } |
| Recipient's bridge consumes it | delivery_status { status: "read" } |
Read receipts fire when onDelivery is called (push bridges: pi, Claude Code) or when drainDelivery is called (drain bridges: MCP, Codex, OpenCode). Cross-peer read receipts propagate via a message_read mesh patch.
This works for both room messages and DMs.
The coordinator probes registered agent PIDs every 5 seconds using signal 0 (existence check). Dead agents are marked offline and the status is broadcast to all peers. Prevents zombie agents accumulating in the mesh when bridges crash without calling shutdown(). The probe interval only runs on the coordinator β other peers are passive.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/agent-comms)<a href="https://allmcps.com/mcp/agent-comms"><img src="https://allmcps.com/api/badge/agent-comms?style=directory" alt="Agent Comms on AllMCPs" /></a>