central-mcp
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., "@central-mcp dispatch a code review to project alpha"
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.
central-mcp
The portfolio PM for running many agent-driven projects at once.
All lines run through central. Dispatch across every project, and never lose the thread of any of them.
One MCP server turns any MCP-capable client (Claude Code, Codex CLI, Gemini CLI, opencode, Hermes Agent, OpenClaw, gajae-code) into a control plane for your portfolio of coding-agent projects. Ask in natural language, and the orchestrator routes the request to the right project's agent — non-blocking, with results reported back asynchronously — then briefs you on that project's real state whenever you come back to it.
Why
Agents made it cheap to run four, eight, fifteen projects at once. They did nothing about keeping track of them. Every context switch charges a re-orientation tax — what happened here while I was away? What state is it in? What was I about to do next? — and nobody is playing PM.
central-mcp is that PM:
Dispatch — send work to any project's agent, in parallel, and keep talking while it runs
Pulse — return to a project and get "what happened / where it stands / what's next", computed from the repository itself, so work that never went through the hub (direct commits, interactive agent sessions, manual edits) counts too
Digest — a fixed-format daily/weekly portfolio report, deliverable to chat by a resident agent or a plain crontab
Observe — live panes on the dispatches you're actively following
Orchestrate from anywhere — any MCP-capable client can be the front end; never locked to one vendor
Every dispatch is a fresh subprocess in the project's cwd (e.g. claude -p "..." --continue). No long-lived processes, no screen scraping, no tmux dependency on the critical path.
Related MCP server: agent-bridge
How you meet it — three tiers
central-mcp is a layer, not a place. A dedicated orchestrator you have to remember to visit gets forgotten, so the surfaces are ranked by how they reach you:
Ambient (the main way in).
cmcp install claudeonce, and every session of the CLI you already use carriesdispatch,project_pulse, and the rest alongside its normal tools. Open a project, ask "where does this stand?", and the briefing happens in place.Reach. A resident agentOS bridge — Hermes or OpenClaw — sends the daily digest and failure alerts to Telegram/Discord, the one channel that finds you when no terminal is open.
Focus.
cmcp tui(experimental), for sessions whose main job is orchestration — fan out, watch it land, supervise.
Design principles
Coding agent-agnostic. MCP tools are the canonical surface. Any MCP-capable client can be the orchestrator; any supported coding agent CLI can be the dispatch target.
Non-blocking dispatch.
dispatchreturns adispatch_idin <100ms. Results arrive asynchronously. The conversation never freezes.Dispatch-router preamble. The orchestrator is instructed to be a pure router — parse the project name, call
dispatch, move on. This minimizes LLM reasoning latency to ~1-2 seconds per turn.File-based state.
registry.yamlis the single source of truth.
Status
One-line curl installer ships at https://central-mcp.org — bootstraps uv when missing, installs central-mcp, and runs central-mcp init.
Supported platforms
Run central-mcp on the platform it's been exercised on, and expect a bit of roughness elsewhere:
macOS — primary development and test target.
Linux — expected to work (pure Python, tmux/zellij are cross-platform), but not regularly tested; please file issues if you hit edges.
Windows — not officially tested. The core (Python + MCP tools + the tmux / zellij backends where those run on Windows) should work in principle; the cmux backend is macOS-only, so the observation-layer options on Windows collapse to whichever of tmux / zellij you can install. Please file issues if you hit edges.
Quickstart
# One line — bootstraps uv, installs central-mcp, runs `central-mcp init`.
curl -fsSL https://central-mcp.org/install.sh | sh(tmux only if you want the optional observation layer.)
# Launch — one command does everything
central-mcpManual install if you'd rather not pipe a script:
# 1. Install uv (https://docs.astral.sh/uv/) if you don't have it yet curl -LsSf https://astral.sh/uv/install.sh | sh # 2. Install central-mcp + scaffold ~/.central-mcp/ uv tool install central-mcp central-mcp initOr with pip:
pip install central-mcp
The first central-mcp run auto-creates ~/.central-mcp/registry.yaml and registers central-mcp with every MCP client binary it finds on PATH (claude, codex, gemini, opencode, hermes, openclaw, gjc). After that it launches the orchestrator in your preferred agent.
Manual install if you want fine-grained control:
central-mcp install all— re-detect + register everywhere
central-mcp install claude— register with a single client
central-mcp init— create the registry without launching
Inside the orchestrator session, speak naturally — full example catalog in First session below.
The orchestrator calls dispatch for each request and continues the conversation immediately — you don't wait. Results arrive through three channels:
Piggyback (automatic): every MCP tool response includes a
completed_dispatchesarray with any results that finished since the last call.Background poll (best-effort): a subagent polls
check_dispatchevery 3 seconds and reports automatically when done.User-driven check (100% reliable): ask "any updates?" anytime.
Multiple dispatches run in parallel.
First session — natural-language examples
Everything below is spoken to the orchestrator in plain language. The orchestrator picks the right MCP tool and moves on. You do NOT need to memorize dispatch(...) / add_project(...) / check_dispatch(...) — those are the MCP-layer verbs shown elsewhere in the README for reference, not commands you type.
Set up (once):
"Add ~/Projects/my-app to the hub. Use claude as its agent."
"Register ~/Projects/api-server — default agent is fine."
"What projects do I have?"
Send work:
"Ask my-app to add a dark mode toggle in settings."
"Send my-app and api-server the same prompt: tighten up the README."
"Dispatch to my-app with codex instead of claude this time."
Check progress:
"What's running right now?"
"Any updates?" / "status?"
"How did that last dispatch to my-app go?"
"Show the last 3 dispatches for my-app."
"Overall status across all projects?" (triggers a portfolio-wide summary)
Recover / switch threads:
"Cancel the my-app dispatch — the prompt was wrong."
"What conversation sessions do I have for api-server?"
"Switch api-server to session abc123 for the next dispatch."
"Back to the default / latest session for api-server."
Language preferences:
"For my-app, answer me in Korean from now on."
"Use French for api-server unless I say otherwise."
"Just this one dispatch in Japanese for my-app."
"Clear the saved language for my-app and go back to English."
Shape the fleet:
"Put my-app and api-server at the top of the list."
"Remove the old legacy-tool project."
Observation tip for first-time users. Starting out, it's worth running central-mcp tmux (or zellij — or cmcp inside cmux.app on macOS) in a second terminal so you can see the per-project dispatch streams live while you chat with the orchestrator. It builds intuition for how fast dispatches really are and what kinds of prompts produce useful output. Once the orchestrator's summaries match what you'd have checked in the panes anyway, drop observation and work from the orchestrator alone — see Optional observation layer below for the full story.
MCP tools
central-mcp exposes 18 tools under the server name central:
Tool | Blocking? | Purpose |
| sync | Enumerate the registry. |
| sync | Metadata for one project — cheap, no subprocesses. |
| sync | What actually happened in a project, where it stands, what's live. Reads the repository (branch, upstream ahead/behind, uncommitted work, recent commits) plus dispatches, sessions, and open PRs — so work that never went through central-mcp shows up. Call it when the user returns to a project or asks "what's the state of X?". |
| sync | Pre-rendered daily/weekly portfolio report. Active projects, warnings (failed and never-finalized dispatches, quiet projects with uncommitted work), quiet list, quota line. Forward |
| <100ms | Send a prompt to a project's agent. Supports per-dispatch agent override and fallback chain. Returns |
| sync | Poll a dispatch — |
| sync | All active + recently completed dispatches. |
| sync | Abort a running dispatch. |
| sync | Last N dispatches for one project (reads its jsonl log). |
| sync | Portfolio-wide snapshot: in-flight + recent cross-project milestones + per-project counts. Call this for "how is everything going?" |
| sync | Enumerate the agent's resumable conversation sessions for one project, including a short best-effort |
| sync | Register a new project. Validates agent name. Auto-trusts codex dirs. |
| sync | Change an existing project's agent, description, tags, permission_mode, fallback, |
| sync | Reorder the registry. Lenient: names listed move to the front, others keep their relative order. Strict mode requires listing every project. |
| sync | Unregister a project. |
How dispatch works
dispatch("my-app", "add error handling to auth")
→ subprocess.Popen(["claude", "-p", "...", "--continue"], cwd="~/Projects/my-app")
→ returns {dispatch_id: "a1b2c3d4"} in <100ms
→ background thread captures stdout when process exits
→ check_dispatch("a1b2c3d4") → {status: "complete", output: "...", duration_sec: 45}Supported agents
Agent | Non-interactive invocation |
|
|
|
|
|
|
|
|
| — |
|
|
| — |
|
|
| — |
|
|
| — |
|
|
| — |
|
| — (print mode runs tools unattended) | — |
Agent names are validated at registration time — typos like cursor-agent are caught immediately, not at dispatch time.
Switching agents mid-project
You can change a project's registered agent any time — useful when a given codebase turns out to pair better with a different CLI:
update_project(name="my-app", agent="codex")update_project also accepts description, tags, permission_mode, and fallback — omitted fields stay untouched. Switching to codex auto-adds the project dir to ~/.codex/config.toml trust list.
One-shot agent override
Sometimes you want to route one task to a different agent without mutating the registry — e.g. a design-heavy task goes to a design-strong agent while the project stays on its usual one:
dispatch(name="my-app", prompt="...", agent="codex")The registry entry is untouched. Next dispatch without agent= goes back to the project's saved agent.
Fallback chain on failure
If the primary agent exits non-zero (rate limit, token cap, crash), central-mcp can transparently retry with a backup:
# per-dispatch (not persisted):
dispatch(name="my-app", prompt="...", fallback=["codex", "gemini"])
# save a default for this project:
update_project(name="my-app", fallback=["codex", "gemini"])The result reports which agent actually produced output (agent_used), whether a fallback was triggered (fallback_used), and the full list of attempts. Timeouts are not retried — the user should see them directly rather than burn the whole chain on a stuck agent.
Pass fallback=[] to explicitly disable the saved chain for a one-shot dispatch.
Permission modes
Most coding agents ask "is this OK?" before editing files, running commands, or installing packages. That's fine when a human is at the terminal — but anywhere central-mcp runs, there's no TTY to answer approval prompts, so the work can hang forever waiting for a reply that never comes. Every agent instance central-mcp spawns (orchestrator pane or project-level dispatch) runs in one of three permission modes:
Mode | What auto-approves | When to use |
| Everything. central-mcp emits each agent's own permission-skip flag (see mapping below). | Default. Fastest. No prompt-injection defense. Available on every supported agent. |
| Cwd-local file work, declared deps, read-only HTTP, pushes to branches Claude created. Everything else goes through a background classifier that blocks | Sensitive repos where prompt-injection resistance matters. Only supported by |
| Nothing. Any tool call that would normally prompt a human refuses and the agent surfaces the error. | Hardening for read-only tasks — Q&A, explain-code, reporting. Writes/builds/shell will fail. Available on every agent. |
Each vendor brands their permission-skip differently — central-mcp's bypass/auto are unified names that map to the right vendor flag per agent:
central-mcp mode | claude | codex | gemini | droid | opencode |
| Skip permissions | Bypass approvals + sandbox | YOLO | Skip permissions (unsafe) | Skip permissions |
| Auto mode | — | — | — | — |
| (no flag) | (no flag) | (no flag) | (no flag) | (no flag) |
If a vendor adds an equivalent to claude's auto mode later (codex sandbox-warn, gemini review-mode, etc), central-mcp will wire it into this same auto alias — existing config keeps working.
Modes apply at two separate layers:
1. Orchestrator layer — central-mcp run / central-mcp tmux / central-mcp up / central-mcp zellij
This is the agent you talk to — the orchestrator pane that calls MCP tools. Default: bypass. Change it with --permission-mode:
central-mcp tmux --permission-mode auto # claude-only, classifier-reviewed
central-mcp run --permission-mode restricted # no auto-approval, prompts will halt
central-mcp zellij --permission-mode bypass # explicit defaultWith orchestrator bypass, the orchestrator can freely read/write files inside ~/.central-mcp without asking — so CLAUDE.md, scratch notes, and hub-level edits happen without friction. With auto (claude + Sonnet/Opus 4.6 only), a background classifier vets each action instead of a blanket skip. auto is ignored (no flags emitted) for non-claude orchestrators. The orchestrator mode does not propagate to dispatched project agents; those carry their own per-project value.
2. Per-project dispatch layer — dispatch(..., permission_mode=...) / registry.yaml
This controls the agent spawned inside a specific project's cwd for one dispatch. The value is saved to registry.yaml on first dispatch (default: "bypass") and reused for every subsequent dispatch to that project. Flip it anytime:
dispatch(name="my-app", prompt="…", permission_mode="bypass") # auto-approve, save
dispatch(name="my-app", prompt="…", permission_mode="auto") # claude-only, classifier
dispatch(name="my-app", prompt="…", permission_mode="restricted") # no skip, no classifier
update_project(name="my-app", permission_mode="auto") # flip without dispatching"auto" is rejected with an explicit error if the project's agent chain includes anything other than claude — central-mcp never silently downgrades auto to bypass for a fallback. With "restricted", read-only dispatches still work (answering questions, reading files, explaining code); anything that would prompt (editing, shell, deps) times out — retry with bypass/auto, or open a regular terminal in the project's cwd for interactive approval.
⚠️
bypassis powerful — and at your own riskIn
bypassmode (at either layer), the agent may edit files, run shell commands, install packages, call network services, and push code without confirming with you first. That is what makes non-stop orchestration possible, but it also means a misguided prompt, prompt injection from a malicious source, or an agent hallucination can cause real damage — dropped tables, force-pushed branches, deleted files, leaked credentials, unintended API spend, etc.
automode is a middle ground — still headless, but a classifier blocks a standard set of destructive patterns (see the Claude Code permission-modes docs for the default policy). It reduces prompt-injection risk but does not eliminate it.restrictedis safest but only useful for agents that don't need to write.Typical reasoning:
Orchestrator mode controls what the hub-level agent can do in
~/.central-mcpand when calling MCP tools. Lower risk in practice because the hub dir has no production code, but still read/write.Per-project mode controls what each project-level agent can do inside that project's cwd. This is the higher-risk layer — it can rewrite your source, run your build, push branches.
Switch away from
bypass(toautofor claude, orrestricted) if any of these apply:
The project (or
~/.central-mcp) holds sensitive code, secrets, or production data you can't lose.No safety-net commit/push is in place.
You didn't read the prompt carefully or you're delegating work from untrusted sources.
You want to review every command the agent is about to run.
Disclaimer: central-mcp is a routing layer and does not supervise what the agents do. You are responsible for the scope, targets, and consequences of every dispatch you run in
bypass(orauto) mode at either layer. The authors and contributors of central-mcp are not liable for any damage, data loss, security breach, cost, or other harm that results from the selected mode. Use snapshots (git commits, backups, branch protection), least-privilege credentials, and offline/sandboxed environments where possible.
If a project deals with sensitive code and you're not comfortable granting blanket bypass, switch to auto (claude + Sonnet/Opus 4.6) or keep restricted and stick to read-only dispatches.
Session handling (conversation continuity)
By default, every dispatch resumes the agent's most-recently-modified conversation in the project's cwd — claude --continue, codex exec resume --last, gemini --resume latest, opencode --continue. Droid is the exception: its headless exec has no "resume latest", so a droid dispatch without an explicit session id always starts a fresh thread.
When the user wants to switch to a specific session (or recover from ambient drift — e.g., an interactive session in the same cwd made the "latest" move), dispatch(session_id=...) is a one-shot override:
list_project_sessions("my-app")
→ [{id: "a1b2...", title: "auth refactor", preview: "Investigate login timeout after refresh", modified: "..."}, ...]
dispatch("my-app", "continue from there", session_id="a1b2...")
# → claude -p "..." -r a1b2...After that dispatch, the resumed session is now the most-recently-modified — so the next default dispatch("my-app", "...") picks it up via --continue automatically. You only restate the id when you want to switch threads.
preview is intentionally bounded and best-effort, not a transcript dump. For filesystem-backed agents it usually comes from an early recognizable message in the session file; for CLI-only backends it may fall back to the backend's own title-like output.
For drift-proof behavior (or for droid, which needs a persistent pin to keep continuity), pin the session:
update_project("my-app", session_id="a1b2...")
# All future dispatches carry -r/-s <id> regardless of ambient state.
update_project("my-app", session_id="")
# Empty string clears the pin.Resolution precedence when dispatching: explicit session_id arg > project's saved session_id > agent's resume-latest flag.
Agent | Specific-session flag | Source of session list |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Preferred response language (per project)
Dispatch defaults stay unchanged: if no language is pinned or overridden, agents receive the original prompt and answer in their own default language (English for the agents central-mcp targets today).
When a project needs a different language consistently, save it in the registry:
update_project("my-app", language="Korean")Every future default dispatch to my-app now gets a preface like:
Respond to the user in Korean.
<original prompt>You can also set it at registration time:
add_project("my-app", "~/Projects/my-app", language="Korean")Per-dispatch behavior:
dispatch("my-app", "summarize the current status") # uses saved project language
dispatch("my-app", "summarize the current status", language="Japanese") # one-shot override
dispatch("my-app", "summarize the current status", language="") # suppress saved language once
update_project("my-app", language="") # clear saved language pinThe saved preference lives in registry.yaml as project metadata, so it is practical, explicit, and backward-compatible with older registries that simply omit the field.
Dispatch history (per project)
Every dispatch streams its start / output / complete events into ~/.central-mcp/logs/<project>/dispatch.jsonl (append-only). dispatch_history reads the terminal events back, merged with their matching start:
dispatch_history(name="my-app") # last 10 dispatches for my-app
dispatch_history(name="my-app", n=50) # last 50For a cross-project view, use orchestration_history (below).
Orchestration history (portfolio view)
Asks "how is everything going?" in one shot. Reads the global timeline at ~/.central-mcp/timeline.jsonl (also append-only) plus the server's in-memory in-flight table:
orchestration_history() # in-flight + last 20 milestones across all projects
orchestration_history(n=100) # wider slice of history
orchestration_history(window_minutes=60) # only count activity in the last hourThe response bundles: in_flight (running now), recent (newest milestones), per_project (dispatched/succeeded/failed/cancelled counts, last timestamp), and a registry snapshot. The orchestrator uses this to write a multi-project summary in one pass.
Performance / cost tip: lighter model for the orchestrator
The orchestrator's job is routing — it doesn't need top-tier reasoning. With Claude Opus 4.7 turns already land in ~2-3 seconds for routing, so latency is not a strong reason to switch. The stronger reason is tokens: every turn the orchestrator takes is billed against its model, and a routing turn with a lighter model is meaningfully cheaper. Optional tunings:
Orchestrator client | Tip |
Claude Code |
|
Codex CLI | Use a lighter model (e.g. |
Gemini CLI | Use Flash instead of Pro if your account offers it. |
opencode | Select a faster model via |
The sub-agent model is independent — each dispatch spawns its own process with whatever model the project's agent defaults to, so lightening the orchestrator does not lighten the sub-agents.
CLI reference
central-mcp # no-arg → launch orchestrator (same as `run`)
central-mcp run [--agent X] [--pick] [--permission-mode {bypass,auto,restricted}]
# launch orchestrator (default: bypass; auto is claude-only)
central-mcp serve # run MCP server on stdio (used by MCP clients)
central-mcp install CLIENT # register with claude | codex | gemini | opencode
# | hermes | openclaw | gjc | all
# hermes/openclaw also get the orchestration skill
central-mcp alias [NAME] # short-name symlink (default: cmcp)
central-mcp unalias [NAME]
central-mcp init [PATH] # scaffold registry.yaml (default: ~/.central-mcp)
central-mcp add NAME PATH [--agent claude|codex|gemini|droid|opencode|hermes|openclaw|gjc]
central-mcp remove NAME
central-mcp reorder NAME [NAME ...] # reorder projects — unlisted ones keep relative order
central-mcp list # one-line registry dump
central-mcp brief # orchestrator-ready markdown snapshot (registry only, ~50ms)
central-mcp pulse [NAME] [--commits N] [--history N] [--pr|--no-pr] [--json]
# what actually happened in a project — git + dispatches
# + sessions + open PRs. No NAME → sweep the workspace.
central-mcp digest [--workspace NAME] [--hours N] [--quiet-days N] [--no-quota] [--json]
# the portfolio report; `cmcp digest | <notifier>` from a
# crontab is a complete push-reporting setup
central-mcp workspace list # list workspaces with project counts
central-mcp workspace current # print the active workspace
central-mcp workspace new NAME # create a new workspace
central-mcp workspace use NAME # switch the active workspace
central-mcp workspace add PROJECT --workspace NAME
central-mcp workspace remove PROJECT --workspace NAME
central-mcp up [--no-orchestrator] [--permission-mode {bypass,auto,restricted}] [--max-panes N]
[--projects A,B,C] [--all-projects]
# optional tmux observation layer (active workspace).
# Panes go to the most recently active projects that fit
# one window; --projects picks, --all-projects tiles all.
central-mcp tmux [same flags as up] [--workspace NAME | --all]
# create session if missing, then attach via tmux
central-mcp zellij [same flags as up] [--workspace NAME | --all]
# same, but via zellij (generates a KDL layout)
central-mcp tmux switch NAME # attach to cmcp-<NAME> session (create if missing)
central-mcp zellij switch NAME # same, via zellij
central-mcp down # kill all cmcp-* observation sessions
central-mcp watch NAME [--from-start]
# stream one project's dispatch events
central-mcp upgrade [--check] # self-update from PyPI (uv → pip fallback)Optional observation layer
Why it's optional
A pane is a microscope, not a map. It earns its screen by showing one project's raw output closely. The portfolio question — where does everything stand? — belongs to
cmcp pulse,cmcp digest, and the orchestrator's briefing, which read git as well as the dispatch log.Orchestrator is the primary surface.
dispatch/check_dispatch/project_pulsereturn structured summaries; the orchestrator turns those into natural-language status — no scrolling stdout required.Work should be possible from anywhere. central-mcp is designed so a phone/tablet over SSH is enough to keep moving. The hub can't require a multi-pane desktop to function.
Turn observation on only when the live view actually helps — debugging a stuck agent, tailing a long migration, or screen-sharing the fleet. For normal operation it adds noise, not signal.
Suggested onboarding — start observed, graduate to orchestrator-only
On your first few sessions you almost certainly want the live view. Watching each project's dispatch events stream past builds a felt sense of how the orchestrator picks projects, how long dispatches actually take, which prompts produce useful output, and where things tend to stall. Treat observation as a trust-building phase: central-mcp tmux (or zellij, or cmux — see below) gives you panes side-by-side with the orchestrator, so you can eyeball its decisions against the raw agent output in real time.
Once the orchestrator's summaries start matching what you would have checked in the panes anyway, drop the observation layer. At that point you've internalized the pipeline, and working from the orchestrator alone — from any terminal, on any device, including a phone over SSH — is the mode central-mcp was designed for. The observation layer stays one command away (central-mcp tmux / central-mcp zellij / ask the orchestrator in cmux) for the specific moments that still benefit from it.
Backends
Two multiplexer backends are supported as CLI commands:
tmux —
central-mcp tmux(creates the session if missing, then attaches)zellij —
central-mcp zellij(generates a KDL layout, launches a zellij session or attaches to an existing one)
Both produce the same logical layout (hub tab + overflow tabs, project panes running central-mcp watch <project>). Pick the one you already have installed; you can use both from different terminals as long as they don't share a session name at the same time.
Sessions are named cmcp-<workspace> (e.g. cmcp-default, cmcp-work). Pass --workspace NAME to target a specific workspace, or --all to create sessions for every workspace in one shot. central-mcp tmux switch NAME / central-mcp zellij switch NAME attaches to cmcp-<NAME>, creating it if missing.
A third option — cmux on macOS — doesn't have its own CLI command: you run cmcp inside cmux.app yourself and ask the orchestrator to build the observation panes. See Running inside cmux below.
central-mcp up creates a tmux session central with:
Pane 0 — orchestrator (Claude Code / Codex / Gemini / opencode), launched in
~/.central-mcpso it picks up the hub'sCLAUDE.md/AGENTS.md.Panes 1…N — one per registered project, each streaming that project's dispatch activity live via
central-mcp watch <project>. Every dispatch's prompt, output, exit code, and duration scrolls past in real time.
Windows are named cmcp-<N> with the first window picking up a -hub suffix (cmcp-1-hub) when it holds the orchestrator — so you can tell at a glance which window to jump to. Cycle panes with Ctrl+b n / Ctrl+b <digit>. When the registry has more projects than fit in one window, extra windows (cmcp-2, cmcp-3, …) are added automatically. --max-panes N sets a per-window cap; without it, central-mcp reads the current terminal's size and picks how many panes fit above the readability floor (~70 cols × 15 rows per pane — tuned so a 13–15" laptop full-screen lands on 2 column slices).
Orchestrator layout: the first window puts the orchestrator pane in a full-height left column sized to match one project column. So orch + 1 project reproduces a 50/50 split, orch + 3 projects yields four equal columns (orch + 3 projects in a single row), and orch + 9 projects gives orch a 1/6 column with 2 × 5 project grid on the right.
central-mcp tmux # active workspace → create if missing, then attach
central-mcp tmux --workspace work # target the "work" workspace session
central-mcp tmux --all # create/attach sessions for every workspace
central-mcp tmux switch work # jump to cmcp-work (create if missing)
central-mcp tmux --permission-mode auto # claude-only; classifier-reviewed orchestrator
central-mcp tmux --permission-mode restricted # orchestrator surfaces approval prompts
central-mcp tmux --no-orchestrator # watch panes only (no orchestrator)
central-mcp tmux --max-panes 6
central-mcp up # create the session but don't attach (scripted flows)
central-mcp down # tear down all cmcp-* sessionsThe hub window (cmcp-1-hub) uses tmux's main-vertical layout: the orchestrator pane sits on the left taking two cells' worth of space, and project panes stack on the right. So the hub holds panes_per_window − 1 panes (default 3 — orchestrator + 2 projects), and overflow windows get the full panes_per_window projects each. Every pane carries its role name on its top border, and the orchestrator border is highlighted in bold yellow so you can spot it at a glance.
Kill with central-mcp down — the MCP dispatch path never depends on this layer, so tearing it down doesn't affect in-flight dispatches. The watch command is a read-only tail of ~/.central-mcp/logs/<project>/dispatch.jsonl; you can also run it standalone in any terminal.
" to run, to exit" in a watch pane
If a zellij watch pane shows <ENTER> to run, <Ctrl-c> to exit instead of streaming dispatch events, the underlying central-mcp watch <project> child has died or never started. This is zellij's built-in safety net — it holds the pane open (preserving scrollback) and waits for explicit user action instead of respawning or dropping to a shell. Don't press ENTER: the pane is disconnected from its original command at this point, so a manual re-run here won't pipe back into central-mcp. Instead, rebuild the session: cmcp zellij (automatic teardown + rebuild — one command). Every pane respawns with a fresh watch child.
Upgrading while an observation session is attached
Only matters if you use the observation layer. Every cmcp tmux / cmcp zellij invocation unconditionally tears down the prior observation session (if any) and rebuilds at the current terminal's size before attaching, so you always end up with fresh panes carrying the newly-installed binary. central-mcp upgrade additionally tears down the observation session before replacing the binary, so upgrading while already attached is covered too.
Trade-off: if two terminals are simultaneously attached to the same session and one runs cmcp tmux, the other disconnects. In exchange, "stale session vs new binary" isn't something you ever have to think about.
Running inside cmux
macOS only. cmux.app is a native GUI terminal designed so that agents manage their own panes. The workflow:
Launch cmux.app.
In a cmux pane, run
cmcp— the orchestrator (claude / codex / gemini) starts inside cmux and inheritsCMUX_WORKSPACE_ID.Ask the orchestrator to turn on observation mode, e.g. "turn on observation mode".
The orchestrator reads ~/.central-mcp/AGENTS.md on launch — which includes a terminal-size-aware recipe for this workflow — and uses its Bash tool to chain cmux new-split, cmux send, and cmux send-key per project. That recipe deliberately snaps each workspace to halving-safe balanced grids (2×2, 2×4, 4×4, etc.) rather than asking cmux to fake clean thirds from repeated 50/50 splits. Workspace naming mirrors tmux / zellij's window convention: the orchestrator's own workspace is renamed to cmcp-hub, and observation panes go into dedicated workspaces named cmcp-watch-1, cmcp-watch-2, … (one per terminal-size-derived grid chunk). cmux lets you tab between them from its sidebar.
No central-mcp cmux subcommand exists: central-mcp itself stays out of the cmux socket, the agent does the work. If pane setup fails partway, the orchestrator reports which projects succeeded and you can ask it to retry the missing ones.
Workspaces
Workspaces let you group projects into named sets and switch between them without editing the registry manually.
# Create and populate a workspace
central-mcp workspace new work
central-mcp workspace add api-server --workspace work
central-mcp workspace add frontend --workspace work
# Switch the active workspace
central-mcp workspace use work
# Inspect
central-mcp workspace list # shows all workspaces with project counts and active marker
central-mcp workspace current # prints "work"Projects not assigned to any named workspace fall back to the built-in default workspace. central-mcp workspace list shows that count too.
Session naming: each workspace gets its own multiplexer session — cmcp-default, cmcp-work, etc. The old central session name is kept as a backward-compat alias and is cleaned up by central-mcp down.
Observation with workspaces:
central-mcp tmux # active workspace only
central-mcp tmux --workspace work # specific workspace
central-mcp tmux --all # one session per workspace simultaneously
central-mcp tmux switch work # jump straight to cmcp-workWorkspace state is stored inside ~/.central-mcp/registry.yaml (current_workspace field) — no separate config file needed.
Registry resolution
Three-level cascade:
$CENTRAL_MCP_REGISTRY(explicit override)./registry.yamlin cwd (per-project override)$HOME/.central-mcp/registry.yaml(global default)
The registry is per-user state — never commit it.
Changing the orchestrator
central-mcp run --pick # re-run picker, save new choice
central-mcp run --agent codex # one-off override
$EDITOR ~/.central-mcp/config.tomlEnvironment variables
CENTRAL_MCP_HOME— user-state dir (default:~/.central-mcp)CENTRAL_MCP_REGISTRY— registry path override
Development
uv tool install --editable .
uv run --group dev pytest # 141 unit tests (fast, no real CLIs)
uv run --group dev pytest -m live # 20 live tests — shell out to real agent binaries
# (claude/codex/gemini/droid); each case skips
# cleanly if that binary isn't on PATHLicense
MIT.
Available Tools
20 toolsadd_projectA
Append a project to registry.yaml.
Registration is immediate. The agent is not spawned until the next
dispatch call. If the agent is codex, also adds a trusted-
directory entry to ~/.codex/config.toml so codex exec doesn't
refuse to run in that path.
language (optional): preferred response language for dispatches (e.g. "Korean", "ko", "Français", "fr"). When set, every future dispatch prepends "Respond to the user in ." to the prompt. Omit or leave empty for the agent's own default (English).
workspace (optional): if given, also add the project to this workspace.
Inputs: name (required), path (required), tags, agent, +3 more. Returns: object
cancel_dispatchA
Abort a running background dispatch. No-op if already finished.
Sets a cancel flag so _run_bg stops before the next fallback
attempt, then terminates the current subprocess. The background
thread finalizes the status to "cancelled".
Inputs: dispatch_id (required). Returns: object
check_dispatchA
Poll a background dispatch started by dispatch_background.
Returns {status: "running", elapsed_sec} while the subprocess is
alive, or the full result (same shape as dispatch_query's return
value) once it has exited.
Inputs: dispatch_id (required). Returns: object
dispatchA
Dispatch a prompt to a project or workspace. NON-BLOCKING.
name: project name, or @workspace to fan-out to all projects in that workspace. When a workspace is targeted, each member project is dispatched independently and a list of dispatch_ids is returned.
Spawns a one-shot subprocess (e.g. claude -p "..." --continue) in the
project's cwd and returns immediately with a dispatch_id (<100ms).
agent (optional): override the project's registered agent for this one dispatch only. Useful for e.g. sending a design-heavy task to a different agent without mutating the registry. Registry is unchanged.
fallback (optional): list of agent names to try in order if the
primary agent exits non-zero (e.g. token/rate limit, crash). If omitted,
the project's saved fallback from the registry is used. Pass an empty
list [] to explicitly disable fallback for this dispatch.
permission_mode controls how the agent handles permission prompts:
"bypass" — skip all prompts (default for new projects)
"auto" — claude-only; classifier-reviewed actions (Sonnet/Opus 4.6 only)
"restricted" — no skip flag; agent may fail on operations needing approval
None (default): use the project's saved mode, or "bypass" for new projects. The resolved value is saved to the registry for future dispatches.
session_id (optional): one-shot override for conversation resumption.
Given → resume that specific session (agent-specific flag: claude
-r <uuid>, codexresume <id>, droid-s <uuid>, opencode-s <uuid>, gemini--resume <index>). After this dispatch the agent's own "resume latest" mechanism picks up the just-used session, so subsequent default dispatches continue from it without restating the id.None (default): use the project's saved
session_idif any (persistent pin), otherwise fall back to the agent's "resume latest" flag. Droid has no headless "resume latest", so absence of a session_id means a fresh session on every droid dispatch.
language (optional): one-shot override for the response language.
A non-empty string (e.g. "Korean", "ko", "Français", "fr") → prepend a "Respond to the user in ." directive to the prompt.
"" (empty string) → suppress the project's saved language for this call (fall back to agent default, usually English) without mutating the registry.
None (default) → use the project's saved
language, set viaupdate_project(language=...). If unset, no directive is added.
Inputs: name (required), prompt (required), agent, resume, +5 more. Returns: object
dispatch_historyA
Return the last N completed/failed/cancelled dispatches for one project.
Reads ~/.central-mcp/logs/<project>/dispatch.jsonl and extracts
terminal events (merged with their matching start so each record
carries both the prompt and the outcome). For a cross-project
portfolio summary, use orchestration_history instead.
Inputs: name (required), n. Returns: object
get_user_preferencesA
Return the current content of ~/.central-mcp/user.md and the available preference sections.
The file holds only user-authored rules — there is no scaffolded
template, so an empty content means "no preferences set yet". The
response also carries available_sections (valid section values
for update_user_preferences) and examples (a hint of what the
user might want to set, surfaced when the user asks what's
configurable). Call this before update_user_preferences so you
can merge new rules with anything already saved.
Inputs: no named parameters. Returns: object
list_dispatchesA
List active and recently completed background dispatches,
including those started by other central-mcp processes (shared
state via ~/.central-mcp/dispatches.db).
status (optional): filter to one of running / complete /
error / timeout / cancelled, or the alias failed —
anything that ended badly (error, timeout, or complete with
ok=false; cancelled is deliberate and excluded).
since (optional): ISO 8601 timestamp; only dispatches whose
finished_at is strictly later are returned (still-running rows
are unaffected by this filter).
Together these back the resident-agent failure watch without
central-mcp holding subscriber state: call
list_dispatches(status="failed", since=<watermark>), alert on
whatever comes back, and advance your watermark to the max
finished_at you saw. The strict-greater-than filter means an
unchanged watermark never re-alerts the same failure.
Inputs: since, status. Returns: Generic wrapper for non-object return types.
list_projectsA
List registered projects. Defaults to the current workspace.
workspace:
None (default) → projects in the current workspace (
CMCP_WORKSPACEenv >config.toml [user].last_workspace>"default"). This matches the orchestrator's "what am I working on right now" expectation."__all__"(or"*") → every registered project across all workspacesany other name → that workspace's members
Inputs: workspace. Returns: Generic wrapper for non-object return types.
list_project_sessionsA
List resumable agent conversation sessions for one project.
Queries the project's agent for sessions saved in its own store
scoped to the project's cwd (filesystem scan for claude/codex/droid,
subprocess call for gemini/opencode). Returns at most limit
sessions sorted by most-recently-modified.
Each session dict carries id, optional title, optional bounded
preview, optional created / modified (ISO 8601), and optional
turns. preview is a short best-effort snippet from the session
contents (often the first recognizable user message, or a backend's
own title-like summary) so callers can distinguish threads without
resuming them. Use the returned id with dispatch(session_id=...)
to resume a specific thread as a one-shot — the agent's own
resume-latest mechanism picks the just-used session up for
subsequent default dispatches, so the id rarely needs to be
restated.
pinned echoes the project's currently saved session_id (if any)
so the orchestrator can mark it in UI.
Inputs: name (required), limit. Returns: object
orchestration_historyA
Portfolio-wide snapshot: in-flight dispatches + recent milestones + per-project stats.
Answers "how is everything going?" without per-project polling. Pulls:
in_flight: currently running dispatches (from memory)recent: last N timeline milestones (dispatched/complete/ error/cancelled) across all projects, newest firstper_project: counts of succeeded/failed/in-flight per project withinwindow_minutes(or all-time if not given)registered_projects: registry snapshot for context
workspace (optional): when given, filters recent milestones, per-project stats, and in-flight dispatches to only projects in that workspace.
include_archives (optional): when True, attach archived_summaries
— one compact aggregate per rotated timeline file — so callers get
a window onto long-past activity without raw records bloating context.
Live timeline.jsonl is always included.
Inputs: n, workspace, window_minutes, include_archives. Returns: object
portfolio_digestA
Pre-rendered portfolio summary for push delivery — paste
digest_markdown VERBATIM; do not re-summarize it.
Built for the resident-agent digest loop (a cron that forwards the
portfolio state to chat every morning), and equally usable by a
terminal orchestrator when the user asks for a daily/weekly recap.
The rendering is fixed server-side for the same reason
token_usage.summary_markdown is: an LLM re-composing the report
daily makes every day look different, and omissions are invisible.
Data spine is the pulse, so — unlike orchestration_history —
work that never went through central-mcp (direct commits,
interactive sessions) is counted. Sections:
active: projects with activity inside the window (commits, dispatch outcomes, in-flight count, uncommitted files)warnings: failed dispatches in the window, dispatches stuck inrunningfor hours (report as unfinished, never as live), and quiet projects with uncommitted work sitting in themquiet: everything else, longest-idle firstquota: compact per-agent subscription windows (wheninclude_quota)
workspace: same semantics as list_projects — None for the
current workspace, a name, or "__all__" for everything.
since_hours: activity window (24 daily; 168 weekly).
quiet_days: idle threshold for the uncommitted-work warning.
Nothing is stored; every call recomputes from source. Scheduling
and alert watermarks belong to the caller (list_dispatches with
status="failed" + since covers the alert half).
Inputs: workspace, quiet_days, since_hours, include_quota. Returns: object
project_noteA
Record what was done / what was left / what comes next for a project.
This is the durable memory a return briefing is built from. project_pulse
reads the repository and can tell anyone what is true; only you can
record what was meant — why an approach was abandoned, what is half
finished, what should happen next. None of that is recoverable from git
later, so it is lost unless it is written down now.
When to call it — this matters more than the arguments. Call it at the end of any stretch of real work in a registered project, whether or not that work came through central-mcp. A session someone opened directly in the repo is the most common case and the one most likely to be forgotten. Also call it when you learn something that changes the plan, and especially when you abandon an approach: "tried X, it fails because Y" leaves no commit, no diff, no trace at all, and is the single most valuable thing this file can hold.
Do not call it for trivia (a typo fix, a question answered) — an over-full ledger gets skimmed, which is the same as empty.
Arguments:
note — free text: what happened, what was left, what was learned.
name — registered project name. Omit if passing cwd.
cwd — a path inside the project; resolved to whichever project
owns it. Use this when you know where you are but not
what it is registered as.
next_step — one line: what should happen next. A briefing offers this
back for confirmation, so write it as an instruction to a
future reader, not a note to yourself.
source — "agent" when you are recording your own work (default),
"user" when you are writing down what the human just told
you. Keep these honest: the ledger's whole value is that a
reader can tell a first-hand record from a relayed one.
Inputs: note (required), cwd, name, source, +1 more. Returns: object
project_pulseA
What actually happened in a project, where it stands, what's live.
Use this when the user returns to a project after time away, asks
"what's the state of X?", or before dispatching into a project you
haven't touched this session. Unlike dispatch_history /
orchestration_history — which only know about work that went
through central-mcp — a pulse reads the repository itself, so
direct commits, interactive agent sessions, and manual edits show up
too.
Sections (each degrades independently, with a reason when
unavailable — never assume a missing section means "nothing
happened"):
git: branch, upstream ahead/behind, working-tree dirt with a bounded file sample, and the lastcommitscommits.dispatches: in-flight work, the lasthistoryoutcomes with prompts and previews, and all-time success/failure counts.staleholds rows still marked running after hours — a crashed or restarted server never wrote their terminal state, so report them as unfinished, not as live work.sessions: resumable agent conversations, when the project's agent has a session reader.pull_requests: open PRs viagh. The only network call here — passinclude_pr=Falsewhen sweeping many projects.
Nothing is stored: every call recomputes from source. Synthesize the result into a short narrative ("since your last visit … currently … next …") rather than reciting the fields back to the user.
Inputs: name (required), commits, history, include_pr. Returns: object
project_statusA
Return the registry entry for one project.
This is metadata only — the working directory, adapter, description, and tags. Dispatch work via dispatch_query to actually hit the agent.
Inputs: name (required). Returns: object
remove_projectC
Remove a project from registry.yaml.
Inputs: name (required). Returns: object
reorder_projectsA
Reorder the registry's projects list.
order is a sequence of project names; those names move to the
front of the registry in the given order. By default any project
not named in order keeps its original relative position after
the reordered prefix, so a partial reorder is always safe (no need
to enumerate every project). Pass strict=True to require
order to list every registered project exactly once.
Raises an error for unknown names, duplicates, or (in strict mode)
missing ones. The reorder persists to registry.yaml immediately,
but panes in an already-running cmcp tmux / cmcp zellij session
don't rearrange live — rerun the multiplexer command to see the
new layout (auto-teardown since 0.6.8 makes this a one-step flow).
Inputs: order (required), strict. Returns: object
tail_dispatchA
Read what a dispatch has printed so far, without waiting for it to finish.
check_dispatch returns output only after the agent exits. Use this
while a dispatch is still running — to answer "what is it doing right
now?", or to look closer when output.state is quiet.
Arguments:
dispatch_id — the id dispatch returned.
since — the next_since value from your previous call, to get
only newer lines. Omit it on the first call. A plain
ISO 8601 timestamp is accepted too.
max_lines — most lines to return (default 50). When more are new,
you get the newest and skipped counts the rest.
Returns lines (oldest first; each has ts, stream, agent, text),
skipped, next_since, the dispatch status, and output:
state streaming | quiet | no_output_yet | exit_only last_output_age_sec seconds since the newest line output_lines lines emitted so far
Read output.state before you report on a silent dispatch:
exit_only— this agent prints only when it exits (claude does). No lines is its normal state. Do not report it as stuck.quiet— the agent printed before and has printed nothing for 15 minutes. It may be stuck. Tell the user; do not cancel on your own.no_output_yet— nothing printed so far. Report the elapsed time.
Lines are raw agent output (often JSON events) — summarize them for
the user; do not paste them. Once status is no longer running,
call check_dispatch for the final result.
Inputs: dispatch_id (required), since, max_lines. Returns: object
token_usageA
Portfolio-wide token-usage aggregation (SQL over tokens.db) plus
a normalized per-agent subscription quota snapshot.
Separated from orchestration_history so token monitoring can evolve
independently of event/dispatch history (and eventually power a live
token pane). Reads are windowed by the user's configured timezone.
period: today | week | month | all
project: restrict to one project name (mutually exclusive with
workspace; if both are given, project wins)
workspace: restrict to projects in a workspace (via registry)
group_by: project | agent | source — how breakdown is keyed
include_quota: include per-agent subscription window utilization
(default True). Cached 60s in-process; opt out for fast bulk polling.
include_summary: include a pre-rendered markdown HUD
(summary_markdown) the orchestrator can surface verbatim
(default True). Uses Unicode block bars, emoji color markers
(🟢 < 50%, 🟡 50–89%, 🔴 ≥ 90%), and fixed-width alignment
inside a fenced code block. Disable to save tokens when you
only need the raw structured data.
Returns: { "ok": True, "period": "today", "window": {"start": ISO, "end": ISO} | {"start": null, "end": null}, "group_by": "project", "breakdown": { key: {dispatch, orchestrator, total, input, output} }, # When group_by="project", # tokens that aren't tied to # any registered project # (orchestrator-session usage) # are bucketed under the # special key "ORCHESTRATOR", # always emitted first in the # breakdown. "total": {dispatch, orchestrator, total, input, output}, "quota": { # only when include_quota=True "claude": {"mode": "pro", "five_hour": {"used_pct", "resets_in"}, "seven_day": {"used_pct", "resets_in"}}, "codex": {"mode": "chatgpt", "primary": {...}, "secondary": {...}}, "gemini": {"mode": "auth_only", "auth_type": ..., "note": ...}, "fetched_at": ISO, "cached": bool, }, "summary_markdown": "Token Usage — ...\n```text\n..." # only when include_summary=True # — pre-rendered HUD; surface # verbatim, do not re-format. }
Inputs: period, project, group_by, workspace, +2 more. Returns: object
update_projectA
Update an existing project's fields. Omitted args stay unchanged.
Use this to permanently change a project's primary agent, edit its
description/tags, flip its permission_mode preference, set a
fallback chain of agents to try when the primary fails (e.g. token
limits hit), pin a specific session_id, or set a preferred
response language for dispatches.
language behavior:
A non-empty string (e.g. "Korean", "ko", "Français", "fr") → every future dispatch prepends "Respond to the user in ." to the prompt. One-shot
dispatch(language="...")still overrides.""(empty string) → clear the saved language; dispatches fall back to the agent's own default (English).None(omitted) → leave the saved language untouched.
session_id behavior:
A non-empty string → all future dispatches without an explicit
session_idwill resume that session (useful for droid, which has no headless "resume latest", and for guarding other agents against ambient-drift when interactive sessions share the cwd).""(empty string) → clear the pin, returning to the agent's default resume-latest behavior.None(omitted) → leave the pin untouched.
Agent names in agent and fallback are validated. permission_mode
must be one of "bypass", "auto", "restricted". If any value is
invalid the registry is not touched.
Inputs: name (required), tags, agent, fallback, +4 more. Returns: object
update_user_preferencesA
Persist a user preference to ~/.central-mcp/user.md.
Call this when the user expresses a PERSISTENT preference — reporting style, language, routing hints, or process rules. Applied every future session. NOT for one-off turn instructions; those need no persistence.
section — one of: "Reporting style" how to format and present responses "Routing hints" which agents/projects to prefer for task types "Process management rules" concurrency or approval constraints "Other preferences" anything else
content — new full text for that section (replaces its existing content; other sections are untouched). Plain language, bullet points recommended: "- Switch to Korean for all responses." "- Prefer claude for architecture.\n- Use codex for shell scripting."
Tip: call get_user_preferences() first so you can merge old and new content.
Inputs: content (required), section (required). Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 20 tools
Most tools have clearly distinct purposes (dispatch vs check_dispatch vs tail_dispatch vs cancel_dispatch are well separated), and project_status vs project_pulse is explicitly contrasted. However, the read-side portfolio tools overlap: portfolio_digest, orchestration_history, dispatch_history, and list_dispatches all report on dispatch/activity state and could be misselected without careful reading of the long descriptions.
There is a mix of conventions: verb_noun tools (list_projects, update_project, cancel_dispatch, add_project) alongside noun-only tools (project_status, project_pulse, token_usage, portfolio_digest, orchestration_history) and bare 'dispatch'. The names remain readable, but the inconsistent verb/noun framing means the pattern isn't predictable.
20 tools is on the heavy side, but the domain is broad (registry CRUD, dispatch lifecycle, sessions, user preferences, and portfolio/token analytics), so most tools earn their place. A few analytics/read tools could plausibly be consolidated, keeping it just short of ideal.
Coverage is strong: full registry CRUD (list/get/add/update/remove/reorder), the full dispatch lifecycle (dispatch/check/tail/cancel/list/history), session listing, preference read/write, and multiple analytics views. Minor gaps exist around per-dispatch detail retrieval and note management, but core workflows have no dead ends.
Maintenance
Related MCP Connectors
Command center for developers coordinating AI coding agents across projects.
Real-time chat hub for AI agents — Claude Code, Cursor, Cline, Codex over MCP or REST.
Human-agent interface for projects: you prioritize and decide, your AI agents execute. Over MCP.
Control plane for autonomous software labor. Agents claim objectives over MCP with audit trail.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAn MCP orchestration server that coordinates multiple AI coding agents using Copilot CLI for parallel task execution with dependency management, file locking, and observability.1ISC
- AlicenseNot gradedqualityBmaintenanceA vendor-neutral MCP server that enables coding agents to delegate tasks, share context, and work as a team through a shared blackboard and task queue.2 npmMIT
- AlicenseAqualityDmaintenanceAn MCP server that enables Claude to orchestrate multiple autonomous Claude Code agents working in parallel across different projects, with tools to dispatch, monitor, and manage their progress.654 npm1MIT
- AlicenseNot gradedqualityDmaintenanceA shared MCP hub that enables multiple coding-agent CLIs to register, discover, and communicate asynchronously via a standalone daemon. It provides MCP tools for agent registration, session management, non-blocking messaging, and cursor-based event reading.3 npm1MIT