Skip to main content
Glama

clawborrator-mcp (channel_v1)

MCP server that connects each running Claude Code instance to a clawborrator hub over WebSocket. Designed to be invoked by Claude Code via .mcp.json; runs as both a long-lived stdio MCP server AND a short-lived hook spawn (selected by the --hook=<HookName> CLI flag).

Published as clawborrator-mcp on npm.

Status: production hub at next.clawborrator.com. Local dev uses ws://localhost:8787. Both supported.


Configuration

Set in your project's .mcp.json:

{
  "mcpServers": {
    "clawborrator": {
      "command": "npx",
      "args": ["-y", "clawborrator-mcp"],
      "env": {
        "CLAWBORRATOR_HUB_URL": "wss://next.clawborrator.com",
        "CLAWBORRATOR_TOKEN":   "ck_live_…"
      }
    }
  }
}

Env var

Required

Notes

CLAWBORRATOR_HUB_URL

yes

ws://… or wss://…; no trailing slash

CLAWBORRATOR_TOKEN

yes

Channel token (ck_live_…) minted via claw token mint --kind=channel

CLAWBORRATOR_REUSE_SESSION_ID

no

Opt-in: reconnect rebinds to a known session id rather than creating a fresh one

CLAWBORRATOR_LOG_LEVEL

no

debug, info, warn, error; default info

Get the snippet pre-filled with the right URL + token via the clawborrator-cli:

npx clawborrator-cli token mint --kind=channel --name=mbp --mcp-snippet --out .mcp.json

If you're running the desktop daemon (clawborrator-supervisor), it mints channel tokens server-side when it spawns managed Claude Code sessions for you — the .mcp.json ends up in the spawned project automatically.


Related MCP server: Claude Relay

Install as a Claude Code plugin

clawborrator is an official external Claude Code plugin. This repo ships .claude-plugin/plugin.json and a root .mcp.json, so once it is listed in a plugin marketplace it installs with:

/plugin install clawborrator@<marketplace>

The bundled .mcp.json resolves its config from environment variables instead of a committed token, so it carries no secret. You still have to supply the channel token yourself — a committed plugin cannot ship a per-user secret. Before the MCP server can connect to the hub, set in your environment:

Env var

Required

Default

CLAWBORRATOR_TOKEN

yes

none. Mint one with claw token mint --kind=channel.

CLAWBORRATOR_HUB_URL

no

wss://next.clawborrator.com. Self-hosters point this at their own hub.

Without CLAWBORRATOR_TOKEN set, the server starts but cannot authenticate, and the session never registers with the hub. This is the one manual step the plugin install cannot do for you.


What it does

Long-lived MCP path (default invocation):

  1. Reads env config; loads channel token.

  2. Opens WSS to <HUB_URL>/channel with Authorization: Bearer <CHANNEL_TOKEN>.

  3. Sends register with host / cwd / pid / version; receives welcome with sessionId + routingName.

  4. Writes <cwd>/.claude/clawborrator/runtime.json (mode 0600) so per-event hook spawns can find the active session.

  5. Maintains the WS with heartbeat ping/pong; reconnects with exponential backoff (1s/2s/5s/15s/30s/60s).

  6. Listens for hub-side messages: prompt (cross-session route), permission_response, peers_update, bye, error.

  7. Dispatches MCP tool calls (see below) over the same WS.

  8. On clean shutdown (SIGINT/SIGTERM/exit), deletes the sidecar.

Short-lived hook path (--hook=<HookName> flag):

  1. Reads JSON payload from stdin (Claude Code's hook protocol).

  2. Locates the active sidecar at .claude/clawborrator/runtime.json.

  3. Maps the hook name to a clawborrator event (e.g. PreToolUse → tail/PreToolUse, UserPromptSubmit → chat/prompt).

  4. POSTs to <HUB_URL>/api/channel/event with the channel token from the sidecar.

  5. Echoes stdin to stdout so Claude's hook chain stays intact.

  6. Exits cleanly even if the hub is unreachable — never breaks the operator's actual Claude flow.

Hooks are auto-installed on first MCP startup: clawborrator-mcp reconciles .claude/settings.json to add (or refresh) the entries that point at dist-hook/clawborrator-tail.mjs. No separate install step.


MCP tools exposed to Claude

Routed: targets a peer (your own session or another operator's session you have a share on) by routingName.

Tool

Purpose

reply({ chat_id, text })

Post a tagged final reply for a routed prompt (closes the round-trip when the source session is blocking on a reply).

reply_chunk({ chat_id, text, done })

Stream a reply progressively — the operator sees text growing live; close with done:true. Same correlation as reply.

list_peers()

Discover other CC sessions the operator has access to (own sessions + shared ones). Refused on agents published as isolated.

route_to_peer({ peer, prompt, mode })

Send one prompt to one peer. mode: 'ask' blocks for the reply; mode: 'tell' is fire-and-forget.

probe_peers({ prompt, peers? })

Fan out the same short question to many peers in parallel for discovery.

await_routed_prompt({ maxWaitMs })

Dequeue an inbound routed prompt for THIS session — used by agents that service requests from other sessions.

Cross-tenant — public agents owned by other operators:

Tool

Purpose

list_agents()

Discover public agents on the hub. Returns handle, name, tagline, online, mine, isolated flags.

dispatch_to_agent({ handle, prompt, mode })

Invoke a published agent by <owner>/<slug> handle. ask mode waits up to 15 min for the reply; tell mode is fire-and-forget.

File exchange:

Tool

Purpose

attach_file({ path, targetSessionId?, publish? })

Upload a file from disk to the session (or to a peer's session you have a share on). Returns fileId. publish: true makes it a standing downloadable for everyone who can reach the agent (no expiry, idempotent per content); shared documents only.

read_file({ fileId })

Fetch a session-attached file inline (text-mime; under 1 MB). Reply-clone makes peer-uploaded files visible to the recipient.

download_to_path({ fileId, path })

Fetch a larger or binary file to disk. Returns the absolute path written.

The hub correlates reply / reply_chunk to their originating route_to_peer / dispatch_to_agent by chatId; the source session's CC unblocks when the matching reply lands. 15-minute timeout caps — see hub_v1/server/src/services/agents.ts and services/op-routes.ts.

For await_routed_prompt to actually fire — i.e., for an agent to service incoming requests — its CLAUDE.md needs a line telling Claude to call it at the start of each turn. Without that note, Claude won't know to consult the inbox. See hub_v1/docs/3-AGENT-SETUP.md for the dispatcher-pattern setup.


Hook coverage

Maps each Claude Code hook to a hub event. The hook script is dist-hook/clawborrator-tail.mjs; auto-installed on first MCP startup (no separate install step).

Hook

Hub event

Notes

UserPromptSubmit

chat/prompt (source='cli')

Operator typing into the local CC terminal.

PreToolUse

tail/PreToolUse (+ chat/assistant_text per text block from the transcript)

The tail captures pre-reply narration too.

PostToolUse

tail/PostToolUse

PostToolUseFailure

tail/PostToolUseFailure

Stop

tail/Stop (+ chat/reply if assistant_text present)

Turn-end signal.

Notification

tail/Notification

CC user notifications (idle / permission).

TaskCreated / TaskCompleted

tail/TaskCreated / tail/TaskCompleted

Carries task_id, task_subject, task_description.

SubagentStart / SubagentStop

tail/SubagentStart / tail/SubagentStop

SubagentStop carries last_assistant_message recap.

SessionStart / SessionEnd are intentionally not hooked by this MCP. The hook spawn had a fundamental race — the sidecar isn't written yet at SessionStart, and is already gone by SessionEnd — so lifecycle is now emitted server-side from the /channel WS welcome / close transitions (hub_v1/server/src/ws/channel.ts). Hub-authoritative, captures actual channel liveness, no hook timing involved.

The tail reads the CC transcript file directly to enrich PreToolUse with the assistant's pre-reply text (which CC doesn't put on the hook payload directly). See transcript.ts for the walker.


Local dev (linked to a sibling hub_v1 checkout)

npm install
npm run build
npm link

# verify the binary is on PATH
clawborrator-mcp --hook=PreToolUse < /dev/null   # exits cleanly with no sidecar

When claude runs in a folder whose .mcp.json references clawborrator-mcp, npm/npx resolves it to your linked build.

To publish a new release:

npm version patch                # bumps package.json + creates git tag
npm publish
git push --follow-tags

The CLI's claw token mint --mcp-snippet autogenerates an .mcp.json snippet pointing at the published version.

Available Tools

12 tools
ask_questionA

Ask the REMOTE operator a multiple-choice question through orchard-chat — does NOT block the local TUI. Prefer this over the built-in AskUserQuestion tool whenever the session is being driven remotely (operator messages arrive as tags), since AskUserQuestion opens a synchronous picker in the local terminal that no one is watching. Same input shape as AskUserQuestion: a questions[] array, each with question, optional header, optional multiSelect, and 2-4 options[] (each {label, description?}). Renders as a clickable card on the operator's orchard-chat. Blocks (max 15min) until the operator picks an option; returns the chosen label as the tool result. If the operator types a free-form chat message INSTEAD of clicking, that message returns the user to a normal turn — don't treat it as the answer; it's a redirect. Picking from a multi-question array fires once per question.

Inputs: questions (required).

attach_fileA

Upload a file from your project as a chat attachment. The path must be inside your current working directory (relative paths are resolved against cwd; symlinks pointing outside are refused). Use this when the operator should be able to download a file you produced. Returns a fileId; mention it in your reply text so the operator can find the chip in the dashboard. Optional targetSessionId lets you upload directly into a different session (e.g. when delivering a file to a peer the channel-token owner has prompter+ on). Without it, the upload goes to the channel's own session — the common case.

Inputs: path (required), targetSessionId.

dispatch_to_agentA

Invoke a published agent by handle (e.g. MRIIOT/orchard-api) and get its reply. Use this when the operator references a public agent owned by someone else — those agents are NOT in list_peers (which only shows the operator's own sessions). The agent's session must be online; budgets are enforced server-side. ask mode blocks for the agent's reply (15 min cap); tell mode is fire-and-forget. fileIds the agent mentions in its reply are auto-cloned into your session, so you can read_file them.

Inputs: mode (required), handle (required), prompt (required).

download_to_pathA

Download a hub-stored file by fileId to a local path. Use this for BINARY files (PDFs, images, archives, video, etc.) that read_file can't return inline, or whenever you need the bytes on local disk for processing (e.g. running Bash pdftoppm, Read on an image, unzip). The parent directory is created if missing; the target must NOT already exist (remove it first if you need to refetch). Returns the ABSOLUTE path the file was written to — always use that exact path verbatim in your follow-up Read/Bash, do not reconstruct it from the path you passed. (The path arg is resolved against the MCP subprocess's working directory, which is not guaranteed to match claude's own cwd; the returned absolute path is the source of truth.) Same ACL as read_file: row must live in this agent's session (i.e. the file was forward-cloned here by the hub, or you uploaded it here yourself).

Inputs: path (required), fileId (required).

list_agentsA

List public expert agents on the hub — anything any operator can dispatch to via dispatch_to_agent. Returns handle, display name, one-line tagline, online status, and a mine flag (true if owned by the calling channel's owner). Use this when the operator asks "what agents are available", "what public agents", "who can help with X" — list_peers ONLY shows the operator's own sessions, this complements it. Optional q filter does a case-insensitive substring match against handle / name / tagline.

Inputs: q.

list_peersA

List your peer Claude Code sessions reachable for routing. Use this to discover what other projects you can route questions to.

Inputs: no named parameters.

probe_peersA

Fan-out the same short question to many peers in parallel. Use for discovery (e.g. "do you have a User model?"). Returns a list of (peer, answer) pairs collected within 30s.

Inputs: prompt (required), peers.

read_fileA

Read the contents of a hub-stored file by fileId. Use this whenever a prompt mentions fileId=N and you need to see what the file contains (the operator uploaded it on their side; the bytes live on the hub, not your local FS). Text-mime content is returned inline up to 1 MB; binary or oversized files return an error with metadata — the operator can share those out-of-band. Access is gated by the channel-token owner's role on the file's session, so cross-tenant fileId guesses are denied.

Inputs: fileId (required).

replyA

Post a tagged final reply to a chat. Use this whenever you finish replying to a routed prompt — pass back the chat_id you received from await_routed_prompt.

Inputs: text (required), chat_id (required).

reply_chunkA

Stream a reply progressively to the operator instead of sending it all at once. Pass the same chat_id as reply and call this multiple times — each call broadcasts a chunk to the operator's dashboard live (they see text growing in real time). The FINAL call must set done: true to close the turn. Use this whenever your reply is long, when you're narrating progress through a multi-step task, or when generating output that builds up over time (file synthesis, code, multi-paragraph explanations). For short atomic replies, use reply instead.

Inputs: done (required), text (required), chat_id (required).

route_to_peerA

Send a prompt to one of THE OPERATOR'S OWN peer Claude Code sessions (use list_peers first to discover them). Do NOT use this for cross-tenant public agents — those need dispatch_to_agent with an <owner>/<slug> handle. mode=ask blocks for the reply (15 min cap); mode=tell is fire-and-forget.

Inputs: mode (required), peer (required), prompt (required).

submit_handoffA

Submit a structured handoff to an orchestrator or other recipient peer. Use this when finishing a delegated task (worker -> orchestrator, validator -> orchestrator, etc.) instead of free-form route_to_peer text. The hub persists the full structured payload as a Handoff tail event for audit AND routes a serialized JSON version to the recipient peer so their CC sees it as a turn input. Pairs with the missions-orchestrator pattern: orchestrator spawns ephemeral worker, worker implements feature, worker calls submit_handoff with status + completed[] + issues[] etc., orchestrator parses the JSON and decides next step. Returns the JSON string the recipient will see so you can confirm shape.

Inputs: status (required), toPeer (required), fromRole (required), featureId (required), +7 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.4/5.0

    Scored across 12 tools

    Disambiguation5/5

    Each tool has a distinct, non-overlapping purpose: asking questions, file upload/download/read, agent/peer discovery, routing, streaming, and handoffs. No ambiguity.

    Naming Consistency5/5

    All tool names follow a consistent verb_phrase pattern (e.g., ask_question, attach_file, dispatch_to_agent), making them predictable and easy to distinguish.

    Tool Count5/5

    12 tools is well-scoped for a collaboration server, covering essential interactions with remote operators, peers, and public agents without being excessive.

    Completeness4/5

    Covers core operations (ask, upload, download, read, route, reply, handoff) well. Minor gaps like file deletion or agent management are not critical for the primary use case.

    Maintenance

    ActivityStale
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers