Skip to content

ACP — Agent Client Protocol ​

ACP is how MateClaw hands a prompt to an agent someone else built.

Agent Client Protocol is an open spec for agent clients to talk to agent servers over JSON-RPC. MateClaw acts as the host: it spawns an external CLI (Claude Code, Codex, OpenCode, Qwen Code, …), runs the initialize → session/new → session/prompt handshake on stdio, streams the response back into the conversation, and closes the process.

If MCP is "plug in a tool", ACP is "plug in a whole agent". From inside a MateClaw turn, calling Claude Code looks the same as calling any built-in tool — your agent just asks for acp_claude-code_prompt and reads the answer.


ACP vs MCP at a glance ​

MCPACP
What you connectA tool serverAn agent
GranularityPer-tool (tools/list)Per-prompt (one shot)
Transport in MateClawstdio / streamable_http / ssestdio
Session modelLong-lived, multi-callStateless: spawn → prompt → close
Typical useFilesystem, search, custom data APIDelegate a coding task to Claude Code / Codex
Surface in MateClawTool catalogSkill catalog (auto-bridged) + tool wrapper

You can mix both in the same agent.


Built-in endpoints ​

The Flyway migration that ships with MateClaw seeds four endpoints, all disabled by default — turn them on after you install the matching CLI.

SlugDisplay nameCommandNotes
claude-codeClaude Codenpx -y @zed-industries/claude-agent-acpAnthropic's Claude Code; reads ANTHROPIC_API_KEY
codexOpenAI Codex CLInpx -y @zed-industries/codex-acpOpenAI's coding agent; reads OPENAI_API_KEY
opencodeOpenCodeopencode acpMulti-model agent; binary must be on PATH
qwen-codeQwen Codeqwen --acpAlibaba's coding agent; reads DASHSCOPE_API_KEY

Built-in rows are write-protected — you can edit args_json / env_json / description / trusted / enabled, but you can't change the slug, replace the command, or delete the row. To run an unrelated agent, add a custom endpoint instead.


Configure via the admin console ​

Settings → ACP Endpoints is the full CRUD surface.

Add or edit an endpoint ​

  • Slug — lowercase identifier (e.g. claude-code). Immutable after create. Skills reference endpoints by this slug.
  • Display name — human label shown on the Skills page.
  • Description — operator notes.
  • Command — the executable (npx, opencode, …). Locked on built-in rows.
  • Args (JSON array) — CLI arguments, e.g. ["-y","@zed-industries/claude-agent-acp"].
  • Env (JSON object) — extra env vars merged into the child process. The visual editor masks values whose key matches *API_KEY*, *TOKEN*, *SECRET*, or *PASS*.
  • Tool parse mode — call_title / call_detail / update_detail. Controls how upstream tool-call events render into the streamed transcript.
  • Trusted — when ON, MateClaw auto-allows any session/request_permission the upstream agent asks for. When OFF, every permission request is denied (use this for non-interactive contexts).
  • Enabled — gate flag. Disabled endpoints don't bridge into the skill catalog.

Test the connection ​

Click Test to spawn the process, run initialize + session/new, and tear down. The result panel shows protocol version, agent capabilities, elapsed time, and — on failure — a translated error hint (see Trust & error translation). Status persists on the row as last_status / last_tested_at / last_error.

Enable / disable / delete ​

  • Toggle — drops the endpoint from the catalog without deleting it.
  • Delete — only available on custom rows. Built-in rows can't be deleted.

Any change publishes an AcpEndpointChangedEvent and the skill catalog re-syncs immediately — no restart needed.


REST API ​

Base path: /api/v1/acp/endpoints. JWT required.

MethodPathWhat it does
GET/List all endpoints
GET/{id}Fetch one
POST/Create custom endpoint
PUT/{id}Patch fields (built-in command is locked)
DELETE/{id}Delete custom endpoint (built-ins refuse)
PUT/{id}/toggle?enabled=true|falseEnable / disable
POST/{id}/testRun connection test

Create a custom endpoint ​

bash
curl -X POST http://localhost:18088/api/v1/acp/endpoints \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <token>" \
  -d '{
    "name": "my-coder",
    "displayName": "My Custom Coder",
    "description": "Internal coding agent",
    "command": "npx",
    "argsJson": "[\"-y\",\"@my-org/my-acp-agent\"]",
    "envJson": "{\"MY_API_KEY\":\"sk-...\"}",
    "toolParseMode": "call_detail",
    "trusted": true,
    "enabled": true
  }'

Test an endpoint ​

bash
curl -X POST http://localhost:18088/api/v1/acp/endpoints/9100002/test \
  -H "Authorization: Bearer <token>"

Response shape:

json
{
  "name": "claude-code",
  "command": "npx",
  "args": ["-y", "@zed-industries/claude-agent-acp"],
  "agentCapabilities": { "loadSession": false, "promptCapabilities": { "image": true } },
  "status": "OK",
  "elapsedMs": 1842
}

On failure status is ERROR and error carries the translated hint.


How endpoints reach your agents ​

There are two paths:

1. Auto-bridged virtual skill (zero config) ​

For every enabled endpoint, MateClaw registers a virtual skill card and a wrapper tool named acp_<slug>_prompt. The tool takes a single prompt string and returns the upstream agent's accumulated text reply. Any agent can call it the same way it calls a built-in tool — no skill manifest required.

Settings → ACP Endpoints (toggle on)
   ↓
AcpEndpointChangedEvent
   ↓
Skill catalog gains card "Claude Code"
Tool registry gains "acp_claude-code_prompt"
   ↓
Agent calls the tool → AcpDelegationService.prompt()
   ↓
spawn → initialize → session/new → session/prompt
   ↓
accumulate agent-message-chunk notifications
   ↓
return text to the agent's turn

2. Hand-authored skills (full control) ​

A skill manifest can declare type: acp and pin to an endpoint. The skill gets its own wrapper tool (acp_<endpoint>_<skill>_prompt), can inject a systemPrefix ahead of every prompt, and can override cwd per session.

yaml
# SKILL.md frontmatter
type: acp
acp:
  endpoint: claude-code
  systemPrefix: |
    You are working inside the MateClaw repo. Always run `mvn test` before reporting done.
  cwd: /workspaces/mateclaw

This is how the claude-code-helper and codex-helper skill templates ship.


Trust & error translation ​

Trust flag ​

ACP servers can pause and ask the host for permission (session/request_permission) before doing something sensitive — writing files, running shell commands, etc. MateClaw does not prompt the user mid-stream; instead, the per-endpoint trusted flag decides:

  • trusted: true — auto-allow the first option the agent offered. Best for installed CLIs you control.
  • trusted: false — cancel every permission request. Use for sandboxed or untrusted endpoints; the upstream agent will gracefully back off.

Error translation ​

Upstream errors from coding agents are notoriously cryptic. AcpRuntimeSupport.translateAuthError() recognises common 401 / 403 / "Request not allowed" patterns and rewrites them into something actionable:

  • Missing key → "Set ANTHROPIC_API_KEY" / OPENAI_API_KEY / DASHSCOPE_API_KEY / GOOGLE_API_KEY, picked per endpoint.
  • Claude Code OAuth keychain hijack → suggests claude logout to clear a stale OAuth token from ~/.claude/ that's shadowing your env var.

Hints surface in the test panel and in the streamed error message your agent receives.

Timeouts and limits ​

  • initialize handshake: 15s
  • session/new: 10s
  • Whole session/prompt round-trip: 300s by default, configurable per endpoint up to 3600s
  • Stdio buffer cap: 50 MiB per call (configurable on the row via stdio_buffer_limit_bytes)

Database — mate_acp_endpoint ​

ColumnTypeDefaultPurpose
idBIGINT—Primary key. Built-ins use 9100001–9100004
nameVARCHAR(64)—Unique slug. Skills reference this
display_nameVARCHAR(128)NULLLabel
descriptionTEXTNULLOperator notes
commandVARCHAR(256)—Process command
args_jsonTEXTNULLCLI args (JSON array)
env_jsonTEXTNULLEnv overrides (JSON object)
tool_parse_modeVARCHAR(32)call_titlecall_title / call_detail / update_detail
prompt_timeout_secondsINT300session/prompt call timeout, capped at 3600s
builtinBOOLEANFALSEBuilt-in rows are write-protected
trustedBOOLEANTRUEAuto-allow permission requests
enabledBOOLEANFALSEOff until you opt in
stdio_buffer_limit_bytesBIGINT5242880050 MiB cap on accumulated stdio
last_statusVARCHAR(32)NULLOK / ERROR
last_tested_atDATETIMENULLLast test timestamp
last_errorTEXTNULLLast test error
workspace_idBIGINT1Bound workspace
create_time / update_timeDATETIME—Timestamps
deletedINT0Logical delete

Schema lives at db/migration/{h2,mysql}/V68__add_acp_endpoints.sql.


Troubleshooting ​

"Command not found" ​

The command must be on the PATH of the user running MateClaw. Verify with which npx (or which opencode, which qwen). On Docker, install the CLI in the image. As a last resort, set command to the full absolute path.

"Request not allowed" / 403 from Claude Code ​

You probably have an OAuth token cached in ~/.claude/ that's overriding the ANTHROPIC_API_KEY you set in the env editor. Run claude logout, then click Test again. The test panel will tell you when it detects this case.

Hangs on session/new ​

Usually means the upstream CLI is downloading dependencies on first run (npx -y does this). Either pre-warm by running the CLI once outside MateClaw, or just retry — subsequent calls are fast.

"Subprocess output exceeded buffer" ​

The agent emitted more than 50 MiB of stdio in a single call. Bump stdioBufferLimitBytes on the endpoint, or split the prompt into smaller turns.

Tool doesn't show up on the Skills page ​

  • Confirm enabled: true.
  • Confirm the test passes (last_status: OK).
  • Open the agent's tool binding — auto-bridged tools are available to every agent unless explicitly excluded.

Next ​

  • Skills — including hand-authored ACP-typed skills
  • Tools — how the wrapper tool plugs into the registry
  • MCP — the sibling protocol for tool servers
  • Security & Approval — pairing the trust flag with Tool Guard