use std::{collections::HashMap, sync::Arc}; use anyhow::Result; use async_trait::async_trait; use rmcp::{ RoleClient, model::{CallToolRequestParams, CallToolResult, Tool as McpTool}, service::{RunningService, ServerSink}, }; use serde_json::Value; use crate::{ error::McpError, model::{Content, ToolResult}, }; #[async_trait] pub trait Tool: Send + Sync { fn name(&self) -> String; fn description(&self) -> String; fn parameters(&self) -> Value; async fn call(&self, args: Value) -> Result; } pub struct McpToolAdapter { tool: McpTool, server: ServerSink, } impl McpToolAdapter { pub fn new(tool: McpTool, server: ServerSink) -> Self { Self { tool, server } } } #[async_trait] impl Tool for McpToolAdapter { fn name(&self) -> String { self.tool.name.clone().to_string() } fn description(&self) -> String { self.tool .description .clone() .unwrap_or_default() .to_string() } fn parameters(&self) -> Value { serde_json::to_value(&self.tool.input_schema).unwrap_or(serde_json::json!({})) } async fn call(&self, args: Value) -> Result { let arguments = match args { Value::Object(map) => Some(map), _ => None, }; println!("arguments: {:?}", arguments); let call_result = self .server .call_tool(CallToolRequestParams { meta: None, name: self.tool.name.clone(), arguments, task: None, }) .await?; Ok(call_result) } } #[derive(Default)] pub struct ToolSet { tools: HashMap>, clients: HashMap>, } impl ToolSet { pub fn set_clients(&mut self, clients: HashMap>) { self.clients = clients; } pub fn add_tool(&mut self, tool: T) { self.tools.insert(tool.name(), Arc::new(tool)); } pub fn get_tool(&self, name: &str) -> Option> { self.tools.get(name).cloned() } pub fn tools(&self) -> Vec> { self.tools.values().cloned().collect() } } pub async fn get_mcp_tools(server: ServerSink) -> Result> { let tools = server.list_all_tools().await?; Ok(tools .into_iter() .map(|tool| McpToolAdapter::new(tool, server.clone())) .collect()) } pub trait IntoCallToolResult { fn into_call_tool_result(self) -> Result; } impl IntoCallToolResult for Result where T: serde::Serialize, { fn into_call_tool_result(self) -> Result { match self { Ok(response) => { let content = Content { content_type: "application/json".to_string(), body: serde_json::to_string(&response).unwrap_or_default(), }; Ok(ToolResult { success: true, contents: vec![content], }) } Err(error) => { let content = Content { content_type: "application/json".to_string(), body: serde_json::to_string(&error).unwrap_or_default(), }; Ok(ToolResult { success: false, contents: vec![content], }) } } } }