telos_agent/integrations/mcp/
bridge.rs1use async_trait::async_trait;
2use serde_json::Value;
3use std::sync::Arc;
4
5use crate::error::AgentError;
6use crate::integrations::mcp::client::McpTool;
7use crate::integrations::mcp::manager::McpManager;
8use crate::tools::api::{PermissionDecision, Tool, ToolContext, ToolDefinition, ToolOutput};
9
10pub struct McpToolBridge {
15 server_id: String,
16 mcp_tool: McpTool,
17 manager: Arc<McpManager>,
18}
19
20impl McpToolBridge {
21 pub fn new(server_id: String, mcp_tool: McpTool, manager: Arc<McpManager>) -> Self {
23 Self { server_id, mcp_tool, manager }
24 }
25
26 pub fn normalized_name(server_id: &str, tool_name: &str) -> String {
31 format!("mcp__{server_id}__{tool_name}")
32 }
33}
34
35#[async_trait]
36impl Tool for McpToolBridge {
37 fn definition(&self) -> ToolDefinition {
38 ToolDefinition {
39 name: Self::normalized_name(&self.server_id, &self.mcp_tool.name),
40 description: format!("[MCP:{}] {}", self.server_id, self.mcp_tool.description),
41 input_schema: self.mcp_tool.input_schema.clone(),
42 }
43 }
44
45 fn is_concurrency_safe(&self, _arguments: &Value) -> bool {
46 false
47 }
48
49 async fn check_permission(
50 &self,
51 _arguments: &Value,
52 _context: &ToolContext,
53 ) -> Result<PermissionDecision, AgentError> {
54 Ok(PermissionDecision::Ask {
55 reason: format!("MCP tool '{}' from server '{}'", self.mcp_tool.name, self.server_id),
56 })
57 }
58
59 async fn invoke(
60 &self,
61 arguments: Value,
62 _context: ToolContext,
63 ) -> Result<ToolOutput, AgentError> {
64 let result =
65 self.manager.call_tool(&self.server_id, &self.mcp_tool.name, arguments).await?;
66 Ok(ToolOutput::json(result))
67 }
68}