use async_trait::async_trait;
use mcp_protocol_sdk::prelude::*;
use serde_json::{Value, json};
use std::collections::HashMap;
struct CalculatorHandler;
#[async_trait]
impl ToolHandler for CalculatorHandler {
async fn call(&self, arguments: HashMap<String, Value>) -> McpResult<ToolResult> {
let a = arguments
.get("a")
.and_then(|v| v.as_f64())
.ok_or_else(|| McpError::Validation("Missing 'a' parameter".to_string()))?;
let b = arguments
.get("b")
.and_then(|v| v.as_f64())
.ok_or_else(|| McpError::Validation("Missing 'b' parameter".to_string()))?;
let result = a + b;
Ok(ToolResult {
content: vec![Content::text(result.to_string())],
is_error: None,
structured_content: Some(json!({
"operation": "addition",
"operands": [a, b],
"result": result
})),
meta: None,
})
}
}
fn test_server_creation() -> Result<(), Box<dyn std::error::Error>> {
let _server = McpServer::new("my-calculator".to_string(), "1.0.0".to_string());
Ok(())
}
fn test_tool_builder() -> McpResult<()> {
use mcp_protocol_sdk::core::tool::ToolBuilder;
let _tool = ToolBuilder::new("enhanced_calculator")
.description("Advanced calculator with validation")
.version("1.0.0")
.schema(json!({
"type": "object",
"properties": {
"a": {"type": "number"},
"b": {"type": "number"}
},
"required": ["a", "b"]
}))
.strict_validation()
.read_only()
.idempotent()
.cacheable()
.build(CalculatorHandler)?;
Ok(())
}
#[cfg(feature = "http")]
fn test_client_config() -> Result<(), Box<dyn std::error::Error>> {
use mcp_protocol_sdk::client::McpClient;
use mcp_protocol_sdk::transport::traits::TransportConfig;
let _config = TransportConfig {
connect_timeout_ms: Some(5_000),
read_timeout_ms: Some(30_000),
write_timeout_ms: Some(30_000),
max_message_size: Some(1024 * 1024), keep_alive_ms: Some(60_000), compression: true,
headers: std::collections::HashMap::new(),
};
let _client = McpClient::new("my-client".to_string(), "1.0.0".to_string());
Ok(())
}
struct EchoHandler;
#[async_trait]
impl ToolHandler for EchoHandler {
async fn call(&self, arguments: HashMap<String, Value>) -> McpResult<ToolResult> {
let message = arguments
.get("message")
.and_then(|v| v.as_str())
.unwrap_or("Hello, World!");
Ok(ToolResult {
content: vec![Content::text(message.to_string())],
is_error: None,
structured_content: None,
meta: None,
})
}
}
async fn test_async_server_setup() -> McpResult<()> {
let mut server = McpServer::new("test-server".to_string(), "1.0.0".to_string());
server
.add_tool(
"echo".to_string(),
Some("Echo a message".to_string()),
json!({
"type": "object",
"properties": {
"message": {"type": "string"}
},
"required": ["message"]
}),
EchoHandler,
)
.await?;
Ok(())
}
fn test_schema_types() -> Result<(), Box<dyn std::error::Error>> {
use mcp_protocol_sdk::protocol::types::*;
let tool_info = ToolInfo {
name: "calculator".to_string(),
description: Some("Performs mathematical operations".to_string()),
input_schema: ToolInputSchema {
schema_type: "object".to_string(),
properties: Some(std::collections::HashMap::new()),
required: Some(vec!["a".to_string(), "b".to_string()]),
additional_properties: std::collections::HashMap::new(),
},
annotations: None,
title: None,
meta: None,
};
let _json = serde_json::to_value(&tool_info)?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_all_readme_examples_compile() {
test_server_creation().expect("Server creation should work");
test_tool_builder().expect("ToolBuilder should work");
#[cfg(feature = "http")]
test_client_config().expect("Client config should work");
test_schema_types().expect("Schema types should work");
}
#[tokio::test]
async fn test_async_examples() {
test_async_server_setup()
.await
.expect("Async server setup should work");
}
#[tokio::test]
async fn test_tool_handler_execution() {
let handler = CalculatorHandler;
let mut args = HashMap::new();
args.insert("a".to_string(), json!(5.0));
args.insert("b".to_string(), json!(3.0));
let result = handler
.call(args)
.await
.expect("Tool should execute successfully");
assert_eq!(result.content.len(), 1);
if let Content::Text { text, .. } = &result.content[0] {
assert_eq!(text, "8");
} else {
panic!("Expected text content");
}
}
}
fn main() {
println!("All README examples compile successfully!");
test_server_creation().expect("Server creation test failed");
test_tool_builder().expect("ToolBuilder test failed");
test_schema_types().expect("Schema types test failed");
#[cfg(feature = "http")]
test_client_config().expect("Client config test failed");
println!("✅ All README examples are working!");
}