atomcode_core/mcp/
tool_adapter.rs1use anyhow::Result;
4use async_trait::async_trait;
5use serde_json::json;
6
7use crate::tool::{ApprovalRequirement, Tool, ToolContext, ToolDef, ToolResult};
8
9use super::client::McpToolInfo;
10use super::registry::McpRegistry;
11
12pub struct McpToolAdapter {
14 registry: std::sync::Arc<McpRegistry>,
15 info: McpToolInfo,
16 tool_name: String, }
18
19impl McpToolAdapter {
20 pub fn new(registry: std::sync::Arc<McpRegistry>, info: McpToolInfo) -> Self {
22 let tool_name = format!("mcp__{}__{}", info.server_name, info.tool_name);
23 Self {
24 registry,
25 info,
26 tool_name,
27 }
28 }
29
30 pub fn full_name(&self) -> &str {
32 &self.tool_name
33 }
34}
35
36#[async_trait]
37impl Tool for McpToolAdapter {
38 fn definition(&self) -> ToolDef {
39 ToolDef {
40 name: Box::leak(self.tool_name.clone().into_boxed_str()),
41 description: if self.info.description.is_empty() {
42 format!(
43 "MCP tool from server '{}'. See input schema for details.",
44 self.info.server_name
45 )
46 } else {
47 format!(
48 "[MCP:{}] {}",
49 self.info.server_name, self.info.description
50 )
51 },
52 parameters: self.info.input_schema.clone(),
53 }
54 }
55
56 fn approval(&self, args: &str) -> ApprovalRequirement {
57 ApprovalRequirement::RequireApproval(format!(
59 "MCP tool '{}' from server '{}' wants to execute with arguments: {}",
60 self.info.tool_name, self.info.server_name, args
61 ))
62 }
63
64 async fn execute(&self, args: &str, _ctx: &ToolContext) -> Result<ToolResult> {
65 let arguments: serde_json::Value = if args.is_empty() || args == "{}" {
66 json!({})
67 } else {
68 serde_json::from_str(args)?
69 };
70
71 let output = self
72 .registry
73 .call_tool(&self.info.server_name, &self.info.tool_name, arguments)
74 .await?;
75
76 Ok(ToolResult {
77 call_id: String::new(),
78 output,
79 success: true,
80 })
81 }
82}
83
84pub fn register_mcp_tools(
87 registry: &mut crate::tool::ToolRegistry,
88 mcp_registry: std::sync::Arc<McpRegistry>,
89 tools: Vec<McpToolInfo>,
90) {
91 for info in tools {
92 let adapter = McpToolAdapter::new(mcp_registry.clone(), info);
93 registry.register_sync(Box::new(adapter));
94 }
95}
96
97pub async fn register_mcp_tools_async(
100 registry: &crate::tool::ToolRegistry,
101 mcp_registry: std::sync::Arc<McpRegistry>,
102 tools: Vec<McpToolInfo>,
103) {
104 for info in tools {
105 let adapter = McpToolAdapter::new(mcp_registry.clone(), info);
106 registry.register(Box::new(adapter)).await;
107 }
108}