refactor: 清理未使用代码并添加未来功能标记
Some checks failed
CI / Rust Check (push) Has been cancelled
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

style: 统一代码格式和注释风格

docs: 更新多个功能文档的完整度和状态

feat(runtime): 添加路径验证工具支持

fix(pipeline): 改进条件判断和变量解析逻辑

test(types): 为ID类型添加全面测试用例

chore: 更新依赖项和Cargo.lock文件

perf(mcp): 优化MCP协议传输和错误处理
This commit is contained in:
iven
2026-03-25 21:55:12 +08:00
parent aa6a9cbd84
commit bf6d81f9c6
109 changed files with 12271 additions and 815 deletions

View File

@@ -256,6 +256,7 @@ pub struct A2aReceiver {
}
impl A2aReceiver {
#[allow(dead_code)] // Reserved for future A2A integration
fn new(rx: mpsc::Receiver<A2aEnvelope>) -> Self {
Self { receiver: Some(rx) }
}

View File

@@ -7,6 +7,9 @@ use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use zclaw_types::Result;
// Re-export McpServerConfig from mcp_transport
pub use crate::mcp_transport::McpServerConfig;
/// MCP tool definition
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct McpTool {
@@ -130,54 +133,48 @@ pub trait McpClient: Send + Sync {
async fn get_prompt(&self, name: &str, arguments: HashMap<String, String>) -> Result<String>;
}
/// Basic MCP client implementation
/// Basic MCP client implementation using stdio transport
pub struct BasicMcpClient {
config: McpClientConfig,
client: reqwest::Client,
transport: crate::mcp_transport::McpTransport,
}
impl BasicMcpClient {
pub fn new(config: McpClientConfig) -> Self {
/// Create new MCP client with server configuration
pub fn new(config: McpServerConfig) -> Self {
Self {
config,
client: reqwest::Client::new(),
transport: crate::mcp_transport::McpTransport::new(config),
}
}
/// Initialize the MCP connection
pub async fn initialize(&self) -> Result<()> {
self.transport.initialize().await
}
}
#[async_trait]
impl McpClient for BasicMcpClient {
async fn list_tools(&self) -> Result<Vec<McpTool>> {
// TODO: Implement actual MCP protocol communication
Ok(Vec::new())
McpClient::list_tools(&self.transport).await
}
async fn call_tool(&self, _request: McpToolCallRequest) -> Result<McpToolCallResponse> {
// TODO: Implement actual MCP protocol communication
Ok(McpToolCallResponse {
content: vec![McpContent::Text { text: "Not implemented".to_string() }],
is_error: true,
})
async fn call_tool(&self, request: McpToolCallRequest) -> Result<McpToolCallResponse> {
McpClient::call_tool(&self.transport, request).await
}
async fn list_resources(&self) -> Result<Vec<McpResource>> {
Ok(Vec::new())
McpClient::list_resources(&self.transport).await
}
async fn read_resource(&self, _uri: &str) -> Result<McpResourceContent> {
Ok(McpResourceContent {
uri: String::new(),
mime_type: None,
text: Some("Not implemented".to_string()),
blob: None,
})
async fn read_resource(&self, uri: &str) -> Result<McpResourceContent> {
McpClient::read_resource(&self.transport, uri).await
}
async fn list_prompts(&self) -> Result<Vec<McpPrompt>> {
Ok(Vec::new())
McpClient::list_prompts(&self.transport).await
}
async fn get_prompt(&self, _name: &str, _arguments: HashMap<String, String>) -> Result<String> {
Ok("Not implemented".to_string())
async fn get_prompt(&self, name: &str, arguments: HashMap<String, String>) -> Result<String> {
McpClient::get_prompt(&self.transport, name, arguments).await
}
}

View File

@@ -7,10 +7,12 @@ use std::io::{BufRead, BufReader, BufWriter, Write};
use std::process::{Child, ChildStdin, ChildStdout, Command, Stdio};
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use std::thread;
use async_trait::async_trait;
use serde::de::DeserializeOwned;
use tokio::sync::Mutex;
use tracing::{debug, warn};
use zclaw_types::{Result, ZclawError};
@@ -125,10 +127,10 @@ impl McpTransport {
cmd.current_dir(cwd);
}
// Configure stdio
// Configure stdio - pipe stderr for debugging
cmd.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::null());
.stderr(Stdio::piped());
// Spawn process
let mut child = cmd.spawn()
@@ -140,6 +142,26 @@ impl McpTransport {
let stdout = child.stdout.take()
.ok_or_else(|| ZclawError::McpError("Failed to get stdout".to_string()))?;
// Take stderr and spawn a background thread to log it
if let Some(stderr) = child.stderr.take() {
let server_name = self.config.command.clone();
thread::spawn(move || {
let reader = BufReader::new(stderr);
for line in reader.lines() {
match line {
Ok(text) => {
debug!(server = %server_name, stderr = %text, "MCP server stderr");
}
Err(e) => {
warn!(server = %server_name, error = %e, "Failed to read MCP server stderr");
break;
}
}
}
debug!(server = %server_name, "MCP server stderr stream ended");
});
}
// Store handles in separate mutexes
*self.stdin.lock().await = Some(BufWriter::new(stdin));
*self.stdout.lock().await = Some(BufReader::new(stdout));
@@ -363,3 +385,24 @@ impl McpClient for McpTransport {
Ok(prompt_text.join("\n"))
}
}
impl Drop for McpTransport {
fn drop(&mut self) {
// Try to kill the child process synchronously
// We use a blocking approach here since Drop cannot be async
if let Ok(mut child_guard) = self.child.try_lock() {
if let Some(mut child) = child_guard.take() {
// Try to kill the process gracefully
match child.kill() {
Ok(_) => {
// Wait for the process to exit
let _ = child.wait();
}
Err(e) => {
eprintln!("[McpTransport] Failed to kill child process: {}", e);
}
}
}
}
}
}