mcp_server_complete_example/
mcp_server_complete_example.rs

1// 完整的MCP服务器示例,展示实际工具的实现
2use rust_agent::{McpServer, Tool};
3use std::sync::Arc;
4use anyhow::Error;
5use std::pin::Pin;
6
7// 天气工具实现
8pub 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        // 解析输入参数,客户端可能发送JSON格式的参数
33        let city = match serde_json::from_str::<serde_json::Value>(input) {
34            Ok(json_value) => {
35                // 如果输入是JSON格式,尝试提取city字段
36                if let Some(city_value) = json_value.get("city") {
37                    city_value.as_str().unwrap_or(input).to_string()
38                } else {
39                    // 如果没有city字段,使用整个输入作为城市名
40                    input.to_string()
41                }
42            },
43            Err(_) => {
44                // 如果不是JSON格式,直接使用输入作为城市名
45                input.to_string()
46            }
47        };
48        
49        Box::pin(async move {
50            // 模拟天气API调用
51            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
67// 计算工具实现
68pub 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        // 解析输入参数,客户端可能发送不同格式的参数
93        let expression = match serde_json::from_str::<serde_json::Value>(input) {
94            Ok(json_value) => {
95                // 如果输入是JSON格式,尝试提取expression字段
96                if let Some(expr_value) = json_value.get("expression") {
97                    expr_value.as_str().unwrap_or(input).to_string()
98                } else {
99                    // 如果没有expression字段,尝试将整个输入作为表达式处理
100                    input.to_string()
101                }
102            },
103            Err(_) => {
104                // 如果不是有效的JSON,将整个输入作为表达式处理
105                input.to_string()
106            }
107        };
108        
109        Box::pin(async move {
110            // 参考本地工具实现,创建一个更健壮的解析器
111            let expression = expression.replace(" ", "");
112            
113            // 尝试匹配不同的运算符
114            for op_char in ["+", "-", "*", "/"].iter() {
115                // 使用find方法而不是contains,这样可以获取操作符的位置
116                if let Some(pos) = expression.find(op_char) {
117                    // 特殊处理减号:确保不是在开头作为负号使用
118                    if *op_char == "-" && pos == 0 {
119                        // 检查是否还有其他减号
120                        if let Some(next_pos) = expression[1..].find("-") {
121                            // 有另一个减号,这是减法运算
122                            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                            // 只有一个减号且在开头,这是一个负数
134                            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                    // 提取左右操作数
143                    let left_str = &expression[0..pos];
144                    let right_str = &expression[pos + 1..];
145                    
146                    // 转换为浮点数
147                    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                            // 执行相应的运算
153                            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                            // 解析失败,继续尝试其他操作符
169                            continue;
170                        }
171                    }
172                }
173            }
174            
175            // 如果没有找到运算符,尝试将整个表达式解析为数字
176            if let Ok(number) = expression.parse::<f64>() {
177                return Ok(format!("Result: {}", number));
178            }
179            
180            // 如果所有尝试都失败了,返回错误
181            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    // 创建MCP服务器实例
195    let server = rust_agent::SimpleMcpServer::new().with_address("127.0.0.1:6000".to_string());
196    
197    // 创建实际的工具实现
198    let weather_tool = WeatherTool::new();
199    let calculator_tool = CalculatorTool::new();
200    
201    // 注册工具
202    server.register_tool(Arc::new(weather_tool))?;
203    server.register_tool(Arc::new(calculator_tool))?;
204    
205    // 启动服务器
206    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    // 保持服务器持续运行
215    // tokio::time::sleep(tokio::time::Duration::from_secs(30)).await;
216    // 这里我们使用 tokio::signal 来等待 Ctrl+C 信号
217    #[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    // 停止服务器
238    // server.stop().await?;
239    println!("MCP服务器已停止");
240    
241    Ok(())
242}