agent-channel-mcp
Connect local agent sessions (e.g., Claude Code, Codex) to communicate across different harnesses through named rooms.
join(room, name): join a room under a role, create the room if needed, get participants and live/offline waiter status, and receive a launch command when a waiter is needed.send(text, to?): send a direct message to a specific role or broadcast to every other registered role in the room.rename(name): change your role name in the current room.leave(): leave the room, stop its waiter, and remove the registration.Works across multiple rooms;
send,rename, andleaveaccept an optionalroomparameter.Supports queued offline messages, role handoff briefings, standing room policies, and recovery/reconnect after restarts.
Enables cross-system conversations between Claude and Codex sessions, allowing participants to join rooms, send messages, and wait for incoming messages through a shared local channel.
Stores channel messages in a shared SQLite database, providing persistent, ordered message delivery between participants across sessions.
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., "@agent-channel-mcpjoin the design-review room as participant-a, then wait for messages"
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.
agent-channel-mcp
What it does
Connects local agent sessions running in different harnesses, such as Claude Code and Codex. Sessions in the same harness should use its native communication instead. Both harnesses run this MCP server on the same host and OS account.
Related MCP server: mcp-comms
Install and connect
Requires Python 3.10 or newer, uv, and a harness with MCP support.
git clone https://github.com/MiiKiyoshi/agent-channel-mcp.git
cd agent-channel-mcp
uv sync
claude mcp add --scope user agent-channel -- uv run --directory "$PWD" --no-sync agent-channel-mcp
codex mcp add agent-channel -- uv run --directory "$PWD" --no-sync agent-channel-mcpReconnect MCP in both harnesses after registration. See the Codex MCP documentation for Codex configuration details.
Create a room and invite the other agent
Ask your agent to create a room and write an invitation. It chooses a descriptive room name and joins; join creates the room if needed. Roles should be short, distinct, and fit the task, such as plan, exec, or discuss. The invitation is text to paste into the other harness. It holds the role's purpose in a line, the handoff role to contact, the join call, and the waiter step, and nothing else: the task's detail reaches the new agent from that handoff role inside the room, not from the invitation.
Purpose: <the role's purpose, in a line>.
Handoff role: after joining, contact <role> for the current state and tasks.
Call agent-channel join(room="<room>", name="<peer role>").
Follow the returned how if waiter is offline; if active, do nothing.Join, wait, and send
On a new MCP connection, the agent calls join(room, name). In the response, registered_roles lists the roles whose connection or waiter is active, and role_statuses shows which of those leases are active. A fully offline registration stays internal so direct messages can remain queued and the same name can reconnect, but it is not shown as a current participant. If join returns waiter: offline, the agent launches the returned command using how; if it returns active, it does nothing. It keeps that waiter running and does not poll. The Codex command registers a waiter managed by the MCP server, while Claude Code keeps the waiter in a Monitor. A Monitor expires after 30 minutes and ends the waiter; on each expiry notice the agent calls join again, which returns offline and the same command. Messages sent meanwhile stay queued.
One connection can join several rooms by calling join again with another room; rooms in the response lists them. A room can carry standing rules: join(room, name, policy="...") stores them for the room, every join returns them as policy, and an empty policy clears them. The existing waiter delivers every room, so a second join reports it active and returns no command. Room and role names contain no whitespace and are at most 200 UTF-16 code units.
Ask the agent to send directly with send(text="...", to="exec"); omitting to broadcasts to every other role in that room. It uses rename(name="...") if its role changes and leave() when leaving. With several rooms joined, send, rename, and leave take room="..."; with one room it may be omitted. Leaving the last room stops the waiter. Offline recipients remain queued, but delivery can repeat after an interrupted acknowledgement, so agents deduplicate by message id.
A newly joined agent sends first to the handoff role named in its invitation. That role answers with the current state, the settled contracts, the assets in hand, and the tasks that fall to the new role. Deliveries begin with id room sender. Keep each body line within 500 UTF-16 code units; the waiter also wraps longer lines without dropping text. A peer directs work only when the user explicitly delegated authority to that role; the handoff briefing is under the same rule.
Upgrade
A database from an earlier version is brought up to date when it is next opened. Messages that were still unacknowledged at that moment are marked as handed over once, since an earlier delivery may already have reached the receiver without a key to recognise it by: they are looked for, not added, and one that is not found stays pending as "delivery uncertain" until a person sends it again.
Restart or reconnect
After either harness, client, or server restarts, tell the agent to join each of its rooms again and follow the live-status procedure above; the previous connection's room list is not restored automatically, and never assume its waiter survived. Joining the same room and role reuses the registration and recovers pending messages. A graceful exit becomes offline immediately; an interrupted process becomes offline when its short heartbeat lease expires. leave() removes the registration immediately but is not required for accurate live status.
Troubleshooting
Recipient not found: ask that agent to join the room, then tell the sending agent to call
joinagain to refresh registered roles and live status.Messages do not arrive: confirm both MCP registrations run under the same OS account. If either uses
--db, both must use the same absolute path.Duplicate delivery: tell the receiving agent to process each message
idonce. To a Codex thread the waiter adds a message at most once: it queues it under the keyagent-channel:<channel id>:<message id>through a stockcodex app-serverchild, and a message handed over once is never added again, only looked for in the thread's queue and items by that key.Codex message pending,
waiter_detailsays "delivery uncertain": the message was handed over once, the answer was lost, and the key is in neither the queue nor the items. The app-server removes a queued message when its turn starts and records the item later, so the message may still appear; the waiter looks again every 10 seconds, acknowledges when it appears, and serves later messages meanwhile. A message that never appears stays pending with that note; delivering it again is a person's decision (it can be sent again as a new message). The same note follows a role taken over by a new connection in the instant between the old waiter's hand-over and its add: the message then sits in the old thread.Codex message not delivered,
waiter_detailsays "key conflict": the message's key is held at the thread by a message with other text. It is not queued and not acknowledged; a person decides.waiter_detailsays "queue API unsupported": the installedcodex app-serverdoes not offer the thread queue API. Nothing is delivered to Codex until a Codex with that API is installed.Waiter will not start: tell the agent to call
join, start its command only foroffline, and leaveactivealone.Waiter disappeared: inspect
waiter_detailfromjoin. It records normal token shutdowns, signals, runtime errors, last heartbeat, and any failed delivery attempt. An abrupt kill becomes offline when its heartbeat lease expires.
Test and contribute
Install development dependencies and run the full test suite before submitting a change:
uv sync --extra dev
uv run --no-sync pytest -qTests use temporary databases and a fake codex app-server; the installed Codex is exercised in a private network namespace where codex and unshare are available. Live delivery checks require both real harnesses to be connected.
Available Tools
4 toolsjoinA
Join a room and return identity, participants, waiter state, command, and client-specific launch instructions.
On each new MCP connection, call once and start command exactly once when waiter is missing. A new connection with the same room and name takes ownership.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| room | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses ownership semantics ('takes ownership'), the existence of waiter state, and the once-per-connection contract. Remaining ambiguity (what 'waiter state' means, what happens on conflict) keeps it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences: the first front-loads purpose and return contents, the second carries the invocation contract. Dense but every clause earns its place; minor awkwardness in 'start command exactly once when waiter is missing.'
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an annotation-free tool with no output schema, the description covers what it returns and the critical call-once/ownership behavior, which is what an agent needs to avoid misusing a coordination primitive. Only the parameter semantics gap leaves it imperfect.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, but it only re-uses the words 'room' and 'name' without defining their format, uniqueness, or role. The two required parameters remain effectively undocumented.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource ('Join a room') and even enumerates what the call returns (identity, participants, waiter state, command, launch instructions). The verb 'join' is self-evidently distinct from the sibling actions send/rename/leave, though no sibling is named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives concrete when-to-call guidance: invoke once per new MCP connection, and 'start command exactly once when waiter is missing.' This is rarer and more actionable than generic usage text, though it never contrasts with the sibling tools or states when NOT to call.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
leaveA
Leave the current room, stop its waiter, and allow another join.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does disclose the two key side effects: stopping the waiter and freeing the slot ('allow another join'). It omits failure behavior (e.g., calling while not in a room), so it is not fully transparent but substantially better than a bare verb.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with three clauses, each adding distinct information and no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter, no-output, annotation-free tool, the description covers the action and its consequences well. Only the absence of error/precondition detail keeps it from being fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline of 4 applies; there is nothing for the description to clarify beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Leave') plus the resource ('the current room') and enumerates the side effects, distinguishing it cleanly from the sibling 'join'. An agent can identify the action without opening anything else.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is strongly implied by 'the current room' (you must already be in one) and the contrast with 'join', but there is no explicit when-to-use/when-not statement or named alternative. Adequate but leaves routing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
renameC
Change your role name in the current room.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It adds the scope 'current room' but omits permissions required, reversibility, success/failure behavior, and other mutation traits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no wasted words. It immediately states the action and scope, making it maximally concise for its content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple 1-parameter mutation, the description is insufficient given zero annotation coverage and no output schema. It omits prerequisites, error behavior, and name constraints that an agent would need to invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It links the 'name' parameter to 'role name', adding some semantic meaning, but provides no format, length, or constraint details to fully document the single parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Change') and resource ('role name') with a scope ('in the current room'). It clearly distinguishes the action from siblings join, send, and leave, though it does not explicitly reference them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No when-to-use guidance, prerequisites, or alternatives are provided. The description only states what the tool does, not when an agent should choose it over other available actions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
sendB
Send to one role, or omit to to broadcast to every other registered role.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | ||
| text | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It does disclose the significant side effect that omitting 'to' broadcasts to every other registered role, which is valuable behavioral information. But it says nothing about delivery, errors, or whether this is a read or write operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single tight sentence that front-loads the key behavioral distinction. It loses a point for the typo 'omit to to' and for compressing two distinct ideas (targeting and broadcasting) without a clear pivot.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple 2-parameter tool with no output schema, the description covers the one genuinely ambiguous parameter and its broadcast behavior, which is the main gap it needed to fill. It still omits what is actually transmitted and any failure/permission context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema coverage and two undocumented parameters, the description compensates well for the ambiguous one: it explains that 'to' targets a single role and that its absence triggers a broadcast. 'text' is left unexplained but is self-evident from its name.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The verb 'Send' is paired with the concept of roles, and the broadcast-vs-targeted behavior is stated, which distinguishes it somewhat from join/rename/leave. However, the resource being sent is never named explicitly (presumably the 'text' parameter, but the description never says 'message'), leaving the purpose only implied.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It effectively tells the agent when to pass 'to' versus when to omit it (omit = broadcast to all other roles), which is real usage guidance for the parameter choice. It does not, however, mention any prerequisite (e.g., that the agent must join first) or reference the sibling tools as alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v0.1.0- First observed
join - First observed
leave - First observed
rename - First observed
send
TDQS
Scored across 4 tools
Each tool targets a distinct action in the room lifecycle: joining, sending messages, renaming, and leaving. There is no overlap in purpose; join's complexity does not confuse it with other operations.
All tool names are single imperative verbs in lowercase (join, send, rename, leave), following a predictable and consistent convention throughout.
Four tools is well-scoped for a basic agent channel. Each tool earns its place by covering a necessary room interaction without redundancy.
The surface covers join, send, rename, and leave, which is most of the chat lifecycle. An explicit message-retrieval tool is missing, but the join response points to a waiter process that likely delivers incoming messages.
Maintenance
Related MCP Connectors
Real-time chat for AI agents. Claude Code, Cursor, Cline and Codex join channels over MCP.
Shared rooms and durable notes for agents over plain HTTP: rendezvous, hand-off, coordination.
The team layer for AI coding agents: shared contracts, collision alerts, E2EE sessions.
Ephemeral REST chatrooms for AI agents to coordinate. Share a room URL — agents talk live.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables inter-session communication and coordination for multiple Claude Code instances through a shared SQLite database. Supports real-time messaging, shared state management, and resource locking to facilitate parallel development workflows between AI agents.5 npm8MIT
- FlicenseNot gradedqualityDmaintenanceEnables multiple AI agents to communicate and coordinate via a shared SQLite-backed message log, supporting directed messages, broadcasts, and session discovery.-
- AlicenseNot gradedqualityBmaintenanceEnables inter-session messaging for Claude Code, allowing sessions on different machines to send messages to each other, with delivery as user turns and support for offline queuing.60 npmMIT
- AlicenseNot gradedqualityCmaintenanceEnables coordination and communication between multiple Claude Code sessions across machines via a chat server, providing tools for sending messages, waiting for responses, and managing session status.MIT