1use crate::client::{MCPClient, ToolResponse};
2use anyhow::Result;
3use std::collections::HashMap;
4use std::sync::Arc;
5use tokio::sync::RwLock;
6
7pub struct MCPToolExecutor {
9 clients: Arc<RwLock<HashMap<String, Arc<MCPClient>>>>,
10}
11
12impl MCPToolExecutor {
13 pub fn new() -> Self {
14 Self {
15 clients: Arc::new(RwLock::new(HashMap::new())),
16 }
17 }
18
19 pub async fn add_server(&self, client: MCPClient) -> Result<()> {
21 let name = client.name().to_string();
22 let mut clients = self.clients.write().await;
23 clients.insert(name, Arc::new(client));
24 Ok(())
25 }
26
27 pub async fn list_all_tools(&self) -> Result<Vec<(String, Vec<crate::client::ToolInfo>)>> {
29 let clients = self.clients.read().await;
30 let mut all_tools = Vec::new();
31
32 for (server_name, client) in clients.iter() {
33 let tools = client.list_tools().await?;
34 all_tools.push((server_name.clone(), tools));
35 }
36
37 Ok(all_tools)
38 }
39
40 pub async fn get_llm_tools(&self) -> Result<Vec<praxis_llm::Tool>> {
42 let mut all_tools = Vec::new();
43 let clients = self.clients.read().await;
44
45 for client in clients.values() {
46 let tools = client.get_llm_tools().await?;
47 all_tools.extend(tools);
48 }
49
50 Ok(all_tools)
51 }
52
53 pub async fn execute_tool(&self, tool_name: &str, arguments: serde_json::Value)
55 -> Result<Vec<ToolResponse>> {
56 let clients = self.clients.read().await;
57
58 for client in clients.values() {
59 let tools = client.list_tools().await?;
60 if tools.iter().any(|t| t.name == tool_name) {
61 return client.call_tool(tool_name, arguments).await;
62 }
63 }
64
65 Err(anyhow::anyhow!("Tool '{}' not found", tool_name))
66 }
67}
68
69#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[tokio::test]
78 async fn test_executor_creation() {
79 let executor = MCPToolExecutor::new();
80 assert!(executor.list_all_tools().await.unwrap().is_empty());
81 }
82}
83