mcp_server_complete_example/
mcp_server_complete_example.rs1use rust_agent::{McpServer, Tool};
3use std::sync::Arc;
4use anyhow::Error;
5use std::pin::Pin;
6
7pub struct WeatherTool {
9 name: String,
10 description: String,
11}
12
13impl WeatherTool {
14 pub fn new() -> Self {
15 Self {
16 name: "get_weather".to_string(),
17 description: "Get the weather information for a specified city. For example: 'What's the weather like in Beijing?'".to_string(),
18 }
19 }
20}
21
22impl Tool for WeatherTool {
23 fn name(&self) -> &str {
24 &self.name
25 }
26
27 fn description(&self) -> &str {
28 &self.description
29 }
30
31 fn invoke(&self, input: &str) -> Pin<Box<dyn std::future::Future<Output = Result<String, Error>> + Send + '_>> {
32 let city = match serde_json::from_str::<serde_json::Value>(input) {
34 Ok(json_value) => {
35 if let Some(city_value) = json_value.get("city") {
37 city_value.as_str().unwrap_or(input).to_string()
38 } else {
39 input.to_string()
41 }
42 },
43 Err(_) => {
44 input.to_string()
46 }
47 };
48
49 Box::pin(async move {
50 let weather_data = match city.to_lowercase().as_str() {
52 "beijing" => "Sunny, 25°C",
53 "shanghai" => "Cloudy, 22°C",
54 "guangzhou" => "Rainy, 28°C",
55 _ => "Weather data not available",
56 };
57
58 Ok(format!("Weather in {}: {}", city, weather_data))
59 })
60 }
61
62 fn as_any(&self) -> &dyn std::any::Any {
63 self
64 }
65}
66
67pub struct CalculatorTool {
69 name: String,
70 description: String,
71}
72
73impl CalculatorTool {
74 pub fn new() -> Self {
75 Self {
76 name: "simple_calculate".to_string(),
77 description: "Perform simple mathematical calculations. Input should be a mathematical expression with numbers and operators (+, -, *, /). For example: '15.5 + 24.3'".to_string(),
78 }
79 }
80}
81
82impl Tool for CalculatorTool {
83 fn name(&self) -> &str {
84 &self.name
85 }
86
87 fn description(&self) -> &str {
88 &self.description
89 }
90
91 fn invoke(&self, input: &str) -> Pin<Box<dyn std::future::Future<Output = Result<String, Error>> + Send + '_>> {
92 let expression = match serde_json::from_str::<serde_json::Value>(input) {
94 Ok(json_value) => {
95 if let Some(expr_value) = json_value.get("expression") {
97 expr_value.as_str().unwrap_or(input).to_string()
98 } else {
99 input.to_string()
101 }
102 },
103 Err(_) => {
104 input.to_string()
106 }
107 };
108
109 Box::pin(async move {
110 let expression = expression.replace(" ", "");
112
113 for op_char in ["+", "-", "*", "/"].iter() {
115 if let Some(pos) = expression.find(op_char) {
117 if *op_char == "-" && pos == 0 {
119 if let Some(next_pos) = expression[1..].find("-") {
121 let actual_pos = next_pos + 1;
123 let left_str = &expression[0..actual_pos];
124 let right_str = &expression[actual_pos + 1..];
125
126 if let (Ok(left), Ok(right)) = (left_str.parse::<f64>(), right_str.parse::<f64>()) {
127 let result = left - right;
128 return Ok(format!("Result: {} (from {} - {})", result, left, right));
129 } else {
130 return Ok(format!("Calculation error: Invalid numbers for subtraction"));
131 }
132 } else {
133 if let Ok(num) = expression.parse::<f64>() {
135 return Ok(format!("Result: {}", num));
136 } else {
137 return Ok(format!("Calculation error: Invalid number"));
138 }
139 }
140 }
141
142 let left_str = &expression[0..pos];
144 let right_str = &expression[pos + 1..];
145
146 let left_result = left_str.parse::<f64>();
148 let right_result = right_str.parse::<f64>();
149
150 match (left_result, right_result) {
151 (Ok(left), Ok(right)) => {
152 let result = match *op_char {
154 "+" => left + right,
155 "-" => left - right,
156 "*" => left * right,
157 "/" => {
158 if right == 0.0 {
159 return Ok(format!("Calculation error: Division by zero"));
160 }
161 left / right
162 },
163 _ => unreachable!()
164 };
165 return Ok(format!("Result: {} (from {} {} {})", result, left, op_char, right));
166 },
167 _ => {
168 continue;
170 }
171 }
172 }
173 }
174
175 if let Ok(number) = expression.parse::<f64>() {
177 return Ok(format!("Result: {}", number));
178 }
179
180 Ok(format!("Calculation error: Failed to parse expression: {}", expression))
182 })
183 }
184
185 fn as_any(&self) -> &dyn std::any::Any {
186 self
187 }
188}
189
190#[tokio::main]
191async fn main() -> Result<(), Box<dyn std::error::Error>> {
192 println!("=== Rust Agent Complete MCP Server Example ===");
193
194 let server = rust_agent::SimpleMcpServer::new().with_address("127.0.0.1:6000".to_string());
196
197 let weather_tool = WeatherTool::new();
199 let calculator_tool = CalculatorTool::new();
200
201 server.register_tool(Arc::new(weather_tool))?;
203 server.register_tool(Arc::new(calculator_tool))?;
204
205 server.start("127.0.0.1:6000").await?;
207
208 println!("MCP服务器已启动,地址: 127.0.0.1:6000");
209 println!("MCP Server端工具:");
210 println!(" 1. get_weather: Get the weather information for a specified city. For example: 'What's the weather like in Beijing?'");
211 println!(" 2. simple_calculate: Perform simple mathematical calculations. Input should be a mathematical expression with numbers and operators (+, -, *, /). For example: '15.5 + 24.3'");
212 println!("服务器正在运行中,按 Ctrl+C 停止服务器");
213
214 #[cfg(unix)]
218 let terminate = async {
219 tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
220 .unwrap()
221 .recv()
222 .await;
223 };
224
225 #[cfg(not(unix))]
226 let terminate = std::future::pending::<()>();
227
228 tokio::select! {
229 _ = tokio::signal::ctrl_c() => {
230 println!("收到 Ctrl+C 信号,正在停止服务器...");
231 },
232 _ = terminate => {
233 println!("收到终止信号,正在停止服务器...");
234 },
235 }
236
237 println!("MCP服务器已停止");
240
241 Ok(())
242}