From 686915d017c708fa0537a0737d059b7e27fdc336 Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Thu, 23 Jul 2026 15:09:20 +0200 Subject: [PATCH] docs: update conductor and RMCP usage examples --- .../src/conductor.rs | 62 +++++++++---------- .../src/lib.rs | 6 +- src/agent-client-protocol-rmcp/README.md | 12 +++- src/agent-client-protocol-rmcp/src/lib.rs | 11 +++- src/agent-client-protocol/src/lib.rs | 2 +- 5 files changed, 52 insertions(+), 41 deletions(-) diff --git a/src/agent-client-protocol-conductor/src/conductor.rs b/src/agent-client-protocol-conductor/src/conductor.rs index 1f44cdca..6a066706 100644 --- a/src/agent-client-protocol-conductor/src/conductor.rs +++ b/src/agent-client-protocol-conductor/src/conductor.rs @@ -63,52 +63,50 @@ //! Components are instantiated lazily when the first `initialize` request is received //! from the editor. This enables dynamic proxy chain construction based on client capabilities. //! -//! ### Simple Usage +//! ### Fixed Chains //! -//! Pass a Vec of components that implement `Component`: +//! Use [`ProxiesAndAgent`] to assemble a conductor that presents as an agent: //! //! ```ignore -//! let conductor = Conductor::new( +//! use agent_client_protocol_conductor::{ConductorImpl, ProxiesAndAgent}; +//! +//! let conductor = ConductorImpl::new_agent( //! "my-conductor", -//! vec![proxy1, proxy2, agent], -//! None, +//! ProxiesAndAgent::new(agent) +//! .proxy(proxy1) +//! .proxy(proxy2), //! ); //! ``` //! -//! All components are spawned in order when the editor sends the first `initialize` request. +//! A conductor that presents as a proxy takes only its internal proxies; its +//! final successor is supplied when the conductor is connected: //! -//! ### Dynamic Component Selection +//! ```ignore +//! use agent_client_protocol_conductor::ConductorImpl; //! -//! Pass a closure to examine the `InitializeRequest` and dynamically construct the chain: +//! let conductor = ConductorImpl::new_proxy("my-proxy-conductor", vec![proxy]); +//! ``` //! -//! ```ignore -//! let conductor = Conductor::new( -//! "my-conductor", -//! |cx, conductor_tx, init_req| async move { -//! // Examine capabilities -//! let needs_auth = has_auth_capability(&init_req); +//! ### Dynamic Chain Selection //! -//! let mut components = Vec::new(); -//! if needs_auth { -//! components.push(spawn_auth_proxy(&cx, &conductor_tx)?); -//! } -//! components.push(spawn_agent(&cx, &conductor_tx)?); +//! Both constructors also accept an instantiator closure. The closure receives +//! the `InitializeRequest` and returns the possibly modified request together +//! with type-erased connectors for the selected chain: //! -//! // Return (potentially modified) request and component list -//! Ok((init_req, components)) -//! }, -//! None, -//! ); -//! ``` +//! ```ignore +//! use agent_client_protocol::{Client, Conductor, DynConnectTo}; +//! use agent_client_protocol_conductor::ConductorImpl; //! -//! The closure receives: -//! - `cx: &ConnectionTo` - Connection context for spawning components -//! - `conductor_tx: &mpsc::Sender` - Channel for message routing -//! - `init_req: InitializeRequest` - The Initialize request from the editor +//! let conductor = ConductorImpl::new_agent("my-conductor", |init_req| async move { +//! let mut proxies: Vec> = Vec::new(); +//! if has_auth_capability(&init_req) { +//! proxies.push(DynConnectTo::new(make_auth_proxy())); +//! } //! -//! And returns: -//! - Modified `InitializeRequest` to forward downstream -//! - `Vec` of spawned components +//! let agent: DynConnectTo = DynConnectTo::new(make_agent()); +//! Ok((init_req, proxies, agent)) +//! }); +//! ``` use std::sync::Arc; diff --git a/src/agent-client-protocol-conductor/src/lib.rs b/src/agent-client-protocol-conductor/src/lib.rs index 2f379215..3dd22bec 100644 --- a/src/agent-client-protocol-conductor/src/lib.rs +++ b/src/agent-client-protocol-conductor/src/lib.rs @@ -86,9 +86,9 @@ use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitEx /// Wrapper for command-line component lists that can serve as either /// proxies-only (for proxy mode) or proxies+agent (for agent mode). /// -/// This exists because `AcpAgent` implements `Component` for all `L`, -/// so a `Vec` can be used as either a list of proxies or as -/// proxies + final agent depending on the conductor mode. +/// This exists because `AcpAgent` implements `ConnectTo` and +/// `ConnectTo`, so a `Vec` can be used as either a list +/// of proxies or as proxies + final agent depending on the conductor mode. #[derive(Debug)] pub struct CommandLineComponents(pub Vec); diff --git a/src/agent-client-protocol-rmcp/README.md b/src/agent-client-protocol-rmcp/README.md index 450ad9fe..f361405f 100644 --- a/src/agent-client-protocol-rmcp/README.md +++ b/src/agent-client-protocol-rmcp/README.md @@ -21,12 +21,20 @@ ACP-transport MCP servers. Use the `McpServerExt` trait to build an MCP server with tools: ```rust -use agent_client_protocol::mcp_server::McpServer; +use agent_client_protocol::{ConnectTo, mcp_server::McpServer, role::mcp}; use agent_client_protocol_rmcp::McpServerExt; -let server = McpServer::builder("my-tools").build(); +async fn serve( + client_transport: impl ConnectTo, +) -> agent_client_protocol::Result<()> { + let server = McpServer::::builder("my-tools").build(); + server.connect_to(client_transport).await +} ``` +Choosing `mcp::Client` as the counterpart makes this a standalone MCP server +that implements `ConnectTo`. + Or create an MCP server from an rmcp service: ```rust diff --git a/src/agent-client-protocol-rmcp/src/lib.rs b/src/agent-client-protocol-rmcp/src/lib.rs index b40b999f..1a91a54d 100644 --- a/src/agent-client-protocol-rmcp/src/lib.rs +++ b/src/agent-client-protocol-rmcp/src/lib.rs @@ -11,11 +11,16 @@ //! //! Build an MCP server with tools using the extension trait: //! -//! ```ignore -//! use agent_client_protocol::mcp_server::McpServer; +//! ```no_run +//! use agent_client_protocol::{ConnectTo, mcp_server::McpServer, role::mcp}; //! use agent_client_protocol_rmcp::McpServerExt; //! -//! let server = McpServer::builder("my-tools").build(); +//! # async fn serve( +//! # client_transport: impl ConnectTo, +//! # ) -> agent_client_protocol::Result<()> { +//! let server = McpServer::::builder("my-tools").build(); +//! server.connect_to(client_transport).await +//! # } //! ``` //! //! Or create an MCP server from an rmcp service: diff --git a/src/agent-client-protocol/src/lib.rs b/src/agent-client-protocol/src/lib.rs index da13ced6..3a3a4195 100644 --- a/src/agent-client-protocol/src/lib.rs +++ b/src/agent-client-protocol/src/lib.rs @@ -123,7 +123,7 @@ pub mod __private { pub use serde_json; } -// Re-export BoxFuture for implementing Component traits +// Re-export BoxFuture for implementing SDK traits that return boxed futures. pub use futures::future::BoxFuture; // Re-export commonly used infrastructure types for convenience