Skip to main content

embacle_server/mcp/tools/
mod.rs

1// ABOUTME: Tool registry mapping MCP tool names to stateless handler implementations
2// ABOUTME: Provides McpTool trait and ToolRegistry for discovery and dispatch via provider routing
3//
4// SPDX-License-Identifier: Apache-2.0
5// Copyright (c) 2026 dravr.ai
6
7pub mod list_models;
8pub mod prompt;
9
10use std::collections::HashMap;
11
12use async_trait::async_trait;
13use serde_json::Value;
14
15use super::protocol::{CallToolResult, ToolDefinition};
16use crate::state::SharedState;
17
18/// Trait implemented by each MCP tool exposed by this server
19#[async_trait]
20pub trait McpTool: Send + Sync {
21    /// Return the tool's MCP definition (name, description, input schema)
22    fn definition(&self) -> ToolDefinition;
23
24    /// Execute the tool with the given arguments against the shared server state
25    async fn execute(&self, state: &SharedState, arguments: Value) -> CallToolResult;
26}
27
28/// Registry mapping tool names to their handler implementations
29#[derive(Default)]
30pub struct ToolRegistry {
31    tools: HashMap<String, Box<dyn McpTool>>,
32}
33
34impl ToolRegistry {
35    /// Create an empty registry
36    pub fn new() -> Self {
37        Self::default()
38    }
39
40    /// Register a tool handler, keyed by its definition name
41    pub fn register(&mut self, tool: Box<dyn McpTool>) {
42        let name = tool.definition().name;
43        self.tools.insert(name, tool);
44    }
45
46    /// List all registered tool definitions for `tools/list` responses
47    pub fn list_definitions(&self) -> Vec<ToolDefinition> {
48        self.tools.values().map(|t| t.definition()).collect()
49    }
50
51    /// Dispatch a `tools/call` to the named tool handler
52    pub async fn execute(
53        &self,
54        name: &str,
55        state: &SharedState,
56        arguments: Value,
57    ) -> CallToolResult {
58        match self.tools.get(name) {
59            Some(tool) => tool.execute(state, arguments).await,
60            None => CallToolResult::error(format!("Unknown tool: {name}")),
61        }
62    }
63}
64
65/// Build the tool registry with stateless tools for the unified server
66pub fn build_tool_registry() -> ToolRegistry {
67    let mut registry = ToolRegistry::new();
68    registry.register(Box::new(prompt::Prompt));
69    registry.register(Box::new(list_models::ListModels));
70    registry
71}