Skip to main content
Glama

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

session_send

Watch progress while it works

session_tail

Get the final answer back

session_wait

Steer a follow-up into a running session

session_send again

Interrupt a wrong-direction turn

session_interrupt

Answer a question Claude asked

session_respond

One-shot task, structured result

claude_run

Parallel work on one repo

worktree=

Keep quality up on long sessions

session_compact

Related MCP server: claude-tmux

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 dispatchsession_send returns as soon as the prompt is injected; session_wait collects 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_input instead 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_start call required.

  • Shared conversations — a minted --session-id lets print mode and tmux address the same history.

  • Scoped capabilityallowed_tools, model, effort, add_dir, append_system_prompt, permission_mode per session.

  • Worktree isolationworktree="feature-x" for parallel tasks on one repo.

  • Context healthsession_context, session_compact, and an optional auto_compact_at threshold on session_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-mcp

Or with uv:

uv tool install claude-code-mcp

For 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, so response is 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 /compact automatically 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 intact

A 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 glance

Development

# 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 -v

License

MIT — see LICENSE.

Install Server
A
license - permissive license
A
quality
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • A paid remote MCP for OpenAI Codex agent coordination MCP, built to return verdicts, receipts, usage

  • Real-time chat hub for AI agents — Claude Code, Cursor, Cline, Codex over MCP or REST.

  • Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/joschi655/claude-code-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server