use crate::mcp::{McpConfig, McpError, McpToolsManager};
use autoagents::core::tool::ToolT;
use std::path::Path;
use std::sync::Arc;
#[derive(Debug, Clone, Default)]
pub struct McpTools {
manager: Arc<McpToolsManager>,
}
impl McpTools {
pub fn new() -> Self {
Self::default()
}
pub async fn from_config<P: AsRef<Path>>(config_path: P) -> Result<Self, McpError> {
let manager = Arc::new(McpToolsManager::from_config_file(config_path).await?);
Ok(Self { manager })
}
pub async fn from_config_object(config: &McpConfig) -> Result<Self, McpError> {
let manager = Arc::new(McpToolsManager::new());
manager.connect_servers(config).await?;
Ok(Self { manager })
}
pub async fn get_tools(&self) -> Vec<Arc<dyn ToolT>> {
self.manager.get_tools().await
}
pub async fn get_tool(&self, name: &str) -> Option<Arc<dyn ToolT>> {
self.manager.get_tool(name).await
}
pub async fn tool_names(&self) -> Vec<String> {
self.manager.tool_names().await
}
pub async fn tool_count(&self) -> usize {
self.manager.tool_count().await
}
pub async fn refresh(&self) -> Result<(), McpError> {
self.manager.refresh_tools().await
}
pub async fn connected_servers(&self) -> Vec<String> {
self.manager.connected_servers().await
}
pub fn manager(&self) -> Arc<McpToolsManager> {
Arc::clone(&self.manager)
}
}
#[macro_export]
macro_rules! mcp_tools_from_config {
($config_path:expr) => {{
$crate::mcp::tools::McpTools::from_config($config_path)
}};
}
impl McpTools {
pub async fn to_boxed_tools(&self) -> Vec<Box<dyn ToolT>> {
self.get_tools()
.await
.into_iter()
.map(|tool| {
Box::new(McpToolWrapper { tool }) as Box<dyn ToolT>
})
.collect()
}
}
#[derive(Debug)]
struct McpToolWrapper {
tool: Arc<dyn ToolT>,
}
impl ToolT for McpToolWrapper {
fn name(&self) -> &str {
self.tool.name()
}
fn description(&self) -> &str {
self.tool.description()
}
fn args_schema(&self) -> serde_json::Value {
self.tool.args_schema()
}
}
#[autoagents::async_trait]
impl autoagents::core::tool::ToolRuntime for McpToolWrapper {
async fn execute(
&self,
args: serde_json::Value,
) -> Result<serde_json::Value, autoagents::core::tool::ToolCallError> {
self.tool.execute(args).await
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_empty_mcp_tools() {
let tools = McpTools::default();
assert_eq!(tools.tool_count().await, 0);
assert!(tools.tool_names().await.is_empty());
assert!(tools.connected_servers().await.is_empty());
}
#[tokio::test]
async fn test_mcp_tools_boxed_conversion() {
let tools = McpTools::default();
let boxed_tools = tools.to_boxed_tools().await;
assert!(boxed_tools.is_empty());
}
}