run_code_rmcp/mcp/
mcp_server.rs1use 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#[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#[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}