agent_client_protocol/lib.rs
1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![deny(missing_docs)]
3
4//! # agent-client-protocol -- the Agent Client Protocol (ACP) SDK
5//!
6//! **agent-client-protocol** is a Rust SDK for building [Agent-Client Protocol (ACP)][acp] applications.
7//! ACP is a protocol for communication between AI agents and their clients (IDEs, CLIs, etc.),
8//! enabling features like tool use, permission requests, and streaming responses.
9//!
10//! [acp]: https://agentclientprotocol.com/
11//!
12//! ## What can you build with agent-client-protocol?
13//!
14//! - **Clients** that talk to ACP agents (like building your own Claude Code interface)
15//! - **Proxies** that add capabilities to existing agents (like adding custom tools via MCP)
16//! - **Agents** that respond to prompts with AI-powered responses
17//!
18//! ## Quick Start: Connecting to an Agent
19//!
20//! The most common use case is connecting to an existing ACP agent as a client.
21//! This example uses stable ACP protocol v1. The draft protocol v2 feature
22//! provides a command-only `V2Session` API and receives updates and interactive
23//! requests through typed connection handlers because prompt acceptance and
24//! inbound traffic are independent. With both v2 and MCP-over-ACP features,
25//! `Proxy.v2()` supports global MCP attachment, while `V2SessionBuilder` and
26//! `V2ResumeSessionBuilder` support per-session attachment plus non-blocking
27//! proxy setup. With `unstable_session_fork`, `V2ForkSessionBuilder` provides
28//! the same shape for forked sessions and uses the response's new session ID.
29//! Per-session MCP routes and runners are ready before a setup request is
30//! published, as is proxy session routing for resume replay. Successful v2
31//! setup detaches MCP handlers for the connection lifetime; dropping the
32//! returned `V2Session` does not unregister them. In v1, `ActiveSession` owns
33//! per-session MCP registrations until drop, unless a proxy handoff detaches
34//! them (`proxy_remaining_messages` or successful `on_proxy_session_start`).
35//! Global proxy attachments are connection-scoped in both versions.
36//!
37//! Here's a minimal example that initializes a v1 connection, creates a
38//! session, and sends a prompt:
39//!
40//! ```no_run
41//! use agent_client_protocol::Client;
42//! use agent_client_protocol::schema::{ProtocolVersion, v1::InitializeRequest};
43//!
44//! # async fn run(transport: impl agent_client_protocol::ConnectTo<agent_client_protocol::Client>) -> agent_client_protocol::Result<()> {
45//! Client.builder()
46//! .name("my-client")
47//! .connect_with(transport, async |cx| {
48//! // Step 1: Initialize the connection
49//! cx.send_request(InitializeRequest::new(ProtocolVersion::V1))
50//! .block_task().await?;
51//!
52//! // Step 2: Create a session and send a prompt
53//! cx.build_session_cwd()?
54//! .block_task()
55//! .run_until(async |mut session| {
56//! session.send_prompt("What is 2 + 2?")?;
57//! let response = session.read_to_string().await?;
58//! println!("{}", response);
59//! Ok(())
60//! })
61//! .await
62//! })
63//! .await
64//! # }
65//! ```
66//!
67//! For a complete working example, see [`yolo_one_shot_client.rs`][yolo].
68//!
69//! [yolo]: https://github.com/agentclientprotocol/rust-sdk/blob/main/src/agent-client-protocol/examples/yolo_one_shot_client.rs
70//!
71//! ## Cookbook
72//!
73//! The [`agent_client_protocol_cookbook`] crate contains practical guides and examples:
74//!
75//! - Connecting as a client
76//! - Global MCP server
77//! - Per-session MCP server with workspace context
78//! - Building agents and reusable components
79//! - Running proxies with the conductor
80//!
81//! [`agent_client_protocol_cookbook`]: https://docs.rs/agent-client-protocol-cookbook
82//!
83//! ## Cargo Features
84//!
85//! No features are enabled by default. Protocol serialization, connections,
86//! sessions, custom MCP servers, and the generic transport adapters remain
87//! available without opting in to native I/O or JSON Schema generation.
88//!
89//! - `process`: native subprocess support through `AcpAgent` and `AcpAgentConfig`.
90//! - `stdio`: the native `Stdio` adapter.
91//! - `schemars`: `JsonSchema` implementations on protocol types and typed MCP
92//! tool helpers in [`mcp_server`].
93//!
94//! For example, a native client launching an agent opts into `process`:
95//!
96//! ```toml
97//! agent-client-protocol = { version = "3", features = ["process"] }
98//! ```
99//!
100//! Enable `stdio` for an agent using `Stdio`, or `schemars` for typed MCP tool
101//! definitions. `LineDirection` is available on native targets with either
102//! `process` or `stdio`; neither feature enables the other.
103//!
104//! The `agent-client-protocol-rmcp` crate explicitly enables `schemars` for its
105//! tool builders. Unstable protocol features remain independent opt-ins.
106//! When upgrading from 2.x, explicitly enable every feature your application
107//! uses; `default-features = false` is no longer needed for a lean dependency.
108//!
109//! ## WebAssembly
110//!
111//! The runtime-neutral protocol engine and transport abstractions compile for
112//! `wasm32-wasip1` and `wasm32-wasip2` without additional features. For
113//! JavaScript-hosted `wasm32-unknown-unknown`, enable `wasm_js` to select Web
114//! Crypto through `wasm-bindgen` as the UUID randomness backend. The target
115//! does not imply a JavaScript host, so this feature is not enabled by default;
116//! other OS-less WebAssembly hosts must arrange a compatible UUID randomness
117//! backend instead.
118//!
119//! This crate does not provide a WebAssembly executor or host I/O adapter. The
120//! native `process` and `stdio` features depend on process spawning and
121//! blocking-thread facilities, so their dependencies and exports (including
122//! `LineDirection`) remain excluded on WebAssembly even when enabled.
123//!
124//! Embedders provide their own runtime and transport. They can exchange
125//! `TransportFrame` values through `Channel`, newline-delimited JSON through
126//! `Lines`, or use `ByteStreams` with `futures::io::AsyncRead` and
127//! `AsyncWrite`. The embedding runtime must drive the resulting connection
128//! future.
129//!
130//! ## Core Concepts
131//!
132//! The [`concepts`] module provides detailed explanations of how agent-client-protocol works,
133//! including connections, sessions, callbacks, ordering guarantees, and more.
134//!
135//! ## Related Crates
136//!
137//! - [`agent-client-protocol-conductor`] - Binary for running proxy chains
138//!
139//! [`agent-client-protocol-conductor`]: https://crates.io/crates/agent-client-protocol-conductor
140
141/// Capability management for the `_meta.symposium` object
142mod capabilities;
143/// Component abstraction for agents and proxies
144pub mod component;
145/// Core concepts for understanding and using agent-client-protocol
146pub mod concepts;
147/// JSON-RPC connection and handler infrastructure
148mod jsonrpc;
149/// Runtime-agnostic MCP server support, including optional attachment to ACP sessions.
150pub mod mcp_server;
151/// Role types for ACP connections
152pub mod role;
153/// ACP protocol schema types - all message types, requests, responses, and supporting types
154pub mod schema;
155/// Utility functions and types
156pub mod util;
157
158pub use capabilities::*;
159
160pub use jsonrpc::{
161 Builder, ByteStreams, Channel, ConnectionContext, ConnectionTo, Dispatch, DynamicHandlerGuard,
162 HandleConnectionClose, HandleDispatchFrom, Handled, INCOMING_TRANSPORT_CLOSED_REASON,
163 IntoHandled, JsonRpcMessage, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse, Lines,
164 NullClose, NullHandler, PreparedRequest, RawConnectionContext, RawJsonRpcError,
165 RawJsonRpcMessage, RawJsonRpcParams, RawJsonRpcResponse, Responder, ResponseRouter,
166 SentRequest, TransportBatch, TransportBatchEntry, TransportFrame, UntypedMessage,
167 is_incoming_transport_closed,
168 run::{ChainRun, NullRun, RunWithConnectionTo},
169};
170pub use jsonrpc::{RequestCancellation, is_cancel_request_notification};
171#[cfg(feature = "unstable_protocol_v2")]
172pub use jsonrpc::{V2Builder, V2ConnectionContext, V2ConnectionTo};
173
174#[cfg(feature = "unstable_protocol_v2")]
175pub use role::acp::{AgentProtocolRouter, ClientProtocolConnector, ProxyProtocolRouter};
176pub use role::{
177 Role, RoleId, UntypedRole,
178 acp::{Agent, Client, Conductor, Proxy},
179};
180
181pub use component::{ConnectTo, ConnectionDriver, DynConnectTo};
182
183/// Implementation details used by the derive macros.
184#[doc(hidden)]
185pub mod __private {
186 pub use serde;
187 pub use serde_json;
188}
189
190// Re-export BoxFuture for implementing SDK traits that return boxed futures.
191pub use futures::future::BoxFuture;
192
193// Re-export commonly used infrastructure types for convenience
194pub use schema::v1::{Error, ErrorCode, Result};
195
196// Re-export derive macros for custom JSON-RPC types
197pub use agent_client_protocol_derive::{JsonRpcNotification, JsonRpcRequest, JsonRpcResponse};
198
199mod session;
200pub use session::*;
201
202#[cfg(all(feature = "process", not(target_family = "wasm")))]
203mod acp_agent;
204#[cfg(all(feature = "process", not(target_family = "wasm")))]
205#[cfg_attr(
206 docsrs,
207 doc(cfg(all(feature = "process", not(target_family = "wasm"))))
208)]
209pub use acp_agent::{AcpAgent, AcpAgentConfig};
210
211#[cfg(all(
212 any(feature = "process", feature = "stdio"),
213 not(target_family = "wasm")
214))]
215mod line_direction;
216#[cfg(all(
217 any(feature = "process", feature = "stdio"),
218 not(target_family = "wasm")
219))]
220pub use line_direction::LineDirection;
221
222#[cfg(all(feature = "stdio", not(target_family = "wasm")))]
223mod stdio;
224#[cfg(all(feature = "stdio", not(target_family = "wasm")))]
225#[cfg_attr(docsrs, doc(cfg(all(feature = "stdio", not(target_family = "wasm")))))]
226pub use stdio::Stdio;
227
228/// This is a hack that must be given as the final argument of
229/// the MCP server builder's `tool_fn_mut` method when defining tools.
230///
231/// The `agent-client-protocol-rmcp` crate provides the builder this macro is
232/// typically used with.
233/// Look away, lest ye be blinded by its vileness!
234///
235/// Fine, if you MUST know, it's a horrific workaround for not having
236/// [return-type notation](https://github.com/rust-lang/rust/issues/109417)
237/// and for [this !@$#!%! bug](https://github.com/rust-lang/rust/issues/110338).
238/// Trust me, the need for it hurts me more than it hurts you. --nikomatsakis
239#[macro_export]
240macro_rules! tool_fn_mut {
241 () => {
242 |func, params, context| Box::pin(func(params, context))
243 };
244}
245
246/// This is a hack that must be given as the final argument of
247/// the MCP server builder's `tool_fn` method when defining stateless concurrent tools.
248///
249/// The `agent-client-protocol-rmcp` crate provides the builder this macro is
250/// typically used with.
251/// See [`tool_fn_mut!`] for the gory details.
252#[macro_export]
253macro_rules! tool_fn {
254 () => {
255 |func, params, context| Box::pin(func(params, context))
256 };
257}
258
259/// This macro is used for the value of the `to_future_hack` parameter of
260/// [`Builder::on_receive_request`] and [`Builder::on_receive_request_from`].
261///
262/// It expands to `|f, req, responder, cx| Box::pin(f(req, responder, cx))`.
263///
264/// This is needed until [return-type notation](https://github.com/rust-lang/rust/issues/109417)
265/// is stabilized.
266#[macro_export]
267macro_rules! on_receive_request {
268 () => {
269 |f: &mut _, req, responder, cx| Box::pin(f(req, responder, cx))
270 };
271}
272
273/// This macro is used for the value of the `to_future_hack` parameter of
274/// [`Builder::on_receive_notification`] and [`Builder::on_receive_notification_from`].
275///
276/// It expands to `|f, notif, cx| Box::pin(f(notif, cx))`.
277///
278/// This is needed until [return-type notation](https://github.com/rust-lang/rust/issues/109417)
279/// is stabilized.
280#[macro_export]
281macro_rules! on_receive_notification {
282 () => {
283 |f: &mut _, notif, cx| Box::pin(f(notif, cx))
284 };
285}
286
287/// This macro is used for the value of the `to_future_hack` parameter of
288/// [`Builder::on_receive_dispatch`] and [`Builder::on_receive_dispatch_from`].
289///
290/// It expands to `|f, dispatch, cx| Box::pin(f(dispatch, cx))`.
291///
292/// This is needed until [return-type notation](https://github.com/rust-lang/rust/issues/109417)
293/// is stabilized.
294#[macro_export]
295macro_rules! on_receive_dispatch {
296 () => {
297 |f: &mut _, dispatch, cx| Box::pin(f(dispatch, cx))
298 };
299}