forked from paiml/rust-mcp-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path02_server_basic.rs
More file actions
125 lines (108 loc) · 3.7 KB
/
02_server_basic.rs
File metadata and controls
125 lines (108 loc) · 3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//! Example: Basic MCP server with tool support
//!
//! This example demonstrates:
//! - Creating a server with tools
//! - Implementing tool handlers
//! - Running server with stdio transport
use async_trait::async_trait;
use pmcp::types::capabilities::ServerCapabilities;
use pmcp::{Server, ToolHandler};
use serde::{Deserialize, Serialize};
use serde_json::Value;
// Define input/output types for better type safety
#[derive(Debug, Deserialize)]
struct CalculatorArgs {
operation: String,
a: f64,
b: f64,
}
#[derive(Debug, Serialize)]
struct CalculatorResult {
result: f64,
expression: String,
}
// Calculator tool implementation
struct CalculatorTool;
#[async_trait]
impl ToolHandler for CalculatorTool {
async fn handle(&self, args: Value, _extra: pmcp::RequestHandlerExtra) -> pmcp::Result<Value> {
// Parse arguments
let params: CalculatorArgs = serde_json::from_value(args)
.map_err(|e| pmcp::Error::validation(format!("Invalid arguments: {}", e)))?;
// Perform calculation
let result = match params.operation.as_str() {
"add" => params.a + params.b,
"subtract" => params.a - params.b,
"multiply" => params.a * params.b,
"divide" => {
if params.b == 0.0 {
return Err(pmcp::Error::validation("Division by zero"));
}
params.a / params.b
},
op => {
return Err(pmcp::Error::validation(format!(
"Unknown operation: {}",
op
)))
},
};
// Return result
Ok(serde_json::to_value(CalculatorResult {
result,
expression: format!(
"{} {} {} = {}",
params.a, params.operation, params.b, result
),
})?)
}
}
// String manipulation tool
struct StringTool;
#[async_trait]
impl ToolHandler for StringTool {
async fn handle(&self, args: Value, _extra: pmcp::RequestHandlerExtra) -> pmcp::Result<Value> {
let text = args["text"]
.as_str()
.ok_or_else(|| pmcp::Error::validation("text field required"))?;
let operation = args["operation"]
.as_str()
.ok_or_else(|| pmcp::Error::validation("operation field required"))?;
let result = match operation {
"uppercase" => text.to_uppercase(),
"lowercase" => text.to_lowercase(),
"reverse" => text.chars().rev().collect(),
"length" => text.len().to_string(),
_ => return Err(pmcp::Error::validation("Unknown operation")),
};
Ok(serde_json::json!({
"original": text,
"result": result,
"operation": operation
}))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize logging
tracing_subscriber::fmt()
.with_env_filter("pmcp=info")
.init();
println!("=== MCP Server Example ===");
println!("Starting server with calculator and string tools...\n");
// Build server with tools
let server = Server::builder()
.name("example-tools-server")
.version("1.0.0")
.capabilities(ServerCapabilities::tools_only())
.tool("calculator", CalculatorTool)
.tool("string_manipulator", StringTool)
.build()?;
println!("Server ready! Listening on stdio...");
println!("Available tools:");
println!(" - calculator: Basic math operations (add, subtract, multiply, divide)");
println!(" - string_manipulator: String operations (uppercase, lowercase, reverse, length)");
// Run server
server.run_stdio().await?;
Ok(())
}