1pub 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#[async_trait]
14pub trait Tool: Send + Sync {
15 fn definition(&self) -> McpTool;
17
18 async fn execute(
20 &self,
21 arguments: serde_json::Value,
22 ) -> std::result::Result<CallToolResult, CallToolError>;
23}
24
25pub struct ToolRegistry {
27 tools: Vec<Box<dyn Tool>>,
28}
29
30impl ToolRegistry {
31 #[must_use]
33 pub fn new() -> Self {
34 Self { tools: Vec::new() }
35 }
36
37 #[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 #[must_use]
46 pub fn get_tools(&self) -> Vec<McpTool> {
47 self.tools.iter().map(|t| t.definition()).collect()
48 }
49
50 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#[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}