claude-code-mcp
Uses tmux as the terminal multiplexer to keep Claude Code sessions alive, allowing injection of commands and reading output via tmux panes.
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., "@claude-code-mcp add error handling for the database connection"
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.
claude-code-mcp
It sounds dumb... but its literally that. Using Claude Code through an MCP server. Its meant for orchestrator agents (like Hermes), giving it fine-grained control over interactive Claude Code sessions running inside tmux. Hermes has a built in Claude Code Skill, but let's be honest, it's huge and takes an enormous amount of the context window...
The core value: a long-running Claude Code REPL stays alive in a tmux pane, and
your orchestrator can steer it at any point — send a task without blocking,
watch progress, inject a follow-up mid-run, interrupt a wrong turn, or collect
the final answer. Way better than using it through claude -p.
The server replaces the whole tmux runbook an orchestrator would otherwise have to carry in its prompt: launch dialogs, readiness gating, idle detection, response extraction. Point Hermes at it and delete the skill file.
Why an orchestrator needs this
Need | Tool |
Send a task without blocking on it |
|
Watch progress while it works |
|
Get the final answer back |
|
Steer a follow-up into a running session |
|
Interrupt a wrong-direction turn |
|
Answer a question Claude asked |
|
One-shot task, structured result |
|
Parallel work on one repo |
|
Keep quality up on long sessions |
|
Related MCP server: agent-mux
The core loop
session_send("work", "implement the auth module", working_dir="/proj")
# → returns immediately: {"dispatched": true, "created": true, ...}
session_tail("work") # progress, any time
session_send("work", "use JWT, not sessions") # steer mid-run
session_wait("work", timeout=300) # → {"response": "...", "timed_out": false}session_wait is resumable. If it times out, nothing is lost — the pending
dispatch survives and the next call keeps waiting:
r = session_wait("work", timeout=300)
while r["timed_out"]:
r = session_wait("work", timeout=300)Why not claude -p?
claude -p exits after one response. There is no channel to inject a
follow-up — every turn spawns a fresh process and loses accumulated context.
This server keeps the interactive REPL alive in a tmux pane, so prompts can be injected at any time, history accumulates inside the running process, and mid-run interrupts work as expected.
Print mode is still available via claude_run for one-shot work — and because
sessions are minted a --session-id up front, a print-mode call can resume a
tmux session's conversation. Start cheap, escalate to interactive.
Features
Non-blocking dispatch —
session_sendreturns as soon as the prompt is injected;session_waitcollects the result whenever you want it.Steer mid-session — send again while Claude is working. Input is queued and the eventual result still spans the whole run.
Launch dialogs handled — workspace trust, the bypass-permissions warning (whose default is "No, exit"), and the effort selector are answered automatically. Anything unrecognised is surfaced as
awaiting_inputinstead of being blind-Entered.Real interrupt — sends Escape, Claude Code's own interrupt, and verifies it took. Ctrl-C is only a fallback (a double Ctrl-C exits the process).
Send & auto-create — no separate
session_startcall required.Shared conversations — a minted
--session-idlets print mode and tmux address the same history.Scoped capability —
allowed_tools,model,effort,add_dir,append_system_prompt,permission_modeper session.Worktree isolation —
worktree="feature-x"for parallel tasks on one repo.Context health —
session_context,session_compact, and an optionalauto_compact_atthreshold onsession_wait.Token-efficient — you get the extracted answer, not the pane dump.
Pure stdlib + mcp SDK — no heavy dependencies.
Requirements
Tool | Version |
Python | ≥ 3.11 |
tmux | ≥ 3.4 |
Claude Code | ≥ 2.0 |
Installation
pip install claude-code-mcpOr with uv:
uv tool install claude-code-mcpFor development:
git clone https://github.com/joschi655/claude-code-mcp
cd claude-code-mcp
pip install -e ".[dev]"MCP configuration
Claude Desktop / Claude Code
{
"mcpServers": {
"claude-code-mcp": {
"command": "claude-code-mcp"
}
}
}With uvx (no install required)
{
"mcpServers": {
"claude-code-mcp": {
"command": "uvx",
"args": ["claude-code-mcp"]
}
}
}Hermes / custom MCP client
{
"mcpServers": {
"claude-code-mcp": {
"command": "python",
"args": ["-m", "claude_code_mcp"]
}
}
}Tools
session_send(name, prompt, ...)
Send a prompt and return immediately. Creates the session if it does not exist. Sending into a session that is already working is a supported steer.
{ "name": "work", "prompt": "implement feature X", "working_dir": "/proj" }Returns {dispatched, name, created, steered, state}.
Launch options (applied only when the session is created): working_dir,
permission_mode, model, effort, allowed_tools, disallowed_tools,
add_dir, append_system_prompt, worktree.
session_wait(name, timeout=300, auto_compact_at=None)
Block until the session finishes, then return the answer. This is the completion trigger — the result comes back as the tool result.
Returns {response, state, timed_out, baseline, elapsed_s, steers}.
timed_out: true— still working. Call again; the pending dispatch survives.baseline: "lost"— the server restarted since the prompt was sent, soresponseis a plain tail of the pane rather than an exact diff.question— present when the session stopped on a prompt.auto_compact_at=70— run/compactautomatically past that context usage.
session_tail(name, lines=40)
Last n lines of pane output, ANSI-stripped. Use this to check on a long task instead of assuming it is stuck.
session_interrupt(name)
Stop the current turn without killing the session. Sends Escape and verifies the session left the busy state; falls back to Ctrl-C only if that fails.
session_respond(name, choice)
Answer a question when state is awaiting_input. choice is an option
number ("1", "2") or a key: up, down, enter, escape. Read the
question from session_status first.
session_status(name) / session_list() / health()
{
"name": "work",
"tmux_alive": true,
"claude_alive": true,
"state": "busy",
"claude_session_id": "02d8d5c3-...",
"working_dir": "/proj",
"context_pct": null,
"pending": true,
"question": null
}state is one of missing, starting, busy, awaiting_input, idle.
session_start(name, ...)
Pre-create a session. Usually unnecessary — session_send does it — but useful
to fix launch options up front. A fresh session is minted a UUID so
claude_run can address the same conversation later.
session_compact(name, focus=None) / session_context(name)
Compress context, or read usage as a percentage. Output quality degrades above
roughly 70% context usage. session_context returns null when the TUI output
cannot be parsed — treat that as unknown, not zero.
session_stop(name) / session_destroy(name)
session_stop kills the tmux session but keeps the conversation, so it can be
resumed later — and so claude_run can address it without transcript
contention. session_destroy forgets it entirely.
claude_run(prompt, session_name=None, ...)
One-shot claude -p with structured output:
{
"result": "...",
"session_id": "75e2167f-...",
"num_turns": 3,
"total_cost_usd": 0.0787,
"duration_ms": 10276
}Pass session_name to resume a managed session's conversation. A live busy
session is refused — two writers corrupt the transcript. fork=True branches
to a new session ID that inherits history, avoiding contention entirely.
Sharing history between print mode and tmux
Sessions get a --session-id at launch, so a conversation is addressable
before it produces any output:
session_send("work", "Remember the codeword: BANANA42")
session_wait("work")
session_stop("work") # free the transcript
claude_run("What was the codeword?", session_name="work")
# → "BANANA42"
session_start("work") # back to interactive, history intactA running TUI holds its history in memory, so it will not display a print-mode
turn until restarted. session_stop first, or use fork=True.
Permissions
Sessions launch with --permission-mode bypassPermissions by default so
unattended runs are not blocked waiting for approval. The real safety control
is allowed_tools — scope each session to what the task actually needs:
session_send("review", "review the diff vs main",
working_dir="/proj", allowed_tools=["Read", "Bash(git *)"])Override per session with permission_mode: acceptEdits, auto,
bypassPermissions, manual, dontAsk, plan.
Parallel work
Independent sessions run concurrently. For several tasks against one repo, use worktrees so they don't collide:
session_send("backend", "fix the auth bug", working_dir="/proj", worktree="auth-fix")
session_send("frontend", "update the header", working_dir="/proj", worktree="header")
session_send("tests", "add API tests", working_dir="/proj", worktree="api-tests")
health() # all sessions and their states at a glanceDevelopment
# Unit tests (no tmux/claude required)
pytest tests/test_parser.py tests/test_session_logic.py -v
# Integration tests (requires tmux + claude, spends tokens)
CLAUDE_TMUX_INTEGRATION=1 pytest tests/test_integration.py -vLicense
MIT — see LICENSE.
Available Tools
15 toolsclaude_runA
Run a one-shot claude -p task and return structured JSON.
Best for work that needs no conversation: review a diff, answer a question, make one contained change. Cheaper and faster than a tmux session.
Pass session_name to resume a managed session's conversation, so one-shot and interactive work share history. A live, busy session is refused (two writers would corrupt the transcript); a live idle one is allowed but the running TUI will not show the turn until restarted. fork=True branches to a new session ID instead, avoiding both issues.
Returns {result, session_id, num_turns, total_cost_usd, duration_ms}.
Always set max_turns to bound cost.
Inputs: prompt (required), cwd, fork, model, +9 more.
healthA
System health check: binary availability + summary of all known sessions.
Returns tmux_available / claude_available (are the binaries on
PATH), session_count, and sessions (SessionInfo dicts).
Inputs: no named parameters.
session_compactA
Compress the session's context via /compact to recover headroom.
Optionally pass focus to bias what is retained, e.g. "the auth refactor". Output quality degrades above ~70% context usage, so compact before then.
Inputs: name (required), focus.
session_contextA
Run /context and report context usage as a percentage.
Returns {name, context_pct}. context_pct is null when the TUI
output cannot be parsed — treat that as unknown, not as zero.
Inputs: name (required).
session_destroyA
Kill the tmux session and remove its stored metadata.
Do this when a task is finished — tmux sessions outlive this server. Do not
use it to stop a slow run; use session_interrupt for that.
Inputs: name (required).
session_interruptA
Stop the current turn without killing the session.
Sends Escape (Claude Code's own interrupt), verifies the session left the
busy state, and only falls back to Ctrl-C if Escape did not take. Follow up
with session_send to redirect.
Inputs: name (required).
session_listA
List all managed sessions (metadata) plus any live tmux sessions.
Inputs: no named parameters.
session_respondA
Answer an on-screen prompt when state is awaiting_input.
choice is an option number ("1", "2", ...) or a navigation key: up,
down, enter, escape. Read the question first via session_status.
Launch dialogs (workspace trust, bypass-permissions, effort) are handled automatically — this is only for questions Claude itself asks.
Inputs: name (required), choice (required).
session_sendA
Send prompt to a session and return immediately (non-blocking).
Creates the session if it does not exist — no session_start needed. Call
session_wait to collect the answer, or session_tail to watch progress.
Sending while Claude is working is supported and is how you steer a run
mid-flight; the input is queued and the pending result still spans the whole
run. The returned steered field says which happened.
Launch options apply only when the session is created. Set working_dir on the first send.
Returns {dispatched, name, created, steered, state}.
Inputs: name (required), prompt (required), model, effort, +8 more.
session_set_claude_idA
Bind an existing Claude conversation ID to name for future --resume.
Only needed to adopt a session this server did not create — new sessions are assigned an ID automatically.
Inputs: name (required), claude_session_id (required).
session_startA
Pre-create a Claude Code session. Usually unnecessary — session_send
creates one on demand — but useful to fix launch options up front.
An existing tmux session called name is returned as-is.
A fresh session is minted a UUID (
--session-id) soclaude_runcan address the same conversation later; a stored or supplied claude_session_id triggers--resumeinstead.permission_mode: one of acceptEdits, auto, bypassPermissions, manual, dontAsk, plan. Defaults to
bypassPermissionsso unattended runs are not blocked by approval prompts — restrict with allowed_tools instead.worktree: run in an isolated git worktree at
.claude/worktrees/<name>.effort: low, medium, high, xhigh, max.
Launch options are stored and reused if the session is recreated.
Inputs: name (required), model, effort, add_dir, +7 more.
session_statusA
Return state info for one session.
state is one of: missing, starting, busy, awaiting_input,
idle. When it is awaiting_input, question holds the on-screen
question and its options. pending means a dispatched prompt has not
been collected by session_wait yet. context_pct is null unless
/context output happens to be on screen.
Inputs: name (required).
session_stopA
Kill the tmux session but keep the conversation.
Use this to free a session's transcript — so claude_run can address it
without contention — while keeping the ability to resume it later with
session_start. Use session_destroy to forget it entirely.
Inputs: name (required).
session_tailA
Peek at the last lines of pane output without blocking.
Use this to check on a long-running task instead of assuming it is stuck.
Returns {name, state, output}.
Inputs: name (required), lines.
session_waitA
Block until the session finishes its pending work, then return the answer.
This is the completion trigger: it returns Claude's final response as the tool result.
Resumable. If timeout (seconds, max 3600) elapses while Claude is
still working, this returns timed_out: true with the partial transcript
and keeps the pending dispatch — just call it again. Nothing is lost.
Set auto_compact_at (e.g. 70) to run /compact automatically when context
usage crosses that percentage after the turn completes.
Returns {response, state, timed_out, baseline, elapsed_s, steers}.
baseline: "lost" means this server restarted since the prompt was sent,
so response is a plain tail of the pane rather than an exact diff.
A question field appears when the session stopped on a prompt.
Inputs: name (required), timeout, auto_compact_at.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 15 tools
Most tools have clearly distinct purposes, but session_stop and session_destroy both kill the tmux session, differentiated only by keeping metadata. Also, session_status, session_context, and session_tail all read session state, though they target different aspects. Descriptions clarify the boundaries sufficiently.
The vast majority follow a consistent session_<verb> pattern (list, start, send, wait, tail, respond, interrupt, status, compact, destroy, stop). The claude_run tool deviates by using a different prefix, but it is still a clear, readable name that fits the server's purpose.
At 15 tools, it sits at the upper edge of the ideal range. Each tool covers a distinct aspect of session lifecycle or health, so the count feels justified rather than bloated. It is slightly heavy but not excessive for the domain.
The tool set covers the full session lifecycle: create, send, wait, tail, respond, interrupt, compact, stop, destroy, plus one-shot execution and health/context checks. There are no obvious missing operations that would leave an agent stuck.
Maintenance
Related MCP Connectors
Shared memory MCP server for Claude Code, Codex, Gemini CLI and Cursor. Cited, editable.
Real-time chat for AI agents. Claude Code, Cursor, Cline and Codex join channels over MCP.
Remote MCP server exposing your Node Command fleet (files, shell, processes, browser) to AI hosts.
A paid remote MCP for OpenAI Codex agent coordination MCP, built to return verdicts, receipts, usage
Related MCP Servers
- AlicenseAqualityDmaintenanceMCP server for orchestrating multiple Claude Code instances via tmux, enabling spawning, reading, sending, listing, and killing sessions.532 npm2MIT
- AlicenseNot gradedqualityDmaintenanceMCP server that manages interactive CLI agent pools using tmux, enabling creation, control, and communication with agents like Claude and Codex.7MIT
- AlicenseAqualityDmaintenanceAn MCP server that connects Claude Desktop to an interactive Claude Code session running in a tmux terminal.1MIT
- AlicenseBqualityBmaintenancePersistent tmux-backed MCP server that lets Claude Code control Codex CLI's interactive TUI, including slash commands and $imagegen. Run local shells, SSH, Docker, WSL, REPLs, and supported coding agents through durable PTY sessions.1912,090 npm6MIT