"添加前端模板和运行代码模块"
This commit is contained in:
109
qiming-run_code_rmcp/.cursor/rules/code-execution.mdc
Normal file
109
qiming-run_code_rmcp/.cursor/rules/code-execution.mdc
Normal file
@@ -0,0 +1,109 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
# 代码执行流程
|
||||
|
||||
本项目的核心功能是执行JavaScript、TypeScript和Python代码,并捕获执行结果。以下是代码执行的主要流程:
|
||||
|
||||
## 代码执行模型
|
||||
|
||||
项目使用模块化的代码执行模型,定义在[src/model/code_run_model.rs](mdc:src/model/code_run_model.rs)中:
|
||||
|
||||
```rust
|
||||
/// 执行结果,包含js/python 执行结果,和打印的log日志
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct CodeScriptExecutionResult {
|
||||
//js/python 执行结果
|
||||
pub result: Option<Value>,
|
||||
//js/python 打印的log日志
|
||||
pub logs: Vec<String>,
|
||||
// 是否执行成功,ture:默认值,执行成功
|
||||
#[serde(skip_serializing)]
|
||||
pub success: bool,
|
||||
//如果执行错误的话,错误信息
|
||||
#[serde(skip_serializing)]
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
/// 代码执行器
|
||||
pub struct CodeExecutor;
|
||||
|
||||
impl CodeExecutor {
|
||||
/// 执行代码
|
||||
pub async fn execute(
|
||||
code: &str,
|
||||
language: LanguageScript,
|
||||
) -> Result<CodeScriptExecutionResult> {
|
||||
Self::execute_with_params(code, language, None).await
|
||||
}
|
||||
|
||||
/// 执行代码并传递参数
|
||||
pub async fn execute_with_params(
|
||||
code: &str,
|
||||
language: LanguageScript,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> Result<CodeScriptExecutionResult> {
|
||||
match language {
|
||||
LanguageScript::Js => JsRunner::new().run_with_params(code, params).await,
|
||||
LanguageScript::Ts => TsRunner::new().run_with_params(code, params).await,
|
||||
LanguageScript::Python => PythonRunner::new().run_with_params(code, params).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 语言特定执行器
|
||||
|
||||
### JavaScript执行器
|
||||
|
||||
JavaScript代码通过[JsRunner](mdc:src/deno_runner/js_runner.rs)执行:
|
||||
|
||||
1. 准备JavaScript代码,添加日志捕获和handler函数执行逻辑
|
||||
2. 使用代码哈希值缓存处理过的代码
|
||||
3. 使用Deno执行代码
|
||||
4. 解析执行结果
|
||||
|
||||
### TypeScript执行器
|
||||
|
||||
TypeScript代码通过[TsRunner](mdc:src/deno_runner/ts_runner.rs)执行:
|
||||
|
||||
1. 准备TypeScript代码,添加日志捕获和handler函数执行逻辑
|
||||
2. 使用代码哈希值缓存处理过的代码
|
||||
3. 使用Deno执行代码
|
||||
4. 解析执行结果
|
||||
|
||||
### Python执行器
|
||||
|
||||
Python代码通过[PythonRunner](mdc:src/python_runner/python_runner.rs)执行:
|
||||
|
||||
1. 分析Python代码的依赖
|
||||
2. 准备Python代码,添加日志捕获和handler/main函数执行逻辑
|
||||
3. 使用代码哈希值缓存处理过的代码
|
||||
4. 使用uv在隔离环境中执行Python代码
|
||||
5. 解析执行结果
|
||||
|
||||
## 参数传递
|
||||
|
||||
参数通过JSON格式传递给脚本:
|
||||
|
||||
1. JavaScript/TypeScript:参数直接传递给handler函数
|
||||
2. Python:参数通过环境变量`INPUT_JSON`传递,然后在脚本中解析并传递给handler或main函数
|
||||
|
||||
## 结果处理
|
||||
|
||||
执行结果通过[CodeScriptExecutionResult](mdc:src/model/code_run_model.rs)结构体表示,包含:
|
||||
|
||||
- result: 执行结果(通过handler/main函数返回)
|
||||
- logs: 执行过程中的日志
|
||||
- success: 执行是否成功
|
||||
- error: 执行错误(如果有)
|
||||
|
||||
## 缓存机制
|
||||
|
||||
为了提高性能,项目使用[CodeFileCache](mdc:src/cache)缓存处理过的代码:
|
||||
|
||||
1. 计算代码的哈希值
|
||||
2. 检查是否存在对应的缓存
|
||||
3. 如果存在,直接使用缓存;否则处理代码并缓存结果
|
||||
72
qiming-run_code_rmcp/.cursor/rules/dependencies.mdc
Normal file
72
qiming-run_code_rmcp/.cursor/rules/dependencies.mdc
Normal file
@@ -0,0 +1,72 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
# 项目依赖
|
||||
|
||||
本项目使用多个Rust库来实现其功能。以下是主要依赖项及其用途:
|
||||
|
||||
## Cargo.toml
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
tokio = { version = "1.32", features = ["full"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
log = "0.4"
|
||||
env_logger = "0.10"
|
||||
anyhow = "1.0"
|
||||
tempfile = "3.8"
|
||||
regex = "1.9"
|
||||
clap = { version = "4.4", features = ["derive"] }
|
||||
thiserror = "1.0"
|
||||
```
|
||||
|
||||
## 主要依赖项
|
||||
|
||||
### 异步运行时
|
||||
|
||||
- [tokio](https://crates.io/crates/tokio): 异步运行时,用于支持异步/await语法和并发执行
|
||||
|
||||
### 序列化/反序列化
|
||||
|
||||
- [serde](https://crates.io/crates/serde): 通用序列化/反序列化框架
|
||||
- [serde_json](https://crates.io/crates/serde_json): JSON序列化/反序列化支持
|
||||
|
||||
### 错误处理
|
||||
|
||||
- [anyhow](https://crates.io/crates/anyhow): 简化错误处理的库
|
||||
- [thiserror](https://crates.io/crates/thiserror): 用于定义自定义错误类型
|
||||
|
||||
### 日志记录
|
||||
|
||||
- [log](https://crates.io/crates/log): 日志记录接口
|
||||
- [env_logger](https://crates.io/crates/env_logger): 基于环境变量的日志记录器
|
||||
|
||||
### 命令行参数解析
|
||||
|
||||
- [clap](https://crates.io/crates/clap): 命令行参数解析库,支持派生宏
|
||||
|
||||
### 其他工具
|
||||
|
||||
- [rmcp](https://crates.io/crates/rmcp): Model Context Protocol (MCP) SDK
|
||||
- [tempfile](https://crates.io/crates/tempfile): 临时文件创建和管理
|
||||
- [regex](https://crates.io/crates/regex): 正则表达式支持
|
||||
|
||||
## 外部依赖
|
||||
|
||||
除了Rust库外,本项目还依赖以下外部工具:
|
||||
|
||||
1. [Deno](https://deno.land/): 现代JavaScript和TypeScript运行时,用于执行JavaScript代码
|
||||
2. [uv](https://github.com/astral-sh/uv): Python包管理器和隔离环境工具,用于安全执行Python代码
|
||||
|
||||
## 安装外部依赖
|
||||
|
||||
```bash
|
||||
# 安装Deno
|
||||
curl -fsSL https://deno.land/x/install/install.sh | sh
|
||||
|
||||
# 安装uv
|
||||
curl -fsSL https://astral.sh/uv/install.sh | sh
|
||||
```
|
||||
101
qiming-run_code_rmcp/.cursor/rules/error-handling.mdc
Normal file
101
qiming-run_code_rmcp/.cursor/rules/error-handling.mdc
Normal file
@@ -0,0 +1,101 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
# 错误处理
|
||||
|
||||
本项目使用[anyhow](mdc:https:/crates.io/crates/anyhow)和[thiserror](mdc:https:/crates.io/crates/thiserror)库进行错误处理,错误类型定义在[error.rs](mdc:src/error.rs)中。
|
||||
|
||||
## 错误类型
|
||||
|
||||
```rust
|
||||
#[derive(Error, Debug)]
|
||||
pub enum AppError {
|
||||
#[error("Failed to execute code: {0}")]
|
||||
ExecutionError(String),
|
||||
|
||||
#[error("Failed to parse output: {0}")]
|
||||
ParseError(String),
|
||||
|
||||
#[error("Failed to create temporary file: {0}")]
|
||||
IoError(#[from] std::io::Error),
|
||||
|
||||
#[error("Failed to parse JSON: {0}")]
|
||||
JsonError(#[from] serde_json::Error),
|
||||
|
||||
#[error("Missing required field: {0}")]
|
||||
MissingField(String),
|
||||
|
||||
#[error("Unsupported language: {0}")]
|
||||
UnsupportedLanguage(String),
|
||||
|
||||
#[error("Handler function not found")]
|
||||
HandlerNotFound,
|
||||
|
||||
#[error("MCP error: {0}")]
|
||||
McpError(String),
|
||||
|
||||
#[error("{0}")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
pub type AppResult<T> = Result<T, AppError>;
|
||||
```
|
||||
|
||||
## 错误处理流程
|
||||
|
||||
1. 在代码执行过程中使用`anyhow::Result`类型传递错误
|
||||
2. 使用`?`操作符传播错误
|
||||
3. 使用`context`方法添加错误上下文
|
||||
4. 在`main`函数中处理所有未捕获的错误
|
||||
|
||||
## 示例
|
||||
|
||||
```rust
|
||||
// 读取代码文件
|
||||
fn get_code(args: &CodeArgs) -> Result<String> {
|
||||
if let Some(file) = &args.file {
|
||||
fs::read_to_string(file).context("Failed to read code file")
|
||||
} else if let Some(code) = &args.code {
|
||||
Ok(code.clone())
|
||||
} else {
|
||||
anyhow::bail!("Either file or code must be provided")
|
||||
}
|
||||
}
|
||||
|
||||
// 执行JavaScript代码
|
||||
fn execute_js(code: &str, show_logs: bool) -> Result<ExecutionResult> {
|
||||
// Prepare the JavaScript code with wrapped handler
|
||||
let wrapped_code = prepare_js_code(code, show_logs);
|
||||
|
||||
// Create a temporary file
|
||||
let mut temp_file = NamedTempFile::new()?;
|
||||
write!(temp_file.as_file_mut(), "{}", wrapped_code)?;
|
||||
|
||||
// Execute with Deno
|
||||
let output = Command::new("deno")
|
||||
.arg("run")
|
||||
.arg("--allow-all")
|
||||
.arg(temp_file.path())
|
||||
.output()
|
||||
.context("Failed to execute Deno")?;
|
||||
|
||||
// Parse the output
|
||||
parse_execution_output(&output.stdout, &output.stderr)
|
||||
}
|
||||
```
|
||||
|
||||
## 错误输出
|
||||
|
||||
执行结果中的错误通过`ExecutionResult`结构体的`error`字段返回,并在`print_result`函数中输出:
|
||||
|
||||
```rust
|
||||
fn print_result(result: ExecutionResult) {
|
||||
// ...
|
||||
|
||||
if let Some(error) = result.error {
|
||||
eprintln!("Error: {}", error);
|
||||
}
|
||||
}
|
||||
```
|
||||
138
qiming-run_code_rmcp/.cursor/rules/examples.mdc
Normal file
138
qiming-run_code_rmcp/.cursor/rules/examples.mdc
Normal file
@@ -0,0 +1,138 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
# 示例代码
|
||||
|
||||
本项目包含JavaScript和Python的示例代码,用于测试代码执行功能。
|
||||
|
||||
## JavaScript示例
|
||||
|
||||
[examples/test_js.js](mdc:examples/test_js.js)是一个简单的JavaScript示例,包含:
|
||||
|
||||
```javascript
|
||||
// Sample JavaScript file with handler function
|
||||
|
||||
// Log some debug information
|
||||
console.log("Initializing JavaScript test...");
|
||||
|
||||
// Define a simple add function
|
||||
function add(a, b) {
|
||||
console.log(`Adding ${a} + ${b}`);
|
||||
return a + b;
|
||||
}
|
||||
|
||||
// Some processing
|
||||
const numbers = [1, 2, 3, 4, 5];
|
||||
console.log("Processing numbers:", numbers);
|
||||
|
||||
// Handler function that will be called to get the result
|
||||
function handler() {
|
||||
console.log("Handler function called");
|
||||
|
||||
// Calculate sum
|
||||
const sum = numbers.reduce((acc, num) => add(acc, num), 0);
|
||||
console.log("Final calculation completed");
|
||||
|
||||
return `The sum of [${numbers.join(", ")}] is ${sum}`;
|
||||
}
|
||||
```
|
||||
|
||||
执行这个示例将输出:
|
||||
|
||||
```
|
||||
--- Logs ---
|
||||
Initializing JavaScript test...
|
||||
Processing numbers: [1,2,3,4,5]
|
||||
Handler function called
|
||||
Adding 0 + 1
|
||||
Adding 1 + 2
|
||||
Adding 3 + 3
|
||||
Adding 6 + 4
|
||||
Adding 10 + 5
|
||||
Final calculation completed
|
||||
------------
|
||||
Result: The sum of [1, 2, 3, 4, 5] is 15
|
||||
```
|
||||
|
||||
## Python示例
|
||||
|
||||
[examples/test_python.py](mdc:examples/test_python.py)是一个简单的Python示例,包含:
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
# Sample Python file with handler function
|
||||
|
||||
import time
|
||||
|
||||
# Log some debug information
|
||||
print("Initializing Python test...")
|
||||
|
||||
# Define a simple function
|
||||
def multiply(a, b):
|
||||
print(f"Multiplying {a} * {b}")
|
||||
return a * b
|
||||
|
||||
# Some processing
|
||||
numbers = [1, 2, 3, 4, 5]
|
||||
print(f"Processing numbers: {numbers}")
|
||||
|
||||
# Handler function that will be called to get the result
|
||||
def handler():
|
||||
print("Handler function called")
|
||||
|
||||
# Calculate product
|
||||
product = 1
|
||||
for num in numbers:
|
||||
product = multiply(product, num)
|
||||
|
||||
print("Final calculation completed")
|
||||
|
||||
return f"The product of {numbers} is {product}"
|
||||
|
||||
# This part won't be executed when the code is run through the MCP runner
|
||||
if __name__ == "__main__":
|
||||
print("Running directly, calling handler...")
|
||||
result = handler()
|
||||
print(f"Result: {result}")
|
||||
```
|
||||
|
||||
执行这个示例将输出:
|
||||
|
||||
```
|
||||
--- Logs ---
|
||||
Handler function called
|
||||
Multiplying 1 * 1
|
||||
Multiplying 1 * 2
|
||||
Multiplying 2 * 3
|
||||
Multiplying 6 * 4
|
||||
Multiplying 24 * 5
|
||||
Final calculation completed
|
||||
------------
|
||||
Result: The product of [1, 2, 3, 4, 5] is 120
|
||||
```
|
||||
|
||||
## 如何创建自己的示例
|
||||
|
||||
创建自己的示例代码时,需要遵循以下规则:
|
||||
|
||||
1. 必须包含一个名为`handler`的函数,作为执行结果的返回点
|
||||
2. `handler`函数的返回值将作为执行结果
|
||||
3. 使用`console.log`(JavaScript)或`print`(Python)输出日志
|
||||
4. 可以定义其他函数和变量,它们将在执行过程中被使用
|
||||
|
||||
示例:
|
||||
|
||||
```javascript
|
||||
// JavaScript示例
|
||||
function handler() {
|
||||
return "Hello from JavaScript!";
|
||||
}
|
||||
```
|
||||
|
||||
```python
|
||||
# Python示例
|
||||
def handler():
|
||||
return "Hello from Python!"
|
||||
```
|
||||
98
qiming-run_code_rmcp/.cursor/rules/fixtures-guide.mdc
Normal file
98
qiming-run_code_rmcp/.cursor/rules/fixtures-guide.mdc
Normal file
@@ -0,0 +1,98 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
# 测试脚本示例指南
|
||||
|
||||
本项目包含多种语言的测试脚本示例,位于`fixtures`目录下。这些示例展示了如何编写可被本工具执行的JavaScript、TypeScript和Python脚本。
|
||||
|
||||
## JavaScript示例
|
||||
|
||||
### 基本执行
|
||||
|
||||
[test_js.js](mdc:fixtures/test_js.js) - 基本的JavaScript执行示例:
|
||||
- 展示了如何使用`console.log`输出日志
|
||||
- 定义了`handler`函数作为执行结果的返回点
|
||||
|
||||
### 参数传递
|
||||
|
||||
[test_js_params.js](mdc:fixtures/test_js_params.js) - 带参数的JavaScript执行示例:
|
||||
- 展示了如何接收和处理传入的参数
|
||||
- 演示了如何根据参数执行不同的逻辑
|
||||
|
||||
### 函数示例
|
||||
|
||||
[rfunction_test1.js](mdc:fixtures/rfunction_test1.js) - 函数式JavaScript示例:
|
||||
- 展示了如何定义和使用函数
|
||||
- 演示了如何处理和返回复杂数据结构
|
||||
|
||||
## TypeScript示例
|
||||
|
||||
### 基本执行
|
||||
|
||||
[test_ts.ts](mdc:fixtures/test_ts.ts) - 基本的TypeScript执行示例:
|
||||
- 展示了TypeScript的类型定义
|
||||
- 定义了带类型的`handler`函数
|
||||
|
||||
### 参数传递
|
||||
|
||||
[test_ts_params.ts](mdc:fixtures/test_ts_params.ts) - 带参数的TypeScript执行示例:
|
||||
- 展示了如何定义参数类型
|
||||
- 演示了TypeScript中的类型安全参数处理
|
||||
|
||||
## Python示例
|
||||
|
||||
### 基本执行
|
||||
|
||||
[test_python.py](mdc:fixtures/test_python.py) - 基本的Python执行示例:
|
||||
- 使用`handler`函数作为执行结果的返回点
|
||||
- 展示了如何使用Python进行基本计算和日志输出
|
||||
|
||||
### 参数传递
|
||||
|
||||
[test_python_params.py](mdc:fixtures/test_python_params.py) - 带参数的Python执行示例:
|
||||
- 展示了如何接收和处理传入的参数
|
||||
- 演示了如何返回包含多个字段的结果
|
||||
|
||||
### 类型示例
|
||||
|
||||
[test_python_types.py](mdc:fixtures/test_python_types.py) - 不同返回类型的Python示例:
|
||||
- 展示了如何返回不同类型的值(字符串、数字、布尔值、列表、字典等)
|
||||
- 演示了不同类型在JSON序列化中的处理方式
|
||||
|
||||
### 函数示例
|
||||
|
||||
[rfunction_python.py](mdc:fixtures/rfunction_python.py) - 函数式Python示例:
|
||||
- 展示了如何定义和使用Python函数
|
||||
- 演示了如何处理和返回复杂数据结构
|
||||
|
||||
## 使用示例
|
||||
|
||||
以下是如何使用这些示例脚本的命令:
|
||||
|
||||
```bash
|
||||
# 执行基本JavaScript示例
|
||||
cargo run -- --show-logs js -f fixtures/test_js.js
|
||||
|
||||
# 执行带参数的JavaScript示例
|
||||
cargo run -- --show-logs js -f fixtures/test_js_params.js -p '{"name":"User"}'
|
||||
|
||||
# 执行基本TypeScript示例
|
||||
cargo run -- --show-logs ts -f fixtures/test_ts.ts
|
||||
|
||||
# 执行带参数的TypeScript示例
|
||||
cargo run -- --show-logs ts -f fixtures/test_ts_params.ts -p '{"a":10, "b":20, "name":"User"}'
|
||||
|
||||
# 执行基本Python示例
|
||||
cargo run -- --show-logs python -f fixtures/test_python.py
|
||||
|
||||
# 执行带参数的Python示例
|
||||
cargo run -- --show-logs python -f fixtures/test_python_params.py -p '{"a":10, "b":20}'
|
||||
|
||||
# 执行不同类型的Python示例
|
||||
cargo run -- --show-logs python -f fixtures/test_python_types.py -p '{"type":"string"}'
|
||||
cargo run -- --show-logs python -f fixtures/test_python_types.py -p '{"type":"number"}'
|
||||
cargo run -- --show-logs python -f fixtures/test_python_types.py -p '{"type":"list"}'
|
||||
cargo run -- --show-logs python -f fixtures/test_python_types.py -p '{"type":"dict"}'
|
||||
```
|
||||
146
qiming-run_code_rmcp/.cursor/rules/mcp-integration.mdc
Normal file
146
qiming-run_code_rmcp/.cursor/rules/mcp-integration.mdc
Normal file
@@ -0,0 +1,146 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
# MCP SDK集成
|
||||
|
||||
本项目支持Model Context Protocol (MCP) SDK集成,允许通过标准化协议执行代码。MCP相关功能主要在[mcp.rs](mdc:src/mcp.rs)中实现。
|
||||
|
||||
## 核心数据结构
|
||||
|
||||
```rust
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct CodeExecutionParams {
|
||||
pub code: String,
|
||||
pub language: String,
|
||||
pub show_logs: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct CodeExecutionResult {
|
||||
pub logs: Vec<String>,
|
||||
pub result: Option<String>,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
```
|
||||
|
||||
## JavaScript执行
|
||||
|
||||
MCP中的JavaScript执行使用以下包装代码:
|
||||
|
||||
```javascript
|
||||
// MCP SDK integration for JavaScript
|
||||
// Note: MCP SDK is not required for basic functionality
|
||||
|
||||
// Log capture setup
|
||||
const logs = [];
|
||||
const originalConsoleLog = console.log;
|
||||
console.log = function() {
|
||||
const message = Array.from(arguments).map(arg =>
|
||||
typeof arg === 'object' && arg !== null ? JSON.stringify(arg) : String(arg)
|
||||
).join(' ');
|
||||
logs.push(message);
|
||||
if (show_logs) {
|
||||
originalConsoleLog.apply(console, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
async function mcpExecute() {
|
||||
try {
|
||||
// User code here
|
||||
|
||||
// Execute handler
|
||||
let result = null;
|
||||
if (typeof handler === 'function') {
|
||||
result = await handler();
|
||||
}
|
||||
|
||||
return {
|
||||
logs: logs,
|
||||
result: result !== undefined ? String(result) : null,
|
||||
error: null
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
logs: logs,
|
||||
result: null,
|
||||
error: error.toString()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Execute and return results
|
||||
mcpExecute().then(result => {
|
||||
originalConsoleLog(JSON.stringify(result));
|
||||
});
|
||||
```
|
||||
|
||||
## Python执行
|
||||
|
||||
MCP中的Python执行使用以下包装代码:
|
||||
|
||||
```python
|
||||
# MCP SDK integration for Python
|
||||
# Note: MCP SDK is not required for basic functionality
|
||||
import sys
|
||||
import json
|
||||
import io
|
||||
from contextlib import redirect_stdout
|
||||
|
||||
# Store logs
|
||||
logs = []
|
||||
|
||||
# Create custom stdout to capture logs
|
||||
class LogCapture(io.StringIO):
|
||||
def write(self, text):
|
||||
if text.strip():
|
||||
logs.append(text.rstrip())
|
||||
if show_logs:
|
||||
sys.__stdout__.write(text)
|
||||
|
||||
def mcp_execute():
|
||||
try:
|
||||
// User code here
|
||||
|
||||
// Execute handler function and capture result
|
||||
result = None
|
||||
with redirect_stdout(LogCapture()):
|
||||
if 'handler' in globals() and callable(handler):
|
||||
result = handler()
|
||||
|
||||
return {
|
||||
"logs": logs,
|
||||
"result": str(result) if result is not None else None,
|
||||
"error": None
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"logs": logs,
|
||||
"result": None,
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
# Execute and print results
|
||||
result = mcp_execute()
|
||||
print(json.dumps(result))
|
||||
```
|
||||
|
||||
## 执行流程
|
||||
|
||||
MCP执行流程由[execute_with_mcp](mdc:src/mcp.rs#L138)函数处理:
|
||||
|
||||
1. 创建临时文件并写入包装后的代码
|
||||
2. 根据语言类型选择执行命令(Deno或uv)
|
||||
3. 执行代码并捕获输出
|
||||
4. 解析JSON格式的执行结果
|
||||
5. 如果无法解析JSON,则返回原始输出
|
||||
|
||||
## 使用方法
|
||||
|
||||
在命令行中使用`--use-mcp`参数启用MCP SDK集成:
|
||||
|
||||
```bash
|
||||
cargo run -- --use-mcp js -c "function handler() { return 'Hello from MCP JS'; }"
|
||||
cargo run -- --use-mcp python -f examples/test_python.py
|
||||
```
|
||||
50
qiming-run_code_rmcp/.cursor/rules/project-overview.mdc
Normal file
50
qiming-run_code_rmcp/.cursor/rules/project-overview.mdc
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
# 项目概述
|
||||
|
||||
这是一个使用Rust开发的命令行工具,用于执行JavaScript、TypeScript和Python代码。该工具支持以下功能:
|
||||
|
||||
1. 执行JavaScript代码(使用Deno运行时)
|
||||
2. 执行TypeScript代码(使用Deno运行时)
|
||||
3. 执行Python代码(使用uv提供隔离环境)
|
||||
4. 捕获并区分脚本中的日志输出和执行结果
|
||||
5. 支持JavaScript/TypeScript的handler函数和Python的handler/main函数作为执行结果的返回点
|
||||
6. 通过环境变量传递参数给脚本
|
||||
7. 可以通过参数控制是否显示日志输出
|
||||
8. 支持MCP SDK集成
|
||||
|
||||
## 主要文件
|
||||
|
||||
- [src/main.rs](mdc:src/main.rs) - 应用程序入口点,处理命令行参数和执行流程
|
||||
- [src/lib.rs](mdc:src/lib.rs) - 库入口点,导出模块和类型
|
||||
- [src/model/code_run_model.rs](mdc:src/model/code_run_model.rs) - 代码执行模型和结果处理
|
||||
- [src/deno_runner/js_runner.rs](mdc:src/deno_runner/js_runner.rs) - JavaScript代码执行器
|
||||
- [src/deno_runner/ts_runner.rs](mdc:src/deno_runner/ts_runner.rs) - TypeScript代码执行器
|
||||
- [src/python_runner/python_runner.rs](mdc:src/python_runner/python_runner.rs) - Python代码执行器
|
||||
- [src/cache/](mdc:src/cache) - 代码缓存管理
|
||||
- [fixtures/](mdc:fixtures) - 测试脚本示例
|
||||
|
||||
## 使用示例
|
||||
|
||||
```bash
|
||||
# 执行JavaScript文件
|
||||
cargo run -- --show-logs js -f fixtures/test_js.js
|
||||
|
||||
# 执行TypeScript文件
|
||||
cargo run -- --show-logs ts -f fixtures/test_ts.ts
|
||||
|
||||
# 执行Python文件
|
||||
cargo run -- --show-logs python -f fixtures/test_python.py
|
||||
|
||||
# 带参数执行Python文件
|
||||
cargo run -- --show-logs python -f fixtures/test_python_params.py -p '{"a":10, "b":20}'
|
||||
|
||||
# 直接执行JavaScript代码
|
||||
cargo run -- js -c "function handler(input) { return 'Hello from JS: ' + input.name; }" -p '{"name":"User"}'
|
||||
|
||||
# 直接执行Python代码
|
||||
cargo run -- python -c "def handler(args): return 'Hello from Python: ' + args.get('name', 'Guest')" -p '{"name":"User"}'
|
||||
```
|
||||
143
qiming-run_code_rmcp/.cursor/rules/python-execution.mdc
Normal file
143
qiming-run_code_rmcp/.cursor/rules/python-execution.mdc
Normal file
@@ -0,0 +1,143 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
# Python代码执行
|
||||
|
||||
本项目使用`uv`在隔离环境中执行Python代码,提供安全可靠的执行环境。以下是Python代码执行的详细流程:
|
||||
|
||||
## Python运行器
|
||||
|
||||
Python代码通过[PythonRunner](mdc:src/python_runner/python_runner.rs)执行,实现了`RunCode`特性:
|
||||
|
||||
```rust
|
||||
pub struct PythonRunner;
|
||||
|
||||
impl RunCode for PythonRunner {
|
||||
async fn run(&self, code: &str) -> Result<CodeScriptExecutionResult> {
|
||||
// 实现代码...
|
||||
}
|
||||
|
||||
async fn run_with_params(&self, code: &str, params: Option<serde_json::Value>) -> Result<CodeScriptExecutionResult> {
|
||||
// 实现代码...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 依赖解析
|
||||
|
||||
Python代码的依赖通过[python_dependencies.rs](mdc:src/python_runner/dependencies/python_dependencies.rs)解析:
|
||||
|
||||
1. 使用Pest解析器分析Python代码中的import语句
|
||||
2. 支持常规import语句和importlib动态导入
|
||||
3. 提取所有导入的模块名称
|
||||
|
||||
```rust
|
||||
pub fn parse_import(python_code: &str) -> Result<Vec<String>> {
|
||||
// 使用Pest解析器分析Python代码
|
||||
let pairs = ImportParser::parse(Rule::file, &input)?;
|
||||
|
||||
// 提取模块名称
|
||||
let mut imported_modules = Vec::new();
|
||||
// 处理各种import语句...
|
||||
|
||||
Ok(imported_modules)
|
||||
}
|
||||
```
|
||||
|
||||
## 代码准备
|
||||
|
||||
Python代码在执行前需要进行包装,添加日志捕获和函数执行逻辑:
|
||||
|
||||
```rust
|
||||
fn prepare_python_code(&self, code: &str, show_logs: bool) -> String {
|
||||
// 创建包装代码,包括:
|
||||
// 1. 日志捕获
|
||||
// 2. 参数解析
|
||||
// 3. 执行handler或main函数
|
||||
// 4. 结果格式化
|
||||
}
|
||||
```
|
||||
|
||||
包装代码主要功能:
|
||||
1. 捕获标准输出作为日志
|
||||
2. 从环境变量`INPUT_JSON`解析参数
|
||||
3. 优先执行`handler`函数,如果不存在则执行`main`函数
|
||||
4. 将执行结果和日志格式化为JSON
|
||||
|
||||
## 参数传递
|
||||
|
||||
参数通过环境变量`INPUT_JSON`传递给Python脚本:
|
||||
|
||||
```rust
|
||||
// 将参数序列化为JSON字符串
|
||||
let params_json = match params {
|
||||
Some(p) => serde_json::to_string(&p)?,
|
||||
None => "{}".to_string(),
|
||||
};
|
||||
|
||||
// 通过环境变量传递参数
|
||||
execute_command.env("INPUT_JSON", ¶ms_json);
|
||||
```
|
||||
|
||||
在Python脚本中,参数通过以下方式获取:
|
||||
|
||||
```python
|
||||
# 从环境变量获取输入参数
|
||||
args = {}
|
||||
try:
|
||||
input_json = os.environ.get('INPUT_JSON')
|
||||
if input_json:
|
||||
args = json.loads(input_json)
|
||||
except Exception as e:
|
||||
print(f"解析输入参数失败: {e}")
|
||||
```
|
||||
|
||||
## 执行流程
|
||||
|
||||
1. 计算代码哈希值,检查缓存
|
||||
2. 如果缓存存在,直接使用;否则:
|
||||
- 分析代码依赖
|
||||
- 准备包装后的代码
|
||||
- 保存到缓存
|
||||
3. 使用`uv`命令在隔离环境中执行代码:
|
||||
```rust
|
||||
let mut execute_command = Command::new("uv");
|
||||
execute_command
|
||||
.arg("run")
|
||||
.arg("-s") // 明确指定作为脚本运行
|
||||
.arg("--isolated") // 在隔离环境中运行
|
||||
.arg("-p")
|
||||
.arg("python3") // 指定Python解释器
|
||||
.env("INPUT_JSON", ¶ms_json) // 通过环境变量传递参数
|
||||
.arg(&temp_path)
|
||||
```
|
||||
4. 解析执行结果,提取日志和返回值
|
||||
|
||||
## 结果处理
|
||||
|
||||
执行结果通过JSON格式返回,包含三个字段:
|
||||
- `logs`: 执行过程中的日志数组
|
||||
- `result`: 执行结果(可能是字符串、数字、布尔值、对象等)
|
||||
- `error`: 执行错误(如果有)
|
||||
|
||||
```json
|
||||
{
|
||||
"logs": ["日志1", "日志2", ...],
|
||||
"result": "执行结果",
|
||||
"error": null
|
||||
}
|
||||
```
|
||||
|
||||
## 支持的返回类型
|
||||
|
||||
Python脚本可以返回多种类型的值:
|
||||
1. 字符串
|
||||
2. 数字
|
||||
3. 布尔值
|
||||
4. 列表/数组
|
||||
5. 字典/对象
|
||||
6. None/null
|
||||
|
||||
所有复杂类型(列表、字典)都会被序列化为JSON字符串。
|
||||
Reference in New Issue
Block a user