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
31//! attachments remain active for the connection lifetime.
32//!
33//! Here's a minimal example that initializes a v1 connection, creates a
34//! session, and sends a prompt:
35//!
36//! ```no_run
37//! use agent_client_protocol::Client;
38//! use agent_client_protocol::schema::{ProtocolVersion, v1::InitializeRequest};
39//!
40//! # async fn run(transport: impl agent_client_protocol::ConnectTo<agent_client_protocol::Client>) -> agent_client_protocol::Result<()> {
41//! Client.builder()
42//! .name("my-client")
43//! .connect_with(transport, async |cx| {
44//! // Step 1: Initialize the connection
45//! cx.send_request(InitializeRequest::new(ProtocolVersion::V1))
46//! .block_task().await?;
47//!
48//! // Step 2: Create a session and send a prompt
49//! cx.build_session_cwd()?
50//! .block_task()
51//! .run_until(async |mut session| {
52//! session.send_prompt("What is 2 + 2?")?;
53//! let response = session.read_to_string().await?;
54//! println!("{}", response);
55//! Ok(())
56//! })
57//! .await
58//! })
59//! .await
60//! # }
61//! ```
62//!
63//! For a complete working example, see [`yolo_one_shot_client.rs`][yolo].
64//!
65//! [yolo]: https://github.com/agentclientprotocol/rust-sdk/blob/main/src/agent-client-protocol/examples/yolo_one_shot_client.rs
66//!
67//! ## Cookbook
68//!
69//! The [`agent_client_protocol_cookbook`] crate contains practical guides and examples:
70//!
71//! - Connecting as a client
72//! - Global MCP server
73//! - Per-session MCP server with workspace context
74//! - Building agents and reusable components
75//! - Running proxies with the conductor
76//!
77//! [`agent_client_protocol_cookbook`]: https://docs.rs/agent-client-protocol-cookbook
78//!
79//! ## WASI
80//!
81//! The runtime-neutral protocol engine and transport abstractions compile for
82//! `wasm32-wasip1` and `wasm32-wasip2`. This crate does not provide a WASI
83//! executor or host I/O adapter. The native `AcpAgent` and `Stdio`
84//! implementations depend on process spawning and blocking-thread facilities,
85//! so they and `LineDirection` are not exported on these targets.
86//!
87//! Embedders provide their own runtime and transport. They can exchange
88//! `TransportFrame` values through `Channel`, newline-delimited JSON through
89//! `Lines`, or use `ByteStreams` with `futures::io::AsyncRead` and
90//! `AsyncWrite`. The embedding runtime must drive the resulting connection
91//! future.
92//!
93//! ## Core Concepts
94//!
95//! The [`concepts`] module provides detailed explanations of how agent-client-protocol works,
96//! including connections, sessions, callbacks, ordering guarantees, and more.
97//!
98//! ## Related Crates
99//!
100//! - [`agent-client-protocol-conductor`] - Binary for running proxy chains
101//!
102//! [`agent-client-protocol-conductor`]: https://crates.io/crates/agent-client-protocol-conductor
103
104/// Capability management for the `_meta.symposium` object
105mod capabilities;
106/// Component abstraction for agents and proxies
107pub mod component;
108/// Core concepts for understanding and using agent-client-protocol
109pub mod concepts;
110/// JSON-RPC connection and handler infrastructure
111mod jsonrpc;
112/// Runtime-agnostic MCP server support, including optional attachment to ACP sessions.
113pub mod mcp_server;
114/// Role types for ACP connections
115pub mod role;
116/// ACP protocol schema types - all message types, requests, responses, and supporting types
117pub mod schema;
118/// Utility functions and types
119pub mod util;
120
121pub use capabilities::*;
122
123pub use jsonrpc::{
124 Builder, ByteStreams, Channel, ConnectionContext, ConnectionTo, Dispatch, DynamicHandlerGuard,
125 HandleConnectionClose, HandleDispatchFrom, Handled, INCOMING_TRANSPORT_CLOSED_REASON,
126 IntoHandled, JsonRpcMessage, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse, Lines,
127 NullClose, NullHandler, RawConnectionContext, RawJsonRpcMessage, RawJsonRpcParams, Responder,
128 ResponseRouter, SentRequest, TransportBatch, TransportBatchEntry, TransportFrame,
129 UntypedMessage, is_incoming_transport_closed,
130 run::{ChainRun, NullRun, RunWithConnectionTo},
131};
132pub use jsonrpc::{RequestCancellation, is_cancel_request_notification};
133#[cfg(feature = "unstable_protocol_v2")]
134pub use jsonrpc::{V2Builder, V2ConnectionContext, V2ConnectionTo};
135
136#[cfg(feature = "unstable_protocol_v2")]
137pub use role::acp::{AgentProtocolRouter, ClientProtocolConnector, ProxyProtocolRouter};
138pub use role::{
139 Role, RoleId, UntypedRole,
140 acp::{Agent, Client, Conductor, Proxy},
141};
142
143pub use component::{ConnectTo, DynConnectTo};
144
145/// Implementation details used by the derive macros.
146#[doc(hidden)]
147pub mod __private {
148 pub use serde;
149 pub use serde_json;
150}
151
152// Re-export BoxFuture for implementing SDK traits that return boxed futures.
153pub use futures::future::BoxFuture;
154
155// Re-export commonly used infrastructure types for convenience
156pub use schema::v1::{Error, ErrorCode, Result};
157
158// Re-export derive macros for custom JSON-RPC types
159pub use agent_client_protocol_derive::{JsonRpcNotification, JsonRpcRequest, JsonRpcResponse};
160
161mod session;
162pub use session::*;
163
164#[cfg(not(target_family = "wasm"))]
165mod acp_agent;
166#[cfg(not(target_family = "wasm"))]
167pub use acp_agent::{AcpAgent, AcpAgentConfig, LineDirection};
168
169#[cfg(not(target_family = "wasm"))]
170mod stdio;
171#[cfg(not(target_family = "wasm"))]
172pub use stdio::Stdio;
173
174/// This is a hack that must be given as the final argument of
175/// the MCP server builder's `tool_fn_mut` method when defining tools.
176///
177/// The `agent-client-protocol-rmcp` crate provides the builder this macro is
178/// typically used with.
179/// Look away, lest ye be blinded by its vileness!
180///
181/// Fine, if you MUST know, it's a horrific workaround for not having
182/// [return-type notation](https://github.com/rust-lang/rust/issues/109417)
183/// and for [this !@$#!%! bug](https://github.com/rust-lang/rust/issues/110338).
184/// Trust me, the need for it hurts me more than it hurts you. --nikomatsakis
185#[macro_export]
186macro_rules! tool_fn_mut {
187 () => {
188 |func, params, context| Box::pin(func(params, context))
189 };
190}
191
192/// This is a hack that must be given as the final argument of
193/// the MCP server builder's `tool_fn` method when defining stateless concurrent tools.
194///
195/// The `agent-client-protocol-rmcp` crate provides the builder this macro is
196/// typically used with.
197/// See [`tool_fn_mut!`] for the gory details.
198#[macro_export]
199macro_rules! tool_fn {
200 () => {
201 |func, params, context| Box::pin(func(params, context))
202 };
203}
204
205/// This macro is used for the value of the `to_future_hack` parameter of
206/// [`Builder::on_receive_request`] and [`Builder::on_receive_request_from`].
207///
208/// It expands to `|f, req, responder, cx| Box::pin(f(req, responder, cx))`.
209///
210/// This is needed until [return-type notation](https://github.com/rust-lang/rust/issues/109417)
211/// is stabilized.
212#[macro_export]
213macro_rules! on_receive_request {
214 () => {
215 |f: &mut _, req, responder, cx| Box::pin(f(req, responder, cx))
216 };
217}
218
219/// This macro is used for the value of the `to_future_hack` parameter of
220/// [`Builder::on_receive_notification`] and [`Builder::on_receive_notification_from`].
221///
222/// It expands to `|f, notif, cx| Box::pin(f(notif, cx))`.
223///
224/// This is needed until [return-type notation](https://github.com/rust-lang/rust/issues/109417)
225/// is stabilized.
226#[macro_export]
227macro_rules! on_receive_notification {
228 () => {
229 |f: &mut _, notif, cx| Box::pin(f(notif, cx))
230 };
231}
232
233/// This macro is used for the value of the `to_future_hack` parameter of
234/// [`Builder::on_receive_dispatch`] and [`Builder::on_receive_dispatch_from`].
235///
236/// It expands to `|f, dispatch, cx| Box::pin(f(dispatch, cx))`.
237///
238/// This is needed until [return-type notation](https://github.com/rust-lang/rust/issues/109417)
239/// is stabilized.
240#[macro_export]
241macro_rules! on_receive_dispatch {
242 () => {
243 |f: &mut _, dispatch, cx| Box::pin(f(dispatch, cx))
244 };
245}