pub mod client;
use anyhow::{Context, Result};
use rmcp::model::{InitializeResult, Tool};
use serde_json::Value;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use crate::kota_code::mcp::client::McpClient;
pub struct McpManager {
clients: Arc<RwLock<HashMap<String, McpClient>>>,
}
impl McpManager {
pub fn new() -> Self {
Self {
clients: Arc::new(RwLock::new(HashMap::new())),
}
}
pub async fn add_server(&self, name: &str, command: &str, args: Vec<String>) -> Result<()> {
let client = McpClient::new(command, args)
.await
.context(format!("Failed to add MCP server: {}", name))?;
let mut clients = self.clients.write().await;
clients.insert(name.to_string(), client);
Ok(())
}
pub async fn remove_server(&self, name: &str) -> Result<()> {
let mut clients = self.clients.write().await;
if let Some(client) = clients.remove(name) {
client.close().await?;
}
Ok(())
}
pub async fn get_server_info(&self, name: &str) -> Result<InitializeResult> {
let clients = self.clients.read().await;
let client = clients
.get(name)
.context(format!("Server not found: {}", name))?;
Ok(client.server_info().clone())
}
pub async fn list_tools(&self, server_name: &str) -> Result<Vec<Tool>> {
let clients = self.clients.read().await;
let client = clients
.get(server_name)
.context(format!("Server not found: {}", server_name))?;
Ok(client.tools().to_vec())
}
pub async fn list_all_tools(&self) -> Result<HashMap<String, Vec<Tool>>> {
let clients = self.clients.read().await;
let mut all_tools = HashMap::new();
for (name, client) in clients.iter() {
all_tools.insert(name.clone(), client.tools().to_vec());
}
Ok(all_tools)
}
pub async fn call_tool(
&self,
server_name: &str,
tool_name: &str,
arguments: Option<Value>,
) -> Result<Value> {
let clients = self.clients.read().await;
let client = clients
.get(server_name)
.context(format!("Server not found: {}", server_name))?;
client.call_tool(tool_name, arguments).await
}
pub async fn refresh_server_tools(&self, server_name: &str) -> Result<()> {
let mut clients = self.clients.write().await;
let client = clients
.get_mut(server_name)
.context(format!("Server not found: {}", server_name))?;
client.refresh_tools().await
}
pub async fn list_servers(&self) -> Vec<String> {
let clients = self.clients.read().await;
clients.keys().cloned().collect()
}
pub async fn has_server(&self, name: &str) -> bool {
let clients = self.clients.read().await;
clients.contains_key(name)
}
pub async fn close_all(&self) -> Result<()> {
let mut clients = self.clients.write().await;
for (_, client) in clients.drain() {
let _ = client.close().await; }
Ok(())
}
}
impl Default for McpManager {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_mcp_manager_creation() {
let manager = McpManager::new();
assert_eq!(manager.list_servers().await.len(), 0);
}
#[tokio::test]
async fn test_server_check() {
let manager = McpManager::new();
assert!(!manager.has_server("test").await);
}
}