Wrap the local Claude Code CLI (claude) as an MCP server over stdio.
Any MCP client — Cursor, Claude Desktop, Hermes, your own agent — can spawn
Claude Code tasks, poll them, stream their output, and cancel them through six
plain tools.
The key idea is the async task model: claude_run returns immediately with
a task_id instead of blocking until Claude finishes. A long task (a multi-file
refactor, a test run, a build) keeps streaming in the background while your MCP
client stays responsive. You poll with claude_status, stream chunk-by-chunk
with claude_wait, and claude_cancel when you want to stop.
Forked from the MCP server inside
lark-channel-bridge, with all the Feishu / Lark messenger code stripped out. This package is the MCP server, nothing else.
npm install
npm run build
node bin/claude-code-mcp-bridge.mjs mcpOr, once published:
npx claude-code-mcp-bridge mcpThe claude CLI must be installed and on PATH (the adapter spawns
claude --version to check availability and claude -p ... --output-format stream-json to run tasks).
claude-code-mcp-bridge mcp [options]
--cwd <path> Default working directory when a caller omits one.
--cwd-root <path> Restrict task cwds to this root. Repeatable.
Defaults to ~/Projects.
Point your MCP client at the stdio server. Example (Claude Desktop /
Cursor mcpServers block):
{
"mcpServers": {
"claude-code": {
"command": "npx",
"args": ["claude-code-mcp-bridge", "mcp", "--cwd-root", "/Users/me/Projects"]
}
}
}| Tool | Signature | What it does |
|---|---|---|
claude_run |
(prompt, cwd?, model?, session_id?) |
Start a Claude task async. Returns a snapshot with task_id. |
claude_status |
(task_id) |
Snapshot: status, accumulated text, counters, in-flight tool. |
claude_wait |
(task_id, from_seq?, timeout_ms?) |
Block briefly for new events after from_seq; returns immediately on terminal state. |
claude_cancel |
(task_id) |
SIGTERM (then SIGKILL) a running task and mark it cancelled. |
claude_list |
() |
List all known tasks in this server (running and terminal). |
claude_forget |
(task_id) |
Drop a finished task from memory. No-op while running. |
-
claude_runprompt(string, required) — the prompt to send to Claude.cwd(string, optional) — working directory; defaults to--cwd, then the server's own cwd. Subject to the cwd-root whitelist (below).model(string, optional) — override the Claude model (e.g.claude-opus-4-8).session_id(string, optional) — resume a prior Claude session by its id (returned from a previous run). Resume is always by explicit id (--resume), never-c, so concurrent tasks sharing a cwd never cross-talk.
-
claude_wait—from_seq(default0) is an event cursor. Each event has a monotonicseq; pass the highestseqyou've seen back asfrom_seqon the next call to stream progress chunk-by-chunk.timeout_msdefaults to30000(clamped 100–120000).
run -> { task_id }
wait(task_id, from_seq=0) -> events [seq 0..n], snapshot
wait(task_id, from_seq=n) -> events [seq n+1..], snapshot
...repeat until snapshot.status != "running"...
--cwd-root (repeatable, default ~/Projects) restricts where tasks may run.
On every claude_run, the requested cwd is resolved with path.resolve (so
/root/../etc can't sneak out) and must equal, or sit under, one of the roots.
A cwd outside every root is rejected before Claude is ever spawned. Pass
multiple --cwd-root flags to allow several trees.
Task state lives entirely in memory, scoped to one stdio connection. When the server process exits, every task record is gone; a second client connection gets a fresh, empty registry. There is no cross-process or cross-restart visibility — this is a session-scoped scheduler, not a durable queue.
Anthropic ships an official claude-code MCP integration, but it follows a
synchronous request/response shape: the call blocks until Claude is done. That
is fine for short prompts and awkward for long ones — a 5-minute refactor pins
your client for 5 minutes.
This bridge is built around an async task model instead: claude_run
returns a task_id instantly and the work continues in the background. Your
client streams progress with claude_wait, checks in with claude_status,
runs several tasks concurrently, and cancels mid-flight — none of which blocks
the client. If you want fire-and-forget long-running Claude Code tasks behind
MCP, that's what this is for.
MIT