Core Summary
Agent Client Protocol (ACP) v1 is an open JSON-RPC 2.0 contract between a coding Agent and the Client that presents it to a developer, usually an IDE or code editor. It standardizes session setup, prompt turns, streamed messages and tool status, permission requests, file access, terminal execution, cancellation, and optional session restoration.
ACP solves an integration problem, not an autonomy or security problem. A compatible message does not prove that an Agent is trustworthy, a file path is authorized, a command is safe, or an external write occurred exactly once.
Contents
- What boundary does ACP standardize?
- How does an ACP v1 connection work?
- Why is ACP bidirectional?
- How do permissions and tool updates work?
- How is ACP different from MCP, A2A, and LSP?
- What can fail in production?
- How should ACP implementations be tested?
- Frequently asked questions
Key Takeaways
- ACP connects an interactive Client to a coding Agent; it does not connect arbitrary Agents to one another.
- Stable ACP wire compatibility is negotiated through the integer
protocolVersion; optional behavior is negotiated through capabilities. - The protocol is bidirectional because the Agent can request Client-owned files, terminals, elicitation, and permission decisions.
session/updatedescribes progress and results, while the originalsession/promptresponse closes the turn with a stop reason.- Permission UX, authentication, object authorization, sandboxing, idempotency, and recovery remain implementation responsibilities.
- The published remote HTTP and WebSocket design is an active RFD, so deploy against verified implementation support rather than assuming universal compatibility.
What Boundary Does ACP Standardize?
ACP standardizes the boundary between the developer-facing application and the program that runs a coding Agent. This separates an editor's interface and local environment from an Agent Runtime that may use different models, prompts, tools, and control loops.
Without a shared protocol, each editor-Agent pair needs a custom adapter. The editor must understand proprietary streaming events, tool representations, permission callbacks, session state, and process behavior. The Agent must separately learn how each editor exposes files, terminals, diffs, and user interaction. ACP gives both sides a common contract.
The two primary roles are:
| Role | Owns | Does not automatically own |
|---|---|---|
| Client | user interface, editor state, local capability exposure, permission presentation | Agent reasoning, model calls, tool implementation |
| Agent | prompt processing, model loop, tool coordination, progress reporting, session context | editor UI, unrestricted local access, backend authorization |
The word "Client" can be confusing because both sides initiate requests. It identifies the user-facing role, not a one-way network caller. The Client invokes methods such as initialize and session/prompt; the Agent may invoke methods such as fs/read_text_file and session/request_permission.
ACP currently defines stable wire-protocol version 1. The official repository distinguishes that negotiated wire version from SDK, crate, and generated-schema release versions. Two schema artifact releases can describe the same v1 wire contract, so compatibility checks must use protocolVersion plus capabilities rather than package version alone.
How Does an ACP v1 Connection Work?
An ACP v1 interaction moves through initialization, session setup, one or more prompt turns, and explicit cancellation or cleanup. The lifecycle gives the Client enough information to render the Agent's work without owning the Agent's internal reasoning loop.
Initialization negotiates support
Every connection starts with initialize. The Client sends the latest major protocol version it supports, its optional capabilities, and normally implementation information. The Agent returns the selected version, its capabilities, available authentication methods, and implementation information.
{
"jsonrpc": "2.0",
"id": 0,
"method": "initialize",
"params": {
"protocolVersion": 1,
"clientCapabilities": {
"fs": {
"readTextFile": true,
"writeTextFile": false
},
"terminal": true
},
"clientInfo": {
"name": "review-workbench",
"title": "Review Workbench",
"version": "2.4.0"
}
}
}
An omitted capability means unsupported. A Client that advertises file reads but not writes has not granted a vague "filesystem" permission. The Agent must not call fs/write_text_file. New optional capabilities do not increase the major wire version, which makes capability-combination tests essential.
If the Agent selects a version the Client does not support, the Client should close the connection and explain the incompatibility. Silently continuing risks parsing a valid message with the wrong semantics.
Session setup binds the working context
session/new creates an independent conversation and returns a sessionId. Its cwd must be absolute and remains the primary base for relative path resolution. If the Agent advertises additionalDirectories, the Client may supply more absolute workspace roots.
{
"jsonrpc": "2.0",
"id": 1,
"method": "session/new",
"params": {
"cwd": "/work/inventory-service",
"additionalDirectories": [
"/work/shared-contracts"
],
"mcpServers": []
}
}
Treat the effective root set as a maximum filesystem boundary, not merely navigation metadata. Canonicalize paths, reject traversal and symlink escapes, and apply the same boundary to direct file methods, shell working directories, search tools, and any Agent-side filesystem implementation.
Session restoration has distinct semantics:
| Method | Capability | History behavior |
|---|---|---|
session/new |
baseline | starts a new context |
session/load |
loadSession |
replays the conversation through updates before returning |
session/resume |
sessionCapabilities.resume |
restores without replaying previous messages |
session/close |
sessionCapabilities.close |
cancels active work and releases session resources |
A session ID is a routing handle, not proof of identity or ownership. Bind it to the authenticated user, workspace, Agent build, policy, and retention rules in trusted application state.
A prompt response closes the turn
session/prompt carries an array of content blocks. Text and resource links are baseline inputs; image, audio, and embedded resource content require advertised prompt capabilities.
During processing, the Agent sends session/update notifications for message chunks, plans, tool calls, tool status, file locations, usage, and other negotiated events. The original prompt request remains open until the Agent returns a stopReason.
{
"jsonrpc": "2.0",
"method": "session/update",
"params": {
"sessionId": "sess_4d53",
"update": {
"sessionUpdate": "tool_call",
"toolCallId": "call_tests_01",
"title": "Run focused unit tests",
"kind": "execute",
"status": "pending"
}
}
}
The Client should correlate updates by session and tool-call identifiers, tolerate partial updates, and render unknown optional fields without failing the entire turn. It should not infer success from the last streamed text: the prompt response and final tool statuses are the structured completion evidence.
Why Is ACP Bidirectional?
ACP is bidirectional because the Client controls resources the Agent needs but should not own directly. The editor can expose unsaved buffers, native terminals, permission UX, or structured user input while retaining control over those capabilities.
The main Agent-to-Client surfaces include:
| Surface | Purpose | Required control |
|---|---|---|
fs/read_text_file |
read text, including unsaved editor state | canonical path and authorized root |
fs/write_text_file |
create or replace text content | write policy, conflict handling, audit |
terminal/create |
start a command with args, env, cwd, and output limit | executable policy, sandbox, credentials |
terminal/output |
retrieve bounded output and exit status | byte limit, encoding, redaction |
session/request_permission |
ask for a user decision on a tool call | truthful preview and argument binding |
elicitation/create |
collect structured or URL-mediated user input | capability, origin, schema, privacy |
This inversion is valuable for editor integration. A Client can return the current buffer rather than stale disk bytes, show a real diff, and keep terminal lifecycle visible. It also creates a high-risk trust boundary: a compromised Agent can ask the Client to read secrets or run dangerous commands.
Capability negotiation answers whether a method is available. It does not answer whether a particular call is allowed. The Client must evaluate each path, command, environment variable, destination, and operation against current policy.
How Do Permissions and Tool Updates Work?
ACP separates the visible lifecycle of a tool call from the optional user permission request. The Agent reports a tool call through session/update, may call session/request_permission, and then reports transitions such as pending, in_progress, completed, or failed.
Permission options include allow or reject choices for one call or future calls. Their labels are presentation hints, not a security policy language. A durable "allow always" rule must be narrowly scoped to the authenticated user, workspace, Agent identity, tool identity, normalized arguments or argument class, policy revision, and expiry.
For a consequential action, the Client should show:
- the executable tool or command;
- the concrete target files, services, or records;
- the working directory and relevant arguments;
- the data destination and expected side effect;
- whether the decision applies once or persists.
The downstream operation still needs its own authorization. An approved request to modify invoice-42 does not prove that the user belongs to the invoice's tenant. Derive identity from trusted authentication, enforce object-level policy at the service, and reject model-supplied identity fields.
ACP tool status also does not provide transaction semantics. If a command or API write commits and the Agent process then exits, the Client may only know that the result is uncertain. Use stable operation keys, an effect journal, and downstream reconciliation before retrying. This is the same production boundary described in Tool Use.
How Is ACP Different from MCP, A2A, and LSP?
ACP, MCP, A2A, and LSP standardize different relationships. Comparing them by acronym alone leads to incorrect architectures and overstated security guarantees.
| Protocol | Primary relationship | Main unit | Not a substitute for |
|---|---|---|---|
| ACP | editor or UI Client to coding Agent | session and prompt turn | backend authorization or Agent runtime |
| MCP | AI Host or Client to capability Server | tool, resource, prompt | user-facing coding session |
| A2A | Agent client to independently operated Agent service | task, message, artifact | local IDE integration |
| LSP | editor to language server | document and language feature | generative Agent workflow |
ACP is MCP-friendly but does not replace MCP. During session setup, the Client can provide MCP server configurations for the Agent to connect to. This composes two boundaries:
developer <-> IDE / ACP Client <-> coding Agent <-> MCP Server <-> data or action
Each hop needs separate identity, authorization, input validation, output limits, and audit. A Client's ACP approval must not be forwarded as an all-purpose credential to an MCP Server.
A2A Protocol targets remote Agent-to-Agent collaboration and durable task exchange. A coding Agent could use A2A behind its runtime, but the IDE still needs ACP semantics to render its local session. The MCP, A2A, and A2UI boundary guide explains why these layers should be added only when ownership boundaries justify them.
LSP is the closest analogy for ecosystem integration, but its workload is different. Language servers answer bounded language-feature requests such as completion, hover, diagnostics, and symbol lookup. Coding Agents run open-ended, multi-step turns that may call models, ask permission, edit files, run commands, and stream plans. ACP therefore needs explicit session, tool, permission, and cancellation semantics beyond a simple "LSP for agents" slogan.
What Can Fail in Production?
Production ACP integrations fail at process, protocol, policy, and effect boundaries. A happy-path chat demo exercises only a small part of the contract.
Standard output can become corrupted
For a local subprocess transport, protocol frames and logs must remain separate. Writing diagnostics to the protocol stream can turn a valid JSON-RPC exchange into an unrecoverable parse failure. Capture logs through the designated diagnostic channel, impose line and message limits, and terminate the process tree when the connection closes.
Capabilities can drift
An Agent update can add optional fields or alter capability combinations without changing protocol v1. Pin the Agent and SDK release, record the negotiated capabilities, ignore unknown optional data where allowed, and run fixtures against every supported combination.
Do not infer wire compatibility from an SDK package number. The official ACP repository explicitly versions schema artifacts independently from protocolVersion.
Paths can escape the workspace
An absolute path is syntactically valid but may still be unauthorized. Resolve symlinks and normalized paths, compare them against the session's effective root set, and perform the check again at execution time to reduce time-of-check/time-of-use races.
Terminal execution can leak or hang
Pass commands and arguments as structured values rather than constructing a shell string. Limit environment variables, execution time, child processes, network access, output bytes, and retained logs. ACP's outputByteLimit bounds retained terminal output, but the Client must still redact secrets and truncate on valid character boundaries.
Cancellation can race with side effects
session/cancel asks the Agent to stop as soon as possible; it cannot reverse a write that already committed. The Client should cancel pending permission requests and preemptively mark unfinished tool calls, while the Agent catches abort exceptions and returns the semantic cancelled stop reason. For external writes, track prepared, dispatched, committed, failed, and outcome_unknown separately.
Untrusted content can influence the Agent
Editor files, MCP results, command output, tool descriptions, and remote resources can all carry Prompt Injection. Keep provenance with every content block, separate data from trusted policy, restrict tools independently of model text, and never let an update or resource expand permissions.
Remote transport assumptions can be premature
The ACP site publishes a Streamable HTTP and WebSocket transport as an active Request for Discussion. Its own status-quo section says ACP only has stdio today. Treat the RFD as a proposal unless the target Client and Agent explicitly document and test the same transport profile; do not describe it as stable v1 behavior merely because ecosystem pages mention remote scenarios.
How Should ACP Implementations Be Tested?
ACP testing should evaluate protocol conformance and the real coding trajectory. A final answer can look correct even when the integration leaked a secret, ignored cancellation, wrote outside the workspace, or duplicated an external effect.
Use this release matrix:
| Layer | Required evidence |
|---|---|
| Wire | valid JSON-RPC, ID correlation, notification handling, error mapping |
| Negotiation | supported and unsupported versions, omitted capabilities, mixed capability sets |
| Session | new, load replay, resume without replay, close, invalid ownership |
| Prompt | content capability checks, ordered chunks, stop reasons, usage limits |
| Permission | allow, reject, persistent-rule scope, cancellation while waiting |
| Files | unsaved reads, traversal, symlink escape, conflicts, oversized content |
| Terminal | structured args, timeout, kill, release, truncation, encoding, secret redaction |
| Reliability | Agent crash, malformed frame, reconnect, duplicate update, unknown effect |
| Security | malicious repository text, poisoned tool output, credential isolation, tenant crossing |
| Evaluation | task success, unnecessary tool calls, diff quality, rollback, latency and cost |
Record the Client build, Agent build, negotiated protocol version, capabilities, session and turn IDs, model and policy revisions, tool-call IDs, redacted argument digests, permission decisions, filesystem roots, terminal exit state, cancellation timing, effect status, and final outcome. Do not store hidden chain-of-thought or unrestricted private file contents.
The broader AI coding rule architecture explains how repository instructions fit into context without becoming authorization. For runtime controls around state, budgets, approvals, idempotency, and recovery, use the Agent Harness guide.
Frequently Asked Questions
What is the Agent Client Protocol?
ACP is an open JSON-RPC 2.0 protocol for communication between an interactive Client, usually an IDE, and a coding Agent. It defines the lifecycle and presentation contract around an Agent session while leaving model behavior, tool implementation, storage, and business policy to the products on each side.
Is ACP just LSP for AI Agents?
The analogy explains the interoperability goal, but not the complete design. LSP standardizes bounded language-intelligence features. ACP carries open-ended sessions, streamed model output, plans, tools, permissions, diffs, terminals, usage, and cancellation, so it has a larger execution and safety surface.
Does ACP replace MCP?
No. ACP connects the editor experience to the coding Agent. MCP connects an AI application or Agent to tools, resources, and prompts. ACP can tell an Agent which MCP servers to connect to, but every MCP request still needs its own authentication, authorization, validation, and result controls. See the MCP production guide for that boundary.
Can ACP run a remote Agent over HTTP?
Remote transport work exists, but support must be verified against the target implementations. The published Streamable HTTP and WebSocket design is marked as an active RFD, while stable v1 documentation centers on the core protocol and the local subprocess model. Pin the exact transport proposal or implementation release before deployment.
What is the minimum safe ACP implementation?
A minimum safe implementation negotiates capabilities, binds sessions to authorized workspace roots, validates all inbound JSON-RPC data, constrains subprocesses and credentials, presents argument-bound permissions, limits output, propagates cancellation, records effect state, and tests denial and failure paths. Protocol conformance alone is insufficient.
Summary
ACP gives editors and coding Agents a common, bidirectional session contract. Its strongest value is not a new model API; it is the separation of the user-facing Client from the replaceable Agent runtime while preserving native files, terminals, diffs, permissions, and progress.
Implement that boundary literally. Negotiate every optional feature, keep workspace and process access narrow, treat permission as user intent rather than backend authorization, and design cancellation around effects that may already have happened. Compose ACP with MCP or A2A only where the neighboring boundary is genuinely required.