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
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:
@@ -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) }
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user