use anyhow::Result;
use async_trait::async_trait;
use serde_json::json;
use crate::tool::{ApprovalRequirement, Tool, ToolContext, ToolDef, ToolResult};
use super::client::McpToolInfo;
use super::registry::McpRegistry;
pub struct McpToolAdapter {
registry: std::sync::Arc<McpRegistry>,
info: McpToolInfo,
tool_name: String,
}
impl McpToolAdapter {
pub fn new(registry: std::sync::Arc<McpRegistry>, info: McpToolInfo) -> Self {
let tool_name = format!("mcp__{}__{}", info.server_name, info.tool_name);
Self {
registry,
info,
tool_name,
}
}
pub fn full_name(&self) -> &str {
&self.tool_name
}
}
#[async_trait]
impl Tool for McpToolAdapter {
fn definition(&self) -> ToolDef {
ToolDef {
name: Box::leak(self.tool_name.clone().into_boxed_str()),
description: if self.info.description.is_empty() {
format!(
"MCP tool from server '{}'. See input schema for details.",
self.info.server_name
)
} else {
format!(
"[MCP:{}] {}",
self.info.server_name, self.info.description
)
},
parameters: self.info.input_schema.clone(),
}
}
fn approval(&self, args: &str) -> ApprovalRequirement {
ApprovalRequirement::RequireApproval(format!(
"MCP tool '{}' from server '{}' wants to execute with arguments: {}",
self.info.tool_name, self.info.server_name, args
))
}
async fn execute(&self, args: &str, _ctx: &ToolContext) -> Result<ToolResult> {
let arguments: serde_json::Value = if args.is_empty() || args == "{}" {
json!({})
} else {
serde_json::from_str(args)?
};
let output = self
.registry
.call_tool(&self.info.server_name, &self.info.tool_name, arguments)
.await?;
Ok(ToolResult {
call_id: String::new(),
output,
success: true,
})
}
}
pub fn register_mcp_tools(
registry: &mut crate::tool::ToolRegistry,
mcp_registry: std::sync::Arc<McpRegistry>,
tools: Vec<McpToolInfo>,
) {
for info in tools {
let adapter = McpToolAdapter::new(mcp_registry.clone(), info);
registry.register_sync(Box::new(adapter));
}
}
pub async fn register_mcp_tools_async(
registry: &crate::tool::ToolRegistry,
mcp_registry: std::sync::Arc<McpRegistry>,
tools: Vec<McpToolInfo>,
) {
for info in tools {
let adapter = McpToolAdapter::new(mcp_registry.clone(), info);
registry.register(Box::new(adapter)).await;
}
}