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}