Skip to main content

crates_docs/tools/
mod.rs

1//! MCP tools module
2//!
3//! Provides MCP tools for Rust crate documentation queries.
4
5pub mod docs;
6pub mod health;
7
8use async_trait::async_trait;
9use rust_mcp_sdk::schema::{CallToolError, CallToolResult, Tool as McpTool};
10use std::sync::Arc;
11
12/// Tool trait
13#[async_trait]
14pub trait Tool: Send + Sync {
15    /// Get tool definition
16    fn definition(&self) -> McpTool;
17
18    /// Execute tool
19    async fn execute(
20        &self,
21        arguments: serde_json::Value,
22    ) -> std::result::Result<CallToolResult, CallToolError>;
23}
24
25/// Tool registry
26pub struct ToolRegistry {
27    tools: Vec<Box<dyn Tool>>,
28}
29
30impl ToolRegistry {
31    /// Create a new tool registry
32    #[must_use]
33    pub fn new() -> Self {
34        Self { tools: Vec::new() }
35    }
36
37    /// Register tool
38    #[must_use]
39    pub fn register<T: Tool + 'static>(mut self, tool: T) -> Self {
40        self.tools.push(Box::new(tool));
41        self
42    }
43
44    /// Get all tool definitions
45    #[must_use]
46    pub fn get_tools(&self) -> Vec<McpTool> {
47        self.tools.iter().map(|t| t.definition()).collect()
48    }
49
50    /// Execute tool
51    pub async fn execute_tool(
52        &self,
53        name: &str,
54        arguments: serde_json::Value,
55    ) -> std::result::Result<CallToolResult, CallToolError> {
56        for tool in &self.tools {
57            if tool.definition().name == name {
58                return tool.execute(arguments).await;
59            }
60        }
61
62        Err(CallToolError::unknown_tool(name.to_string()))
63    }
64}
65
66impl Default for ToolRegistry {
67    fn default() -> Self {
68        Self::new()
69    }
70}
71
72/// Create default tool registry
73#[must_use]
74pub fn create_default_registry(service: &Arc<docs::DocService>) -> ToolRegistry {
75    ToolRegistry::new()
76        .register(docs::lookup::LookupCrateToolImpl::new(service.clone()))
77        .register(docs::search::SearchCratesToolImpl::new(service.clone()))
78        .register(docs::lookup::LookupItemToolImpl::new(service.clone()))
79        .register(health::HealthCheckToolImpl::new())
80}