ExMCP.ACP.Adapters.Claude (ex_mcp v1.0.0-rc.0)

View Source

Adapter for Claude Code CLI.

Translates between ACP JSON-RPC and Claude's stream-json NDJSON protocol. Ported from Arbor's CliTransport + StreamParser.

Claude CLI Protocol

  • Input: NDJSON on stdin with {"type":"user","message":{...},"session_id":"..."}
  • Output: NDJSON on stdout with event types: stream_event, assistant, user, result
  • Args: --output-format stream-json --input-format stream-json --verbose

ACP Mapping

Claude EventACP Message
stream_event (text_delta)session/update notification (text)
stream_event (thinking_delta)session/update (agent_thought_chunk)
assistantaccumulate content blocks
assistant (tool_use)session/update (tool_call)
user (tool_result)session/update (tool_call_update)
resultprompt response result

Features

  • Session resume via --resume <session_id> flag
  • Thinking block streaming with deduplication
  • Multi-turn tool use cycle tracking
  • Usage tracking with cache token support
  • Configurable thinking budget

Limitations

  • No session persistence/listing (sessions managed by Claude CLI)
  • No session cancel (would need SIGINT to Port subprocess)
  • No runtime config changes (static at launch)

Permission control (added 2026-06-06)

Pass-through opts on command/1 let callers narrow Claude's tool surface:

Claude.command(
  permission_mode: :dont_ask,
  allowed_tools: ["WebSearch", "WebFetch"]
)

Valid :permission_mode values (snake_case atoms map to Claude CLI's camelCase strings; bare binaries pass through):

  • nil (default, 2026-06-06 change) — passes no flag; Claude uses its built-in default mode. In a non-interactive ACP session this means the first tool use will block on a permission request the host is expected to handle.
  • :bypass — passes --dangerously-skip-permissions. The pre-2026-06-06 default. Disables Claude's entire permission engine.
  • :default — explicit default mode (same as nil but emits the flag explicitly).
  • :accept_edits — auto-accepts file edits + common filesystem ops; prompts for other tools.
  • :plan — read-only exploration (file reads + read-only shell).
  • :auto — auto-approves with safety classifier.
  • :dont_askbest non-interactive default: auto-denies all tools except those in allowed_tools. Pair with an explicit allow-list for the tools the pipeline actually needs.
  • :bypass_permissions — same effect as :bypass via the modern flag form (--permission-mode bypassPermissions).

:allowed_tools and :disallowed_tools accept a list of tool names; deny takes precedence over allow per Claude CLI's own rules.

Breaking change 2026-06-06

The default :permission_mode is now nil rather than :bypass. Callers that relied on the historical unrestricted behavior must explicitly pass permission_mode: :bypass. The flip is to align the default with the principle of least privilege: a host that spawns Claude with no opinion should NOT silently disable Claude's built-in safety system.