Expand description
§agent-client-protocol – the Agent Client Protocol (ACP) SDK
agent-client-protocol is a Rust SDK for building Agent-Client Protocol (ACP) applications. ACP is a protocol for communication between AI agents and their clients (IDEs, CLIs, etc.), enabling features like tool use, permission requests, and streaming responses.
§What can you build with agent-client-protocol?
- Clients that talk to ACP agents (like building your own Claude Code interface)
- Proxies that add capabilities to existing agents (like adding custom tools via MCP)
- Agents that respond to prompts with AI-powered responses
§Protocol versions
Every connection names the ACP protocol version it speaks:
Client.v1(),Agent.v1()andProxy.v1()start a stable protocol v1 connection. Its types are inv1and its messages inv1::schema.- With the
unstable_protocol_v2feature,Client.v2(),Agent.v2()andProxy.v2()start a draft protocol v2 connection. Its types are inagent_client_protocol::v2and its messages inv2::schema.
The v1 and v2 modules use the same names for the connection, the builder,
the request handles and schema (ConnectionTo, Builder, Responder,
Dispatch, SentRequest, …). Their session APIs differ:
v1::ActiveSession reads the session’s updates from its own stream, while
v2::ActiveSession only sends commands and the updates arrive through
typed handlers on the connection. Some names exist in only one module, such
as v1::LoadSessionBuilder and v1::SessionMessage, or
v2::InitializeOutcome.
The crate root holds what every version shares: transports, roles, the
JSON-RPC traits, Error, the generic request handles (which default to
the version-neutral Raw marker) and, with unstable_protocol_v2, the
routers that serve both versions. Builder::new remains as the raw,
version-neutral escape hatch: it applies no protocol-version guard.
§Quick Start: Connecting to an Agent
The most common use case is connecting to an existing ACP agent as a client.
This example uses stable ACP protocol v1. The draft protocol v2 feature
provides a command-only v2::ActiveSession API and receives updates and interactive
requests through typed connection handlers because prompt acceptance and
inbound traffic are independent. With both v2 and MCP-over-ACP features,
Proxy.v2() supports global MCP attachment, while v2::SessionBuilder and
v2::ResumeSessionBuilder support per-session attachment plus non-blocking
proxy setup. With unstable_session_fork, v2::ForkSessionBuilder provides
the same shape for forked sessions and uses the response’s new session ID.
Per-session MCP routes and runners are ready before a setup request is
published, as is proxy session routing for resume replay. Successful v2
setup detaches MCP handlers for the connection lifetime; dropping the
returned v2::ActiveSession does not unregister them. In v1, v1::ActiveSession owns
per-session MCP registrations until drop, unless a proxy handoff detaches
them (proxy_remaining_messages or successful on_proxy_session_start).
Global proxy attachments are connection-scoped in both versions.
Here’s a minimal example that initializes a v1 connection, creates a session, and sends a prompt:
use agent_client_protocol::Client;
use agent_client_protocol::{schema::ProtocolVersion, v1::schema::InitializeRequest};
use agent_client_protocol::v1::SessionSetup;
Client.v1()
.name("my-client")
.connect_with(transport, async |cx| {
// Step 1: Initialize the connection
cx.send_request(InitializeRequest::new(ProtocolVersion::V1))
.block_task().await?;
// Step 2: Create a session and send a prompt
cx.build_session_cwd()?
.block_task()
.run_until(async |SessionSetup { mut session, .. }| {
session.send_prompt("What is 2 + 2?")?;
let response = session.read_to_string().await?;
println!("{}", response);
Ok(())
})
.await
})
.awaitFor a complete working example, see yolo_one_shot_client.rs.
§Cookbook
The agent_client_protocol_cookbook crate contains practical guides and examples:
- Connecting as a client
- Global MCP server
- Per-session MCP server with workspace context
- Building agents and reusable components
- Running proxies with the conductor
§Cargo Features
No features are enabled by default. Protocol serialization, connections, sessions, custom MCP servers, and the generic transport adapters remain available without opting in to native I/O or JSON Schema generation.
process: native subprocess support throughAcpAgentandAcpAgentConfig.stdio: the nativeStdioadapter.schemars:JsonSchemaimplementations on protocol types and typed MCP tool helpers inmcp_server.
For example, a native client launching an agent opts into process:
agent-client-protocol = { version = "5", features = ["process"] }Enable stdio for an agent using Stdio, or schemars for typed MCP tool
definitions. LineDirection is available on native targets with either
process or stdio; neither feature enables the other.
The agent-client-protocol-rmcp crate explicitly enables schemars for its
tool builders. Unstable protocol features remain independent opt-ins.
No features have been enabled by default since 3.0. When upgrading from
2.x, explicitly enable every feature your application uses;
default-features = false is no longer needed for a lean dependency.
§Stability
- The stable API, everything that is not behind an
unstable_*feature, follows semver: it changes incompatibly only in a major release. - Everything behind an
unstable_*feature may change in a minor release. This includes all ofagent_client_protocol::v2and the other items thatunstable_protocol_v2enables. Stabilizing protocol v2 only removes theunstable_protocol_v2gate. - This crate depends on one exact version of
agent-client-protocol-schema(an=requirement), and a minor release may move that pin to a newer schema release. Use each version’s message types throughv1::schemaandv2::schema, and the version-neutral items such asProtocolVersionthroughschema, instead of depending onagent-client-protocol-schemadirectly. A direct dependency must allow the exact version this crate pins, or Cargo cannot resolve the dependency graph. - All SDK crates share one version number, so moving a public dependency of
any of them to a new major version, such as
axumorreqwestinagent-client-protocol-http, is a major release of all of them.
§WebAssembly
The runtime-neutral protocol engine and transport abstractions compile for
wasm32-wasip1 and wasm32-wasip2 without additional features. For
JavaScript-hosted wasm32-unknown-unknown, enable wasm_js to select Web
Crypto through wasm-bindgen as the UUID randomness backend. The target
does not imply a JavaScript host, so this feature is not enabled by default;
other OS-less WebAssembly hosts must arrange a compatible UUID randomness
backend instead.
This crate does not provide a WebAssembly executor or host I/O adapter. The
native process and stdio features depend on process spawning and
blocking-thread facilities, so their dependencies and exports (including
LineDirection) remain excluded on WebAssembly even when enabled.
Embedders provide their own runtime and transport. They can exchange
TransportFrame values through Channel, newline-delimited JSON through
Lines, or use ByteStreams with futures::io::AsyncRead and
AsyncWrite. The embedding runtime must drive the resulting connection
future.
Handlers, transports, and connection futures must be Send on every
target, including WebAssembly. JavaScript host values such as
wasm_bindgen::JsValue are !Send, so keep them outside the connection and
exchange Send data with it through Channel or ByteStreams. A later
release may relax these bounds on WebAssembly. That change would not affect
native code.
§Core Concepts
The concepts module provides detailed explanations of how agent-client-protocol works,
including connections, sessions, callbacks, ordering guarantees, and more.
§Related Crates
agent-client-protocol-conductor- Binary for running proxy chains
Re-exports§
pub use role::acp::AgentProtocolRouter;unstable_protocol_v2pub use role::acp::ClientProtocolConnector;unstable_protocol_v2pub use role::acp::ProxyProtocolRouter;unstable_protocol_v2pub use role::Role;pub use role::RoleId;pub use role::UntypedRole;pub use role::acp::Agent;pub use role::acp::Client;pub use role::acp::Conductor;pub use role::acp::Proxy;pub use component::ConnectTo;pub use component::ConnectionDriver;pub use component::DynConnectTo;
Modules§
- component
- Component abstraction for agents and proxies ConnectTo abstraction for agents and proxies.
- concepts
- Core concepts for understanding and using agent-client-protocol Core concepts for understanding and using agent-client-protocol.
- mcp_
server - Runtime-agnostic MCP server support, including optional attachment to ACP sessions. Runtime-agnostic MCP server support.
- role
- Role types for ACP connections Role types for ACP connections.
- schema
- Version-neutral ACP schema items.
- util
- Utility functions and types
- v1
- The SDK API for ACP protocol v1.
- v2
unstable_protocol_v2 - The SDK API for draft ACP protocol v2.
Macros§
- on_
receive_ dispatch - This macro is used for the value of the
to_future_hackparameter ofBuilder::on_receive_dispatchandBuilder::on_receive_dispatch_from. - on_
receive_ notification - This macro is used for the value of the
to_future_hackparameter ofBuilder::on_receive_notificationandBuilder::on_receive_notification_from. - on_
receive_ request - This macro is used for the value of the
to_future_hackparameter ofBuilder::on_receive_requestandBuilder::on_receive_request_from. - tool_fn
- This is a hack that must be given as the final argument of
the MCP server builder’s
tool_fnmethod when defining stateless concurrent tools. - tool_
fn_ mut - This is a hack that must be given as the final argument of
the MCP server builder’s
tool_fn_mutmethod when defining tools.
Structs§
- AcpAgent
processand non-target_family=wasm - A component representing an external ACP agent running in a separate process.
- AcpAgent
Config processand non-target_family=wasm - Configuration for launching an ACP agent subprocess.
- Builder
- A JSON-RPC connection that can act as either a server, client, or both.
- Byte
Streams - A component that communicates over byte streams (stdin/stdout, sockets, pipes, etc.).
- Chain
Run - Chains two RunIn implementations to run in parallel.
- Channel
- A channel endpoint representing one side of a bidirectional JSON-RPC transport.
- Connection
To - Connection context for sending messages and spawning tasks.
- Dynamic
Handler Guard - A guard that keeps a dynamic message handler registered.
- Error
- A JSON-RPC error object, independent of the ACP protocol version.
- Error
Code - A JSON-RPC error code.
- Initialization
Version Mismatch unstable_protocol_v2 - A successful
initializeresponse that selected a lower protocol version than the local API requires. - Lines
- A component that communicates over line streams.
- Null
Close - A close handler that does nothing.
- Null
Handler - Null handler that accepts no messages.
- NullRun
- A no-op RunIn that completes immediately.
- Prepared
Request - A request that has not been published to its connection.
- Raw
- The version-neutral protocol marker of the raw dispatch layer, and the default.
- RawJson
RpcError - A JSON-RPC error without ACP-specific interpretation.
- RawJson
RpcNotification - A JSON-RPC notification with uninterpreted params.
- RawJson
RpcRequest - A JSON-RPC request with uninterpreted params.
- Request
Cancellation - A request-local marker that is set when the peer asks to cancel the request.
- Request
Cancellation Handle - Explicit cancellation control for one outgoing request.
- Responder
- The context to respond to an incoming request.
- Response
Router - Context for handling an incoming JSON-RPC response.
- Sent
Request - Represents a pending response of type
Rfrom an outgoing request. - Stdio
stdioand non-target_family=wasm - A transport that connects to an ACP peer via standard input/output.
- Untyped
Message - An incoming JSON message without any typing. Can be a request or a notification.
- V1
- ACP protocol version 1.
- V2
unstable_protocol_v2 - ACP protocol version 2.
Enums§
- Connection
Termination - Why a driven connection stopped.
- Dispatch
- An incoming request, notification, or response being dispatched through handlers. Requests include the context used to answer them; responses include the context used to route them to the local requester.
- Handled
- Return type from JrHandler; indicates whether the request was handled or not.
- Line
Direction ( processorstdio) and non-target_family=wasm - Direction of a line being sent or received by a native transport.
- RawJson
RpcId - A JSON-RPC
idexactly as it appears on the wire: an integer, a string ornull. - RawJson
RpcMessage - One valid JSON-RPC message carried inside a
TransportFrame. - RawJson
RpcParams - Raw JSON-RPC request or notification parameters.
- RawJson
RpcResponse - A transport-level JSON-RPC response with an opaque result or raw error.
- Selected
Initialize Response unstable_protocol_v2 - A peer’s initialization response, typed by the protocol version it selected.
- Transport
Frame - A JSON-RPC frame exchanged between protocol components and transports.
Constants§
- CONNECTION_
TERMINATED_ REASON - Stable discriminator stored in the
data.reasonfield of errors produced when a connection terminates for a reason other than clean incoming EOF before a request receives its response. - INCOMING_
TRANSPORT_ CLOSED_ REASON - Stable discriminator stored in the
data.reasonfield of errors produced when the incoming transport reaches clean EOF before a request receives its response.
Traits§
- Handle
Connection Close - A handler that runs after the incoming transport reaches clean EOF.
- Handle
Dispatch From - Handlers process incoming JSON-RPC messages on a connection.
- Into
Handled - Trait for converting handler return values into
Handled. - Json
RpcMessage - Common bounds for any JSON-RPC message.
- Json
RpcNotification - A struct that represents a notification (JSON-RPC message that does not expect a response).
- Json
RpcRequest - A struct that represents a request (JSON-RPC message expecting a response).
- Json
RpcResponse - Defines the “payload” of a successful response to a JSON-RPC request.
- Protocol
- The protocol version of a request handle or builder, as a type.
- RunWith
Connection To - A background task that runs alongside a connection.
Functions§
- is_
cancel_ request_ notification - Whether a notification is a
$/cancel_request, even when it is still wrapped inproxy/successorenvelopes. - is_
connection_ terminated - Return whether
errorreports that the connection terminated before a request received its response. - is_
incoming_ transport_ closed - Return whether
errorreports that the incoming transport reached clean EOF before a request received its response.
Type Aliases§
- BoxFuture
alloc - An owned dynamically typed
Futurefor use in cases where you can’t statically type your result or need to add some indirection. - Result
- Result type whose error defaults to the SDK’s
Error.
Derive Macros§
- Json
RpcNotification - Derive macro for implementing
JsonRpcNotificationandJsonRpcMessagetraits. - Json
RpcRequest - Derive macro for implementing
JsonRpcRequestandJsonRpcMessagetraits. - Json
RpcResponse - Derive macro for implementing
JsonRpcResponsetrait.