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 initializesession/newsession/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 modecall_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: 5 min
  • Stdio buffer cap: 50 MiB per call (configurable on the row via stdio_buffer_limit_bytes)

Database — mate_acp_endpoint

ColumnTypeDefaultPurpose
idBIGINTPrimary key. Built-ins use 91000019100004
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
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_timeDATETIMETimestamps
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