mcpkit_rs/lib.rs
1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![cfg_attr(docsrs, allow(unused_attributes))]
3//! A WebAssembly-focused fork of the Rust SDK for the Model Context Protocol (MCP).
4//!
5//! The MCP is a protocol that allows AI assistants to communicate with other
6//! services. `mcpkit-rs` is a WebAssembly-enhanced fork of the official Rust
7//! implementation, extending it with WASM runtime integration for tool execution.
8//!
9//! There are two ways in which the library can be used, namely to build a
10//! server or to build a client.
11//!
12//! ## Server
13//!
14//! A server is a service that exposes capabilities. For example, a common
15//! use-case is for the server to make multiple tools available to clients such
16//! as Claude Desktop or the Cursor IDE.
17//!
18//! For example, to implement a server that has a tool that can count, you would
19//! make an object for that tool and add an implementation with the `#[tool_router]` macro:
20//!
21//! ```rust
22//! use std::sync::Arc;
23//! use mcpkit_rs::{ErrorData as McpError, model::*, tool, tool_router, handler::server::tool::ToolRouter};
24//! use tokio::sync::Mutex;
25//!
26//! #[derive(Clone)]
27//! pub struct Counter {
28//! counter: Arc<Mutex<i32>>,
29//! tool_router: ToolRouter<Self>,
30//! }
31//!
32//! #[tool_router]
33//! impl Counter {
34//! fn new() -> Self {
35//! Self {
36//! counter: Arc::new(Mutex::new(0)),
37//! tool_router: Self::tool_router(),
38//! }
39//! }
40//!
41//! #[tool(description = "Increment the counter by 1")]
42//! async fn increment(&self) -> Result<CallToolResult, McpError> {
43//! let mut counter = self.counter.lock().await;
44//! *counter += 1;
45//! Ok(CallToolResult::success(vec![Content::text(
46//! counter.to_string(),
47//! )]))
48//! }
49//! }
50//! ```
51//!
52//! ### Structured Output
53//!
54//! Tools can also return structured JSON data with schemas. Use the [`Json`] wrapper:
55//!
56//! ```rust,no_run
57//! # use mcpkit_rs::{tool, tool_router, handler::server::{tool::ToolRouter, wrapper::Parameters}, Json};
58//! # use schemars::JsonSchema;
59//! # use serde::{Serialize, Deserialize};
60//! #
61//! #[derive(Serialize, Deserialize, JsonSchema)]
62//! struct CalculationRequest {
63//! a: i32,
64//! b: i32,
65//! operation: String,
66//! }
67//!
68//! #[derive(Serialize, Deserialize, JsonSchema)]
69//! struct CalculationResult {
70//! result: i32,
71//! operation: String,
72//! }
73//!
74//! # #[derive(Clone)]
75//! # struct Calculator {
76//! # tool_router: ToolRouter<Self>,
77//! # }
78//! #
79//! # #[tool_router]
80//! # impl Calculator {
81//! #[tool(name = "calculate", description = "Perform a calculation")]
82//! async fn calculate(&self, params: Parameters<CalculationRequest>) -> Result<Json<CalculationResult>, String> {
83//! let result = match params.0.operation.as_str() {
84//! "add" => params.0.a + params.0.b,
85//! "multiply" => params.0.a * params.0.b,
86//! _ => return Err("Unknown operation".to_string()),
87//! };
88//!
89//! Ok(Json(CalculationResult { result, operation: params.0.operation }))
90//! }
91//! # }
92//! ```
93//!
94//! The `#[tool]` macro automatically generates an output schema from the `CalculationResult` type.
95//!
96//! Next also implement [ServerHandler] for your server type and start the server inside
97//! `main` by calling `.serve(...)`. See the examples directory in the repository for more information.
98//!
99//! ## Client
100//!
101//! A client can be used to interact with a server. Clients can be used to get a
102//! list of the available tools and to call them. For example, we can `uv` to
103//! start a MCP server in Python and then list the tools and call `git status`
104//! as follows:
105//!
106//! ```rust
107//! use anyhow::Result;
108//! use mcpkit_rs::{model::CallToolRequestParams, service::ServiceExt};
109//! #[cfg(feature = "transport-child-process")]
110//! #[cfg_attr(docsrs, doc(cfg(feature = "transport-child-process")))]
111//! use mcpkit_rs::transport::{TokioChildProcess, ConfigureCommandExt};
112//! use tokio::process::Command;
113//!
114//! #[cfg(feature = "transport-child-process")]
115//! #[cfg_attr(docsrs, doc(cfg(feature = "transport-child-process")))]
116//! async fn client() -> Result<()> {
117//! let service = ().serve(TokioChildProcess::new(Command::new("uvx").configure(|cmd| {
118//! cmd.arg("mcp-server-git");
119//! }))?).await?;
120//!
121//! // Initialize
122//! let server_info = service.peer_info();
123//! println!("Connected to server: {server_info:#?}");
124//!
125//! // List tools
126//! let tools = service.list_tools(Default::default()).await?;
127//! println!("Available tools: {tools:#?}");
128//!
129//! // Call tool 'git_status' with arguments = {"repo_path": "."}
130//! let tool_result = service
131//! .call_tool(CallToolRequestParams {
132//! meta: None,
133//! name: "git_status".into(),
134//! arguments: serde_json::json!({ "repo_path": "." }).as_object().cloned(),
135//! task: None,
136//! })
137//! .await?;
138//! println!("Tool result: {tool_result:#?}");
139//!
140//! service.cancel().await?;
141//! Ok(())
142//! }
143//! ```
144#![doc = include_str!("../README.md")]
145
146mod error;
147#[allow(deprecated)]
148pub use error::{Error, ErrorData, RmcpError};
149
150/// Basic data types in MCP specification
151pub mod model;
152
153#[cfg(any(feature = "client", feature = "server"))]
154#[cfg_attr(docsrs, doc(cfg(any(feature = "client", feature = "server"))))]
155pub mod service;
156/// WASM tool execution support and manifest types
157#[cfg(feature = "client")]
158#[cfg_attr(docsrs, doc(cfg(feature = "client")))]
159pub use handler::client::ClientHandler;
160#[cfg(feature = "server")]
161#[cfg_attr(docsrs, doc(cfg(feature = "server")))]
162pub use handler::server::ServerHandler;
163#[cfg(feature = "policy")]
164#[cfg_attr(docsrs, doc(cfg(feature = "policy")))]
165pub use handler::server::policy::PolicyEnabledServer;
166#[cfg(feature = "server")]
167#[cfg_attr(docsrs, doc(cfg(feature = "server")))]
168pub use handler::server::wrapper::Json;
169#[cfg(any(feature = "client", feature = "server"))]
170#[cfg_attr(docsrs, doc(cfg(any(feature = "client", feature = "server"))))]
171pub use service::{Peer, Service, ServiceError, ServiceExt};
172#[cfg(feature = "client")]
173#[cfg_attr(docsrs, doc(cfg(feature = "client")))]
174pub use service::{RoleClient, serve_client};
175#[cfg(feature = "server")]
176#[cfg_attr(docsrs, doc(cfg(feature = "server")))]
177pub use service::{RoleServer, serve_server};
178
179pub mod handler;
180#[cfg(feature = "server")]
181#[cfg_attr(docsrs, doc(cfg(feature = "server")))]
182pub mod task_manager;
183pub mod transport;
184
185#[cfg(feature = "config")]
186#[cfg_attr(docsrs, doc(cfg(feature = "config")))]
187pub mod config;
188
189#[cfg(feature = "wasm-tools")]
190#[cfg_attr(docsrs, doc(cfg(feature = "wasm-tools")))]
191pub mod wasm;
192
193#[cfg(feature = "distribution")]
194#[cfg_attr(docsrs, doc(cfg(feature = "distribution")))]
195pub mod bundle;
196
197// re-export
198#[cfg(all(feature = "macros", feature = "server"))]
199#[cfg_attr(docsrs, doc(cfg(all(feature = "macros", feature = "server"))))]
200pub use mcpkit_rs_macros::*;
201#[cfg(all(feature = "macros", feature = "server"))]
202#[cfg_attr(docsrs, doc(cfg(all(feature = "macros", feature = "server"))))]
203pub use pastey::paste;
204#[cfg(feature = "schemars")]
205#[cfg_attr(docsrs, doc(cfg(feature = "schemars")))]
206pub use schemars;
207#[cfg(feature = "macros")]
208#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
209pub use serde;
210#[cfg(feature = "macros")]
211#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
212pub use serde_json;