use anyhow::Result; use rmcp::{ ServerHandler, ServiceExt, handler::server::{router::tool::ToolRouter, wrapper::Parameters}, model::{ServerCapabilities, ServerInfo}, schemars, tool, tool_handler, tool_router, transport::stdio, }; use tracing_subscriber::{self, EnvFilter}; // --- Calculator types --- #[derive(Debug, serde::Deserialize, schemars::JsonSchema)] pub struct SumRequest { #[schemars(description = "the left hand side number")] pub a: i32, pub b: i32, } #[derive(Debug, serde::Deserialize, schemars::JsonSchema)] pub struct SubRequest { #[schemars(description = "the left hand side number")] pub a: i32, #[schemars(description = "the right hand side number")] pub b: i32, } // --- Calculator server --- #[derive(Debug, Clone)] pub struct Calculator { tool_router: ToolRouter, } #[tool_router] impl Calculator { pub fn new() -> Self { Self { tool_router: Self::tool_router(), } } #[tool(description = "Calculate the sum of two numbers")] fn sum(&self, Parameters(SumRequest { a, b }): Parameters) -> String { (a + b).to_string() } #[tool(description = "Calculate the difference of two numbers")] fn sub(&self, Parameters(SubRequest { a, b }): Parameters) -> String { (a - b).to_string() } } #[tool_handler] impl ServerHandler for Calculator { fn get_info(&self) -> ServerInfo { ServerInfo::new(ServerCapabilities::builder().enable_tools().build()) .with_instructions("A simple calculator".to_string()) } } // --- Main --- #[tokio::main] async fn main() -> Result<()> { tracing_subscriber::fmt() .with_env_filter(EnvFilter::from_default_env().add_directive(tracing::Level::DEBUG.into())) .with_writer(std::io::stderr) .with_ansi(false) .init(); tracing::info!("Starting Calculator MCP server"); let service = Calculator::new().serve(stdio()).await.inspect_err(|e| { tracing::error!("serving error: {:?}", e); })?; service.waiting().await?; Ok(()) }