Skip to main content

crates_docs/tools/
mod.rs

1//! MCP 工具模块
2//!
3//! 提供用于 Rust crate 文档查询的 MCP 工具。
4//!
5//! # 工具列表
6//!
7//! - `docs::lookup_crate::LookupCrateToolImpl`: 查找 crate 文档
8//! - `docs::search::SearchCratesToolImpl`: 搜索 crate
9//! - `docs::lookup_item::LookupItemToolImpl`: 查找特定项目
10//! - `health::HealthCheckToolImpl`: 健康检查
11//!
12//! # 示例
13//!
14//! ```rust,no_run
15//! use std::sync::Arc;
16//! use crates_docs::tools::{ToolRegistry, create_default_registry};
17//! use crates_docs::tools::docs::DocService;
18//! use crates_docs::cache::memory::MemoryCache;
19//!
20//! let cache = Arc::new(MemoryCache::new(1000));
21//! let doc_service = Arc::new(DocService::new(cache).unwrap());
22//! let registry = create_default_registry(&doc_service);
23//! ```
24
25pub mod docs;
26pub mod health;
27
28use async_trait::async_trait;
29use rust_mcp_sdk::schema::{CallToolError, CallToolResult, Tool as McpTool};
30use std::collections::HashMap;
31use std::sync::Arc;
32
33/// 工具 trait
34///
35/// 定义 MCP 工具的基本接口,包括获取工具定义和执行工具。
36///
37/// # 实现
38///
39/// 所有工具都需要实现此 trait 才能注册到 [`ToolRegistry`]。
40#[async_trait]
41pub trait Tool: Send + Sync {
42    /// 获取工具定义
43    ///
44    /// 返回工具的元数据,包括名称、描述、参数等。
45    fn definition(&self) -> McpTool;
46
47    /// 执行工具
48    ///
49    /// # 参数
50    ///
51    /// * `arguments` - 工具参数(JSON 格式)
52    ///
53    /// # 返回值
54    ///
55    /// 返回工具执行结果或错误
56    async fn execute(
57        &self,
58        arguments: serde_json::Value,
59    ) -> std::result::Result<CallToolResult, CallToolError>;
60}
61
62/// 工具注册表
63///
64/// 使用 `HashMap` 实现 O(1) 查找的工具注册表。
65///
66/// # 字段
67///
68/// - `tools`: 存储工具的字典,键为工具名称
69pub struct ToolRegistry {
70    tools: HashMap<String, Box<dyn Tool>>,
71}
72
73impl ToolRegistry {
74    /// 创建新的工具注册表
75    ///
76    /// # 示例
77    ///
78    /// ```rust
79    /// use crates_docs::tools::ToolRegistry;
80    ///
81    /// let registry = ToolRegistry::new();
82    /// assert!(registry.is_empty());
83    /// ```
84    #[must_use]
85    pub fn new() -> Self {
86        Self {
87            tools: HashMap::new(),
88        }
89    }
90
91    /// 注册工具
92    ///
93    /// # 参数
94    ///
95    /// * `tool` - 要实现 [`Tool`] trait 的工具实例
96    ///
97    /// # 返回值
98    ///
99    /// 返回自身以支持链式调用
100    ///
101    /// # 示例
102    ///
103    /// ```rust,no_run
104    /// use crates_docs::tools::ToolRegistry;
105    /// use crates_docs::tools::health::HealthCheckToolImpl;
106    ///
107    /// let registry = ToolRegistry::new()
108    ///     .register(HealthCheckToolImpl::new());
109    /// ```
110    #[must_use]
111    pub fn register<T: Tool + 'static>(mut self, tool: T) -> Self {
112        let boxed_tool: Box<dyn Tool> = Box::new(tool);
113        let name = boxed_tool.definition().name.clone();
114        self.tools.insert(name, boxed_tool);
115        self
116    }
117
118    /// 获取所有工具定义
119    ///
120    /// # 返回值
121    ///
122    /// 返回所有注册工具的元数据列表
123    #[must_use]
124    pub fn get_tools(&self) -> Vec<McpTool> {
125        self.tools.values().map(|t| t.definition()).collect()
126    }
127
128    /// 按名称执行工具
129    ///
130    /// # 参数
131    ///
132    /// * `name` - 工具名称
133    /// * `arguments` - 工具参数(JSON 格式)
134    ///
135    /// # 返回值
136    ///
137    /// 返回工具执行结果,如果工具不存在返回错误
138    pub async fn execute_tool(
139        &self,
140        name: &str,
141        arguments: serde_json::Value,
142    ) -> std::result::Result<CallToolResult, CallToolError> {
143        match self.tools.get(name) {
144            Some(tool) => tool.execute(arguments).await,
145            None => Err(CallToolError::unknown_tool(name.to_string())),
146        }
147    }
148
149    /// 检查工具是否存在
150    ///
151    /// # 参数
152    ///
153    /// * `name` - 工具名称
154    ///
155    /// # 返回值
156    ///
157    /// 如果工具存在返回 `true`,否则返回 `false`
158    #[must_use]
159    pub fn has_tool(&self, name: &str) -> bool {
160        self.tools.contains_key(name)
161    }
162
163    /// 获取注册工具数量
164    #[must_use]
165    pub fn len(&self) -> usize {
166        self.tools.len()
167    }
168
169    /// 检查注册表是否为空
170    #[must_use]
171    pub fn is_empty(&self) -> bool {
172        self.tools.is_empty()
173    }
174}
175
176impl Default for ToolRegistry {
177    fn default() -> Self {
178        Self::new()
179    }
180}
181
182/// 创建默认工具注册表
183///
184/// 注册所有内置工具:
185/// - `lookup_crate`: 查找 crate 文档
186/// - `search_crates`: 搜索 crate
187/// - `lookup_item`: 查找特定项目
188/// - `health_check`: 健康检查
189///
190/// # 参数
191///
192/// * `service` - 文档服务实例
193///
194/// # 示例
195///
196/// ```rust,no_run
197/// use std::sync::Arc;
198/// use crates_docs::tools::create_default_registry;
199/// use crates_docs::tools::docs::DocService;
200/// use crates_docs::cache::memory::MemoryCache;
201///
202/// let cache = Arc::new(MemoryCache::new(1000));
203/// let doc_service = Arc::new(DocService::new(cache).unwrap());
204/// let registry = create_default_registry(&doc_service);
205/// ```
206#[must_use]
207pub fn create_default_registry(service: &Arc<docs::DocService>) -> ToolRegistry {
208    ToolRegistry::new()
209        .register(docs::lookup_crate::LookupCrateToolImpl::new(
210            service.clone(),
211        ))
212        .register(docs::search::SearchCratesToolImpl::new(service.clone()))
213        .register(docs::lookup_item::LookupItemToolImpl::new(service.clone()))
214        .register(health::HealthCheckToolImpl::new())
215}