ExMCP.ACP.Adapters.Claude (ex_mcp v1.0.0-rc.0)
View SourceAdapter 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 Event | ACP Message |
|---|---|
stream_event (text_delta) | session/update notification (text) |
stream_event (thinking_delta) | session/update (agent_thought_chunk) |
assistant | accumulate content blocks |
assistant (tool_use) | session/update (tool_call) |
user (tool_result) | session/update (tool_call_update) |
result | prompt 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-indefaultmode. 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 asnilbut 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_ask— best non-interactive default: auto-denies all tools except those inallowed_tools. Pair with an explicit allow-list for the tools the pipeline actually needs.:bypass_permissions— same effect as:bypassvia 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.