run_code_rmcp/mcp/
mcp_server.rs

1use anyhow::Result;
2use rmcp::{
3    ErrorData as McpError, ServerHandler,
4    handler::server::wrapper::Parameters,
5    model::{
6        CallToolResult, Content, Implementation, ProtocolVersion, ServerCapabilities, ServerInfo,
7    },
8    tool, tool_handler, tool_router,
9};
10use serde::Deserialize;
11use serde_json::json;
12
13use crate::model::{CodeExecutor, LanguageScript};
14
15/// 代码执行请求参数
16#[derive(Debug, Deserialize, schemars::JsonSchema)]
17pub struct CodeRunRequest {
18    #[schemars(description = "要执行的代码")]
19    pub code: String,
20
21    #[schemars(description = "可选的执行参数")]
22    pub params: Option<serde_json::Value>,
23}
24
25/// 代码执行工具服务
26#[derive(Debug, Clone, Default)]
27pub struct CodeRunnerService;
28
29#[tool_router]
30impl CodeRunnerService {
31    #[tool(description = "执行JavaScript代码并返回结果")]
32    async fn run_javascript(
33        &self,
34        request: Parameters<CodeRunRequest>,
35    ) -> Result<CallToolResult, McpError> {
36        let request = request.0;
37        match CodeExecutor::execute_with_params_compat(
38            &request.code,
39            LanguageScript::Js,
40            request.params,
41        )
42        .await
43        {
44            Ok(result) => {
45                if result.success {
46                    let content = Content::json(json!({
47                        "result": result.result,
48                        "logs": result.logs,
49                        "success": true
50                    }))?;
51                    Ok(CallToolResult::success(vec![content]))
52                } else {
53                    let content = Content::json(json!({
54                        "success": false,
55                        "error": result.error,
56                        "logs": result.logs
57                    }))?;
58                    Ok(CallToolResult::success(vec![content]))
59                }
60            }
61            Err(err) => {
62                let content = Content::json(json!({
63                    "success": false,
64                    "error": err.to_string(),
65                    "logs": []
66                }))?;
67                Ok(CallToolResult::success(vec![content]))
68            }
69        }
70    }
71
72    #[tool(description = "执行TypeScript代码并返回结果")]
73    async fn run_typescript(
74        &self,
75        request: Parameters<CodeRunRequest>,
76    ) -> Result<CallToolResult, McpError> {
77        let request = request.0;
78        match CodeExecutor::execute_with_params_compat(
79            &request.code,
80            LanguageScript::Ts,
81            request.params,
82        )
83        .await
84        {
85            Ok(result) => {
86                if result.success {
87                    let content = Content::json(json!({
88                        "result": result.result,
89                        "logs": result.logs,
90                        "success": true
91                    }))?;
92                    Ok(CallToolResult::success(vec![content]))
93                } else {
94                    let content = Content::json(json!({
95                        "success": false,
96                        "error": result.error,
97                        "logs": result.logs
98                    }))?;
99                    Ok(CallToolResult::success(vec![content]))
100                }
101            }
102            Err(err) => {
103                let content = Content::json(json!({
104                    "success": false,
105                    "error": err.to_string(),
106                    "logs": []
107                }))?;
108                Ok(CallToolResult::success(vec![content]))
109            }
110        }
111    }
112
113    #[rmcp::tool(description = "执行Python代码并返回结果")]
114    async fn run_python(
115        &self,
116        request: Parameters<CodeRunRequest>,
117    ) -> Result<CallToolResult, McpError> {
118        let request = request.0;
119        match CodeExecutor::execute_with_params_compat(
120            &request.code,
121            LanguageScript::Python,
122            request.params,
123        )
124        .await
125        {
126            Ok(result) => {
127                if result.success {
128                    let content = Content::json(json!({
129                        "result": result.result,
130                        "logs": result.logs,
131                        "success": true
132                    }))?;
133                    Ok(CallToolResult::success(vec![content]))
134                } else {
135                    let content = Content::json(json!({
136                        "success": false,
137                        "error": result.error,
138                        "logs": result.logs
139                    }))?;
140                    Ok(CallToolResult::success(vec![content]))
141                }
142            }
143            Err(err) => {
144                let content = Content::json(json!({
145                    "success": false,
146                    "error": err.to_string(),
147                    "logs": []
148                }))?;
149                Ok(CallToolResult::success(vec![content]))
150            }
151        }
152    }
153}
154
155impl ServerHandler for CodeRunnerService {
156    fn get_info(&self) -> ServerInfo {
157        ServerInfo {
158            protocol_version: ProtocolVersion::V_2024_11_05,
159            capabilities: ServerCapabilities::builder().enable_tools().build(),
160            server_info: Implementation::from_build_env(),
161            instructions: Some("一个支持执行JavaScript、TypeScript和Python代码的服务".to_string()),
162        }
163    }
164}