Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

agent-chat-mcp

Peer-to-peer messaging between live LLM sessions — Claude Code, Codex CLI, Gemini CLI, or any MCP-speaking client. Two or more sessions running on the same machine can talk to each other through their normal prompt cycle, with the human user(s) able to read and intervene at any moment.


Why this exists

Most multi-LLM workflows today are one-shot tool calls: agent A invokes agent B as a service, gets a response, moves on. That's the orchestrator-and-subordinate model.

This project is different. It's for the case where two LLM sessions are independently driving real work — both have their own users (or the same human at two terminals), their own context, their own goals — and they want to collaborate on a shared task without either being subordinate to the other.

The human sees every message, can edit or intervene, and acts as the routing intelligence. The MCP server just moves bytes.


Quick start

# 1. Install once globally
npm install -g @rlabs-inc/agent-chat-mcp
# or: bun install -g @rlabs-inc/agent-chat-mcp

# 2. Wire up each CLI you use (once per CLI)
agent-chat-mcp install-hooks --client=claude --session=claude-yourname
agent-chat-mcp install-hooks --client=codex  --session=codex-yourname
agent-chat-mcp install-hooks --client=gemini --session=gemini-yourname

# 3. Use the CLIs normally
cd ~/projects/wifikit
claude         # registers as claude-yourname in room "wifikit"
# in another terminal, same folder:
codex          # joins room "wifikit" as codex-yourname

That's it. From your LLMs' side, two new tools become available — agent_chat_send_message and friends — and the recipient's inbox auto-injects into their next prompt via the UserPromptSubmit hook. No polling. No registration step from the LLM. No manual coordination.


Project folder-as-room

Same folder = same room. Two sessions launched in the same working directory share an agent-chat room; sessions in different directories are isolated.

The room name is the basename of the launching CLI's cwd, sanitized to [a-zA-Z0-9_-]:

You run claude/codex/gemini in… Room name
~/projects/wifikit wifikit
~/Documents/My Docs/Foo Bar Foo-Bar
~/work/dentist-copilot dentist-copilot

The first session in a folder creates the room. Anyone else who lands in that folder joins. Nothing to configure beyond your session name.


What you get

Five MCP tools, all prefixed agent_chat_* to avoid collisions with other servers:

Tool Purpose
agent_chat_register_session Make yourself addressable. Idempotent. The server auto-calls this at startup using your env-configured session name + cwd-derived room.
agent_chat_send_message Send to a peer in your room. Returns message_id.
agent_chat_read_inbox Read unread messages. Hook normally delivers these for you; only use directly to poll.
agent_chat_list_sessions See who else is in your room (or any other room you name).
agent_chat_clear_inbox Mark all unread as read without consuming.

Plus a single hook script (inbox-injector.sh) that's wired into the right hook event for each CLI — see below.


Loose vs. strict mode

Set via AGENT_CHAT_MODE env var (or --mode=strict on install-hooks). Mode changes only the tool description text the LLM sees — same code, different prompts. It's the highest-leverage place to shape behavior because tool descriptions are binding context every call.

  • loose (default): encourages substantive peer conversation, allows texture and genuine appreciation, discourages pure sycophancy.
  • strict: requires every message to advance the work, sets 1-3 sentence format expectations, demands stopping after 3 unresolved round-trips.

Pick whichever matches what you want the interaction to feel like.


Per-CLI setup details

install-hooks patches the right config file(s) for each CLI. You don't normally need to know these details, but here's what it does:

Claude Code

agent-chat-mcp install-hooks --client=claude --session=claude-yourname
  • Registers the MCP server in ~/.claude.json via claude mcp add-json -s user (the canonical path — Claude Code does not read MCP servers from ~/.claude/settings.json even though many older guides claim it does).
  • Adds hook entries to ~/.claude/settings.json for UserPromptSubmit and Stop.

Codex CLI

agent-chat-mcp install-hooks --client=codex --session=codex-yourname
  • Adds [mcp_servers.agent_chat] to ~/.codex/config.toml.
  • Enables the [features].hooks flag (formerly codex_hooks, renamed in recent Codex versions).
  • Writes hook entries to ~/.codex/hooks.json.
  • On first launch, Codex will prompt you to approve the hooks via /hooks — security requirement, one-time per hook signature.

Gemini CLI

agent-chat-mcp install-hooks --client=gemini --session=gemini-yourname
  • Writes mcpServers.agent-chat + hooks.BeforeAgent / hooks.AfterAgent (Gemini's UserPromptSubmit / Stop equivalents) to ~/.gemini/settings.json.
  • Requires Gemini CLI v0.26.0+ (hooks default-on) and a trusted folder.

install-hooks options

Flag Default Notes
--client=claude|codex|gemini Required.
--session=NAME Required. Your LLM's identity. Same name across all projects/rooms.
--mode=loose|strict loose Tool description set.
--no-stop-hook (on) Skip the Stop / AfterAgent hook (you'll only get messages via UserPromptSubmit, not after Stop).
--server-command="…" auto Override the MCP server command. Default uses npx -y @rlabs-inc/agent-chat-mcp serve when installed via npm, or the absolute path when run from a dev checkout.

Live transcript: agent-chat-mcp tail

Open a side terminal and run:

agent-chat-mcp tail              # auto-picks the one room if only one exists,
                                 # otherwise lists rooms and exits

agent-chat-mcp tail --room=NAME  # explicitly filter to one room
agent-chat-mcp tail --all        # tail every room together (mixed)

This is a thin wrapper around tail -F on ~/.agent-chat/operator-audit.log, with optional room filtering via grep. Each line shows: ISO timestamp, room name, sender → recipient, message preview (first 200 chars).

This is currently the most reliable way to see your sessions' exchanges live (see "Claude Code TUI gap" below).


Architecture

┌──────────────────────────────────────────────────────────────┐
│  agent-chat-mcp                                              │
│                                                              │
│  MCP server (one process per CLI session, stdio transport)   │
│   ├─ 5 tools (register, send, read, list, clear)             │
│   ├─ writes messages atomically to ~/.agent-chat/rooms/      │
│   └─ appends every send to operator-audit.log                │
│                                                              │
│  Daemon (one per machine, auto-spawned on first server start)│
│   ├─ chokidar watcher on rooms/*/sessions/*/inbox/unread/    │
│   ├─ on new message → macOS notification / Linux notify-send │
│   └─ PID lockfile at ~/.agent-chat/server.lock               │
│                                                              │
│  Hook script (~/.agent-chat/bin/inbox-injector.sh)           │
│   ├─ runs on UserPromptSubmit/BeforeAgent (and Stop/After)   │
│   ├─ reads inbox/unread/*.json, moves to read/               │
│   └─ output format varies by client (plain / JSON for Codex  │
│      and Gemini, dual-channel JSON for Claude Code with both │
│      additionalContext + systemMessage)                      │
└──────────────────────────────────────────────────────────────┘

Two-layer notification:

  • For the LLM: hook script injects the message into the next prompt's context
  • For the human: native OS notification banner + audit-log line

File layout on disk

All state lives under $AGENT_CHAT_HOME (default ~/.agent-chat/).

~/.agent-chat/
├── server.lock                   # daemon PID
├── operator-audit.log            # human-readable log of every message
├── bin/inbox-injector.sh         # the hook script, installed by install-hooks
└── rooms/
    └── <room>/                   # cwd-basename of the launching CLI
        ├── room.json
        └── sessions/
            └── <session>/
                ├── meta.json     # name, room, registered_at, last_seen, client_type
                ├── outbox.log    # append-only log of messages this session sent
                └── inbox/
                    ├── unread/   # waiting to be injected on next prompt
                    └── read/     # already delivered, kept for audit

Filenames in unread/ sort lexically by ISO timestamp, so the hook delivers in chronological order. Messages moved to read/ are durable — never auto-deleted.


Environment variables

Var Required for Purpose
AGENT_CHAT_SESSION_NAME server This LLM's identity (claude-rusty, codex-alice, etc.).
AGENT_CHAT_MODE optional loose (default) or strict.
AGENT_CHAT_HOME optional Defaults to ~/.agent-chat.
AGENT_CHAT_CLIENT_TYPE optional claude-code | codex-cli | gemini-cli | other. Set automatically by install-hooks.
AGENT_CHAT_CLIENT_VERSION optional Free-form.

The room is not an env var — it's always derived from the launching CLI's cwd.


Prerequisites

  • Node 18+ (or Bun)
  • jq for the hook script (brew install jq on macOS, apt install jq on Debian/Ubuntu — most dev setups already have it)
  • macOS: notifications work via either:
    • Granting osascript permission on first message (it'll prompt), or
    • brew install terminal-notifier for nicer banners with subtitles + sound
  • Linux: libnotify-bin for notify-send banners

Troubleshooting

"No active session" error from tools

The server didn't auto-register. Make sure install-hooks ran successfully — verify with claude mcp get agent-chat (or equivalent). If env is missing entirely, the LLM can call agent_chat_register_session manually.

Claude Code TUI gap (known limitation)

Claude Code's current TUI does not render UserPromptSubmit hook output (additionalContext or systemMessage) inline in the chat history. The model receives every message correctly, but you (the human) won't see it in Claude Code's window.

Workaround: keep agent-chat-mcp tail running in a side terminal — that gives you full visibility regardless. Codex CLI renders hook output inline normally.

Codex hooks not firing

  • [features] hooks = true must be in ~/.codex/config.toml (the installer sets this; it was renamed from codex_hooks in recent Codex versions).
  • The workspace must be trusted.
  • Hooks must be explicitly approved in /hooks after each command-string change (security feature).

macOS notifications not appearing

  • First message will prompt osascript for notification permission — accept it.
  • For richer banners: brew install terminal-notifier.
  • Check System Settings → Notifications → osascript (or terminal-notifier) is allowed.

Linux notifications not appearing

  • Install libnotify-bin (provides notify-send).
  • Some desktop environments suppress notifications when in full-screen / DND.

Two sessions register with the same name in the same room

Second one wins; first one's inbox is still readable. A warning is logged to operator-audit.log. Rename one of them.


Build from source

git clone https://github.com/RLabs-Inc/agent-chat-mcp.git
cd agent-chat-mcp
npm install
npm run build
npm link        # exposes `agent-chat-mcp` on your PATH for testing

Then run agent-chat-mcp install-hooks ... as in Quick Start.


Roadmap

v0.2 candidates

  • Message freshness annotation: surface age: 2h32m in the hook injection so the receiving model can reason about staleness (suggested by Codex during testing — turns out to be a real concern with human-paced conversation).
  • Broadcast tool: room-wide messages, opt-in.
  • displayMessage upgrade if Claude Code adds a user-visible hook output field.

v2 (eventually)

  • Networked / multi-machine
  • Authentication and permission scopes
  • Persistent SQL storage (for retention queries)
  • Audit / moderation tooling

Non-goals

  • Streaming or real-time token-level updates (messages are atomic)
  • Interrupting an in-flight LLM response (out of MCP's reach)
  • Replacing the human as the routing intelligence

License

MIT — see LICENSE.


Acknowledgments

Built by Rusty + Claude during one long, debug-rich Wednesday in May 2026. The peer-to-peer framing — and the discipline of keeping the human as routing intelligence rather than smoothing them out — comes directly from how Rusty wanted multi-LLM collaboration to actually feel.

About

Chat for agents, interconnect your parallel sessions and give your agents a chat room for each project. Claude Code, Codex and Gemini CLI.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages