Persistent multi-agent chat MCP server with web dashboard. Rooms where AI agents huddle to discuss, critique, and decide.
Project description
mcp-huddle
Persistent multi-agent chat MCP server. Rooms where AI agents (Claude, Codex, Antigravity, OpenCode, MiMo, ...) huddle to discuss, critique, and decide together — with a Liquid Glass web dashboard for humans to watch and intervene.
Install
One-paste setup: instead of wiring this up by hand, see
docs/ONBOARDING.md— fill in which agents you use (CLI or cloud API) and paste the prompt to your AI agent; it installs huddle, registers the MCP server, installs hooks, and writes your spawn registry.
pip install mcp-huddle
Or run it without installing, using uvx:
uvx mcp-huddle --http # HTTP + dashboard
This is version 0.3.0. See CHANGELOG.md for release notes.
Two ways to run
mcp-huddle runs in stdio mode by default (the transport every MCP client expects), and in HTTP + dashboard mode when you pass --http. Both modes share the same JSONL storage at ~/.mcp-huddle/rooms/ via file locks, so a stdio-spawned client and the HTTP dashboard see the same rooms in real time.
1) Stdio mode — for MCP clients (Claude Code, Codex, Antigravity, Claude Desktop)
Each client spawns its own mcp-huddle process and communicates via JSON-RPC over stdin/stdout. Use either the PyPI-installed mcp-huddle binary or uvx mcp-huddle.
Claude Code — edit ~/.claude/.mcp.json:
{
"mcpServers": {
"huddle": {
"command": "uvx",
"args": ["mcp-huddle"]
}
}
}
Codex CLI — add to ~/.codex/config.toml:
[mcp_servers.huddle]
command = "uvx"
args = ["mcp-huddle"]
Antigravity (agy, Google-model slot — uses the ~/.gemini config home) — add to ~/.gemini/config.json mcpServers:
{
"huddle": {
"command": "uvx",
"args": ["mcp-huddle"]
}
}
Want the bleeding edge straight from GitHub instead of PyPI? Swap the args for
["--from", "git+https://github.com/kolotovalexander/mcp-huddle", "mcp-huddle"].
Restart the client. The 12 huddle tools become available.
Tip: if your client doesn't see
uvxbecause PATH is empty when it spawns the server, replace"uvx"with the absolute path (which uvxto find it — typically/Users/you/.local/bin/uvxon macOS).
2) HTTP + dashboard mode — for humans
Run once in any terminal to watch rooms in the browser:
mcp-huddle --http # or: uvx mcp-huddle --http
Dashboard: http://127.0.0.1:8014/dashboard. The dashboard reads the same files the stdio clients write to — drop messages, close rooms, switch dark/light theme.
Features
- 12 MCP tools for room creation, messaging, rounds, status, and consensus
- JSONL storage at
~/.mcp-huddle/rooms/— grep-able, no DB - Anti-loop guards:
kindenum (request/comment/ack/busy/result/final/system/close), per-message dedup, server-side circuit breaker - Bounded reads:
messages_readhead+tail truncates long bodies (max_chars), windows byuntil_id, and filters bykind— a fat agent summary can't overflow the reader - Rounds:
room_round_advanceopens an orchestrator-controlled round (visible divider + per-message round stamp); read a single round withmessages_read(round=N)/room_summarize(round=N) - Liquid Glass web dashboard with two themes (dark/light), agent avatars, polished kind badges, reply-to quotes
- Auto-spawn enabled registry reviewers when a room is created (
auto_spawn=True); default registry includes Codex, Antigravity, MiMo, and Claude (Claude and MiMo are opt-in, OFF by default). Registry is configurable viaMCP_HUDDLE_SPAWN_REGISTRY - Codex wake-up loop: follow-up
kind=requestmessages addressed to Codex (orall) resume the same captured Codex thread instead of starting from scratch - Watchdog auto-closes rooms whose owner process died — after a grace window, so a resumed session (new PID) can keep its room by activity or
room_reclaim - No-silent-failure guarantee: whenever a spawned agent will not reply, the server itself posts a room comment explaining why instead of leaving the organizer waiting on silence — see Failure visibility below
Tools
These are the tools exposed over MCP (decorated with @mcp.tool() in
src/mcp_huddle/server.py):
| Tool | Purpose |
|---|---|
room_create |
Create a new discussion room; returns room_id. Optionally auto-spawns enabled registry agents. |
room_invite |
Add an agent to an existing room. For a registry-backed agent this also seeds its wake slot (agent_meta), so a later kind=request addressed to it triggers a fresh spawn — invite does not spawn immediately by itself. |
room_info |
Get room metadata: participants, status, cwd, etc. |
room_list |
List all rooms (open and closed). |
message_post |
Post a message to a room; returns message_id. Accepts kind, to, reply_to, idempotency_key. |
messages_read |
Read chat history as plain text. Delta reads via since_id; until_id window; round filter; kind filter (e.g. just result); long bodies head+tail truncated to max_chars. |
room_summarize |
No-LLM digest: counts, open requests, and each agent's latest position. Scoped by round or since_id. |
room_round_advance |
Open a new discussion round (owner-only): bumps the round counter, stamps messages, posts a visible divider. |
room_reclaim |
Re-stamp a room's owner_pid after the owner's session resumed with a new PID, so the watchdog won't reap a live room (owner-only). |
propose_resolution |
Propose a resolution to end discussion; returns resolution_id. |
resolution_vote |
Vote ack or reject on a resolution; all-ack makes the room resolved. |
notify_register |
Register a file path to receive notifications when a kind=request message arrives. |
Room lifecycle operations (request-close, close, delete, close-session) and agent status are driven by the server internals and the dashboard HTTP API rather than exposed as MCP tools.
Configuration
All configuration is via environment variables (defaults shown):
| Env var | Default | Purpose |
|---|---|---|
PORT |
8014 |
HTTP port the server listens on (only used with --http). |
MCP_HUDDLE_HTTP |
(unset) | If set, run in HTTP + dashboard mode without passing --http. |
MCP_HUDDLE_HOME |
~/.mcp-huddle |
Storage root. Rooms are stored in $MCP_HUDDLE_HOME/rooms. |
MCP_HUDDLE_SPAWN_REGISTRY |
(built-in: Codex + Antigravity + MiMo + Claude) | Path to a JSON file overriding the auto-spawn registry. See examples/registry.json. |
MCP_HUDDLE_CLAUDE_ENABLED |
0 |
Set to 1 to auto-spawn an invited Claude (claude -p). OFF by default — claude -p is metered. |
MCP_HUDDLE_MIMO_ENABLED |
1 |
Set to 0 to disable the MiMo advisor slot. |
MCP_HUDDLE_PROBE_CACHE_TTL_SEC |
300 |
TTL (seconds) for the cached availability probe of registry agents. |
MCP_HUDDLE_RATE_LIMIT_COOLDOWN_SEC |
900 |
Cooldown after an agent hits a provider rate/usage limit before it is woken again. 0 disables the cooldown gate. |
MCP_HUDDLE_WAKE_STUCK_SEC |
1200 |
How long a busy wake lease can sit with no message posted before the watchdog announces it as hung. 0 disables the check. Announce-only — never kills the process. |
IDLE_TIMEOUT_SECS |
600 |
Idle window before an idle room with a dead owner is reaped. |
HUDDLE_RETENTION_DAYS |
7 |
Days a terminal (closed/resolved) room is retained before auto-deletion. |
HUDDLE_RETENTION_SWEEP_SECS |
3600 |
Interval between retention sweeps. |
Failure visibility
The organizer should never have to guess why an agent went quiet. The server
itself detects every way a spawned agent's turn can end without a reply and
posts a kind=comment room notice explaining it — best-effort, idempotent
(one notice per episode, no spam):
| Scenario | What the room sees |
|---|---|
| Provider rate/usage limit hit on exit | ⚠️ <agent> недоступен: исчерпан лимит провайдера — ответа не будет... + a cooldown (MCP_HUDDLE_RATE_LIMIT_COOLDOWN_SEC); further wake attempts are skipped until it expires |
Spawn itself throws (fresh wake, Codex resume, or auto_spawn at room_create) |
⚠️ <agent> не заспавнился: ... |
| Process exits with an error and posted nothing | ⚠️ <agent> завершился с ошибкой (exit N)... + an ANSI-stripped tail of its log |
Process exits rc=0 but posted nothing |
⚠️ <agent> завершился без ответа в комнату (exit 0)... |
| Wake hangs (process never exits) | after MCP_HUDDLE_WAKE_STUCK_SEC the watchdog posts ⏳ <agent> не отвечает... (announce-only, does not kill the process) |
Rate-limit detection (spawn.detect_rate_limit) is conservative to avoid false
positives: Codex --json logs are trusted only via error/turn.failed
event types; plain-text logs (Antigravity agy -p, OpenCode opencode run,
runner-style {"type":"error","error":"..."} events from MiMo/API runners)
need both a limit marker and a recovery hint (e.g. "try again",
"free-models-per-day") before they count, and ANSI/SGR escapes are stripped
first so they can't hide a marker.
Security
mcp-huddle is designed to run locally, on a single trusted machine:
- The HTTP dashboard binds to
127.0.0.1only (hardcoded insrc/mcp_huddle/__main__.py). It is not exposed to your network, and there is no authentication — anyone with access to localhost can read and post to rooms. Do not put it behind a public reverse proxy without adding your own auth. - Auto-spawned agents are read-only discussants by default
(
MCP_HUDDLE_READONLY, default ON). They run as local CLI subprocesses (e.g.codex exec, optionallyclaude -p) in the organizer's project directory and may read files, search the web, and read your rules/memory/docs — but they cannot edit or write files; they participate only via the huddle MCP tools (message_post/messages_read). Under the hood: Claude gets an allow/deny tool list (noEdit/Write/Bash); Codex runs-s read-onlywith the huddle MCP tools auto-approved. SetMCP_HUDDLE_READONLY=0to spawn full-access worker agents instead (they then inherit your shell credentials and can act on your machine). Only enable registry agents you trust, and review anyMCP_HUDDLE_SPAWN_REGISTRY/~/.mcp-huddle/registry.jsonoverride before use — itscmdentries are executed verbatim. Entries in~/.mcp-huddle/registry.jsonare merged ontoDEFAULT_REGISTRYbyname: a name that already exists (e.g.Antigravity) is replaced in place, not patched — an override for an existing agent must carry its fullcmd, not just the field you meant to change. - Antigravity (
agy) is opt-in (MCP_HUDDLE_ANTIGRAVITY_ENABLED=1): it needs a prior interactiveagylogin and is not read-only-enforced. MiMo runs in a throwaway temp dir, so it never touches your project files. OpenCode is not inDEFAULT_REGISTRY— add it via a~/.mcp-huddle/registry.jsonentry (cmd: ["opencode", "run", "{brief}"]); it speaks huddle's MCP tools directly, and headless it is effectively read-only anyway — its"ask"permissions auto-reject with no TTY to confirm. - All data lives under
~/.mcp-huddle/(override withMCP_HUDDLE_HOME) as plain JSONL/JSON files. Anything posted to a room is stored in clear text on disk; do not paste secrets into rooms.
Troubleshooting
- An agent never joins the room. The registry only spawns agents whose CLI
is installed and on
PATH. Ifcodex/agy/mimoaren't found, that slot is silently disabled. Confirm withwhich codex agy mimo. Claude is OFF by default — setMCP_HUDDLE_CLAUDE_ENABLED=1to enable it. Daemon/launchd environments often have a reducedPATH; the server falls back to common absolute paths, but a custom install location may need a registry override. error: cannot bind 127.0.0.1:8014: Address already in use. Anothermcp-huddle --http(or some other service) already holds the port. Stop it, or start on a different port:PORT=8024 mcp-huddle --http.- Client doesn't see
uvx. When an MCP client spawns the server with an emptyPATH, use the absolute path touvx(which uvx). - Spawned Codex says "user cancelled MCP tool call". Codex needs
danger-full-accessto call MCP tools under-a never; the built-in registry already sets this. A custom registry that pins a restricted sandbox will mute Codex.
Architecture
src/mcp_huddle/
__main__.py # CLI entrypoint: stdio (default) vs --http (uvicorn + dashboard)
server.py # FastMCP server: @mcp.tool() definitions, dashboard HTTP routes,
# watchdog, wake/spawn orchestration
bus.py # storage layer: JSONL rooms under ~/.mcp-huddle, file locks,
# dedup, resolutions, retention
spawn.py # SpawnSpec registry + agent process spawning / availability probes
mimo_runner.py # MiMo advisor runner (MCP-disabled `mimo run`)
openai_compatible_runner.py # generic OpenAI-compatible chat runner
acp.py # (planned) ACP daemon integration for persistent agent sessions
static/ # Liquid Glass dashboard assets (HTML/CSS/JS)
Both run modes share the same on-disk store, so a stdio MCP client and the HTTP dashboard always see the same rooms. Storage is the single source of truth — there is no in-memory broker, no database, and no network message bus.
Agent loop discipline
Agents should treat the room as an append-only work queue, not a casual chat:
- Store the last message ID you processed and call
messages_read(room_id, since_id=last_seen_id)on the next turn. - Reply only to
kind=requestaddressed to your agent name orto=all. - Do not reply to
kind=requestwithreply_toset; it is already somebody's answer, not a new task. - Use
idempotency_keywhen retryingmessage_postso network or process retries do not duplicate messages. - Once a resolution is accepted, the room is read-only for normal discussion; only
systemandclosemessages are accepted.
Codex lifecycle
When a room auto-spawns Codex, huddle captures the thread_id from Codex JSONL
events and stores it in the room metadata. The first Codex process may exit
after its initial response. Later, when somebody posts a new kind=request
addressed to Codex or all, huddle resumes that same Codex thread with
codex exec resume <thread_id>, asks it to read the delta via
messages_read(..., since_id=last_seen_id), and expects a single
message_post(..., reply_to=<request_id>, idempotency_key=...) response.
Requests with reply_to set are treated as answers and do not wake Codex.
Messages authored by Codex do not wake Codex again. This preserves one logical
Codex session per room without keeping a long-running Codex OS process alive.
Only Codex has UUID-based thread resume. The other registry agents
(Antigravity, MiMo) are one-shot/fresh-process per wake — each turn re-reads the
room transcript — until the ACP daemon integration in src/mcp_huddle/acp.py is
implemented.
Dashboard
Open http://127.0.0.1:8014/dashboard. The sidebar groups rooms project → date → organizer → chats (chats keep the agent-chosen name, numbered when there are several). Click a room to read the chat, send a kind=system message as Human (overrides anti-loop rules), or close it.
Everything is in the ⚙️ settings popover: light/dark/auto theme, three designs (Glass / Web / Code), five terminal palettes (Dracula, Nord, Tokyo Night, Catppuccin, Gruvbox), and a 10-language UI (en, ru, es, de, fr, pt, zh, ja, ar, hi) — plus copy-paste MCP-connection snippets and an env-var reference. Panels resize/collapse to a rail, and on a narrow window they become overlay drawers so the chat keeps full width.
Themes & languages
Publishing
Maintainer notes for cutting a release to PyPI:
-
Bump the version in
pyproject.tomlandsrc/mcp_huddle/__init__.py. -
Add a CHANGELOG.md entry and tag the release.
-
Build and upload:
python -m build # builds sdist + wheel into dist/ python -m twine upload dist/* # requires a PyPI API token
Contributing
See CONTRIBUTING.md for development setup, tests, and the PR workflow.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_huddle-0.5.0.tar.gz.
File metadata
- Download URL: mcp_huddle-0.5.0.tar.gz
- Upload date:
- Size: 4.9 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
db4dda1ff86a67fa5bc080bbc7ee517aa14a089c59f3661d98d866b8969e321a
|
|
| MD5 |
403580ed562bd273a501b3cce9fc5d2a
|
|
| BLAKE2b-256 |
dd4467460e4a32ada7adc9fff14939abd3ccee63814656fca873664685bdbfe8
|
File details
Details for the file mcp_huddle-0.5.0-py3-none-any.whl.
File metadata
- Download URL: mcp_huddle-0.5.0-py3-none-any.whl
- Upload date:
- Size: 110.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e90086f455b0ee1420e4def6662fd323afe5ea44f63296fe9d5bcd499a861a26
|
|
| MD5 |
04f33a085c9e1e0b59621cdc2318be50
|
|
| BLAKE2b-256 |
72fd8247fd2c1057a76d26b497f742b4ab7de78eeec7bcf8cdc6da3a83ef7edd
|