use crate::protocol::{ToolError, ToolMetadata, ToolProtocol, ToolResult};
use async_trait::async_trait;
use std::collections::HashMap;
use std::error::Error;
use std::sync::Arc;
use tokio::sync::RwLock;
#[derive(Clone)]
pub struct UnifiedMcpServer {
tools: Arc<RwLock<HashMap<String, Arc<dyn ToolProtocol>>>>,
}
impl UnifiedMcpServer {
pub fn new() -> Self {
Self {
tools: Arc::new(RwLock::new(HashMap::new())),
}
}
pub async fn register_tool(&mut self, tool_name: &str, protocol: Arc<dyn ToolProtocol>) {
let mut tools = self.tools.write().await;
tools.insert(tool_name.to_string(), protocol);
}
pub async fn unregister_tool(&mut self, tool_name: &str) {
let mut tools = self.tools.write().await;
tools.remove(tool_name);
}
pub async fn has_tool(&self, tool_name: &str) -> bool {
let tools = self.tools.read().await;
tools.contains_key(tool_name)
}
pub async fn tool_count(&self) -> usize {
let tools = self.tools.read().await;
tools.len()
}
}
impl Default for UnifiedMcpServer {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
impl ToolProtocol for UnifiedMcpServer {
async fn execute(
&self,
tool_name: &str,
parameters: serde_json::Value,
) -> Result<ToolResult, Box<dyn Error + Send + Sync>> {
let tools = self.tools.read().await;
let protocol = tools.get(tool_name).cloned().ok_or_else(|| {
Box::new(ToolError::NotFound(tool_name.to_string())) as Box<dyn Error + Send + Sync>
})?;
drop(tools);
protocol.execute(tool_name, parameters).await
}
async fn list_tools(&self) -> Result<Vec<ToolMetadata>, Box<dyn Error + Send + Sync>> {
let tools = self.tools.read().await;
let mut seen: std::collections::HashSet<usize> = std::collections::HashSet::new();
let protocols: Vec<Arc<dyn ToolProtocol>> = tools
.values()
.filter(|p| seen.insert(Arc::as_ptr(*p) as *const () as usize))
.cloned()
.collect();
drop(tools);
let mut all_tools = Vec::new();
for protocol in protocols {
match protocol.list_tools().await {
Ok(mut tool_list) => all_tools.append(&mut tool_list),
Err(e) => {
eprintln!("Error listing tools from protocol: {}", e);
}
}
}
Ok(all_tools)
}
async fn get_tool_metadata(
&self,
tool_name: &str,
) -> Result<ToolMetadata, Box<dyn Error + Send + Sync>> {
let all_tools = self.list_tools().await?;
all_tools
.into_iter()
.find(|t| t.name == tool_name)
.ok_or_else(|| {
Box::new(ToolError::NotFound(tool_name.to_string())) as Box<dyn Error + Send + Sync>
})
}
fn protocol_name(&self) -> &str {
"unified-mcp-server"
}
async fn initialize(&mut self) -> Result<(), Box<dyn Error + Send + Sync>> {
let _tools = self.tools.read().await;
Ok(())
}
async fn shutdown(&mut self) -> Result<(), Box<dyn Error + Send + Sync>> {
let _tools = self.tools.read().await;
Ok(())
}
}