agent-client-protocol 5.0.0

Core protocol types and traits for the Agent Client Protocol
Documentation
//! Runtime-agnostic MCP server support.
//!
//! This module provides infrastructure for serving MCP directly without tying
//! the core SDK to a particular MCP implementation or async runtime. With the
//! `unstable_mcp_over_acp` feature, the same servers can be attached to ACP
//! session setup requests through the `with_mcp_server` builder methods.
//! Stable protocol v1 and draft protocol v2 both support global proxy
//! attachment and per-session attachment. V2 uses
//! `Proxy.v2().with_mcp_server(...)` or
//! `v2::SessionBuilder::with_mcp_server(...)` for new sessions and
//! `v2::ResumeSessionBuilder::with_mcp_server(...)` for resumed sessions. With
//! `unstable_session_fork`, `v2::ForkSessionBuilder::with_mcp_server(...)`
//! attaches a server to a forked session. V2 attachment additionally requires
//! `unstable_protocol_v2`.
//!
//! ## Building MCP servers with tools
//!
//! The opt-in `schemars` feature provides `McpTool`, `McpToolRegistry`
//! and its metadata types, and the `tool_fn` / `tool_fn_mut` functions for
//! automatically generating JSON Schemas from Rust input and output types.
//! The `agent-client-protocol-rmcp` crate provides the builder APIs for MCP
//! tools backed by the `rmcp` crate and enables this feature.
//!
//! Custom servers using [`crate::mcp_server::McpServerConnect`],
//! [`crate::mcp_server::McpServer`], and the connection types remain available
//! without `schemars`, including ACP attachment when
//! `unstable_mcp_over_acp` is enabled.
//!
//! ## Custom MCP Server Implementations
//!
//! You can implement [`crate::mcp_server::McpServerConnect`] to create custom MCP
//! servers:
//!
//! ```rust,ignore
//! use agent_client_protocol::mcp_server::{McpConnectionTo, McpServer, McpServerConnect};
//! use agent_client_protocol::{DynConnectTo, NullRun, Role, role};
//!
//! struct MyCustomServer;
//!
//! impl<R: Role> McpServerConnect<R> for MyCustomServer {
//!     fn name(&self) -> String {
//!         "my-custom-server".to_string()
//!     }
//!
//!     fn connect(&self, cx: McpConnectionTo<R>) -> DynConnectTo<role::mcp::Client> {
//!         // Return a component that serves MCP requests
//!         DynConnectTo::new(my_mcp_component(cx))
//!     }
//! }
//!
//! let server = McpServer::new(MyCustomServer, NullRun);
//! ```

#[cfg(feature = "unstable_mcp_over_acp")]
mod active_session;
mod connect;
mod context;
#[cfg(feature = "schemars")]
mod registry;
mod server;
#[cfg(feature = "unstable_mcp_over_acp")]
mod service;
#[cfg(feature = "schemars")]
mod tool;
#[cfg(feature = "schemars")]
mod tool_fn;

pub use connect::McpServerConnect;
pub use context::{McpConnectionContext, McpConnectionTo};
#[cfg(feature = "schemars")]
#[cfg_attr(docsrs, doc(cfg(feature = "schemars")))]
pub use registry::{
    McpToolMetadata, McpToolRegistry, McpToolSchema, RegisteredMcpTool, UnknownToolError,
};
pub use server::McpServer;
#[cfg(feature = "unstable_mcp_over_acp")]
pub use service::{
    McpOperationCancellation, McpOutcome, McpRequest, McpRequestContext, McpService,
};

/// `-33000`: an MCP-over-ACP binding resource limit was exceeded.
#[cfg(feature = "unstable_mcp_over_acp")]
pub const MCP_RESOURCE_LIMIT_EXCEEDED: crate::ErrorCode = crate::ErrorCode::new(-33000);
/// `-33001`: the declared MCP server registration is unavailable.
#[cfg(feature = "unstable_mcp_over_acp")]
pub const MCP_SERVER_UNAVAILABLE: crate::ErrorCode = crate::ErrorCode::new(-33001);
/// `-33002`: the MCP backend or transport failed without a valid MCP outcome.
#[cfg(feature = "unstable_mcp_over_acp")]
pub const MCP_BACKEND_FAILURE: crate::ErrorCode = crate::ErrorCode::new(-33002);
#[cfg(feature = "schemars")]
#[cfg_attr(docsrs, doc(cfg(feature = "schemars")))]
pub use tool::McpTool;
#[cfg(feature = "schemars")]
#[cfg_attr(docsrs, doc(cfg(feature = "schemars")))]
pub use tool_fn::{tool_fn, tool_fn_mut};

/// Expands to the first block when this crate was built with
/// `unstable_mcp_over_acp`, and to the `else` block otherwise.
///
/// MCP integrations in other crates use this to pick the native
/// MCP-over-ACP path from this crate's features rather than their own, so
/// feature unification cannot leave them on the per-request fallback while
/// ACP attachment is available. Hidden from the docs, but
/// `agent-client-protocol-rmcp` depends on it, so it is a stable cross-crate
/// contract for the 5.x line: renaming it or changing its syntax is a
/// breaking change.
#[cfg(feature = "unstable_mcp_over_acp")]
#[doc(hidden)]
#[macro_export]
macro_rules! __if_mcp_over_acp {
    ({ $($then:tt)* } else { $($else:tt)* }) => {
        $($then)*
    };
}

/// Expands to the first block when this crate was built with
/// `unstable_mcp_over_acp`, and to the `else` block otherwise.
///
/// MCP integrations in other crates use this to pick the native
/// MCP-over-ACP path from this crate's features rather than their own, so
/// feature unification cannot leave them on the per-request fallback while
/// ACP attachment is available. Hidden from the docs, but
/// `agent-client-protocol-rmcp` depends on it, so it is a stable cross-crate
/// contract for the 5.x line: renaming it or changing its syntax is a
/// breaking change.
#[cfg(not(feature = "unstable_mcp_over_acp"))]
#[doc(hidden)]
#[macro_export]
macro_rules! __if_mcp_over_acp {
    ({ $($then:tt)* } else { $($else:tt)* }) => {
        $($else)*
    };
}