pub mod client;
pub mod config_loader;
pub mod server;
pub mod server_config;
pub mod tool_adapter;
pub mod transport;
pub mod types;
use std::collections::HashMap;
use std::sync::Arc;
pub use client::McpClient;
pub use config_loader::{McpConfigFile, McpServerEntry};
pub use server::McpServer;
pub use server_config::{McpServerConfig, TransportConfig};
pub use tool_adapter::McpToolAdapter;
pub use types::{
McpContent, McpPrompt, McpPromptGetResult, McpResource, McpResourceReadResult, McpTool,
McpToolCallResult, ServerCapabilities,
};
use echo_core::error::Result;
use echo_core::tools::Tool;
pub struct McpManager {
clients: HashMap<String, Arc<McpClient>>,
}
impl McpManager {
pub fn new() -> Self {
Self {
clients: HashMap::new(),
}
}
pub async fn connect(&mut self, config: McpServerConfig) -> Result<Vec<Box<dyn Tool>>> {
let name = config.name.clone();
if self.clients.contains_key(&name) {
tracing::warn!("MCP: 服务端 '{}' 已存在,先断开旧连接", name);
self.disconnect(&name).await;
}
let client = McpClient::new(config).await?;
let tools = client
.tools()
.iter()
.map(|tool| {
Box::new(McpToolAdapter::new(client.clone(), tool.clone())) as Box<dyn Tool>
})
.collect::<Vec<_>>();
self.clients.insert(name, client);
Ok(tools)
}
pub async fn connect_from_config(
&mut self,
config: &McpConfigFile,
) -> Result<Vec<Box<dyn Tool>>> {
let configs = config.to_server_configs()?;
let mut all_tools = Vec::new();
for cfg in configs {
let tools = self.connect(cfg).await?;
all_tools.extend(tools);
}
Ok(all_tools)
}
pub fn get_all_tools(&self) -> Vec<Box<dyn Tool>> {
self.clients
.values()
.flat_map(|client| {
client.tools().iter().map(|tool| {
Box::new(McpToolAdapter::new(client.clone(), tool.clone())) as Box<dyn Tool>
})
})
.collect()
}
pub fn get_client(&self, name: &str) -> Option<&Arc<McpClient>> {
self.clients.get(name)
}
pub fn server_names(&self) -> Vec<&str> {
self.clients.keys().map(|s| s.as_str()).collect()
}
pub async fn close_all(&self) {
for (name, client) in &self.clients {
tracing::info!("MCP: 关闭服务端 '{}'", name);
client.close().await;
}
}
pub async fn disconnect(&mut self, name: &str) -> bool {
if let Some(client) = self.clients.remove(name) {
tracing::info!("MCP: 断开服务端 '{}'", name);
client.close().await;
true
} else {
false
}
}
}
impl Default for McpManager {
fn default() -> Self {
Self::new()
}
}