ricecoder_mcp/
registry.rs1use crate::error::Result;
4use crate::metadata::ToolMetadata;
5use std::collections::HashMap;
6
7#[derive(Debug, Clone)]
9pub struct ToolRegistry {
10 tools: HashMap<String, ToolMetadata>,
11}
12
13impl ToolRegistry {
14 pub fn new() -> Self {
16 Self {
17 tools: HashMap::new(),
18 }
19 }
20
21 pub fn register_tool(&mut self, tool: ToolMetadata) -> Result<()> {
23 if self.tools.contains_key(&tool.id) {
25 return Err(crate::error::Error::NamingConflict(format!(
26 "Tool with ID '{}' already exists",
27 tool.id
28 )));
29 }
30
31 self.tools.insert(tool.id.clone(), tool);
32 Ok(())
33 }
34
35 pub fn get_tool(&self, id: &str) -> Option<&ToolMetadata> {
37 self.tools.get(id)
38 }
39
40 pub fn list_tools(&self) -> Vec<&ToolMetadata> {
42 self.tools.values().collect()
43 }
44
45 pub fn list_tools_by_category(&self, category: &str) -> Vec<&ToolMetadata> {
47 self.tools
48 .values()
49 .filter(|t| t.category == category)
50 .collect()
51 }
52
53 pub fn list_tools_by_server(&self, server_id: &str) -> Vec<&ToolMetadata> {
55 self.tools
56 .values()
57 .filter(|t| t.server_id.as_deref() == Some(server_id))
58 .collect()
59 }
60
61 pub fn tool_count(&self) -> usize {
63 self.tools.len()
64 }
65}
66
67impl Default for ToolRegistry {
68 fn default() -> Self {
69 Self::new()
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use crate::metadata::ToolSource;
77
78 #[test]
79 fn test_register_tool() {
80 let mut registry = ToolRegistry::new();
81 let tool = ToolMetadata {
82 id: "test-tool".to_string(),
83 name: "Test Tool".to_string(),
84 description: "A test tool".to_string(),
85 category: "test".to_string(),
86 parameters: vec![],
87 return_type: "string".to_string(),
88 source: ToolSource::Custom,
89 server_id: None,
90 };
91
92 let result = registry.register_tool(tool);
93 assert!(result.is_ok());
94 assert_eq!(registry.tool_count(), 1);
95 }
96
97 #[test]
98 fn test_register_duplicate_tool() {
99 let mut registry = ToolRegistry::new();
100 let tool = ToolMetadata {
101 id: "test-tool".to_string(),
102 name: "Test Tool".to_string(),
103 description: "A test tool".to_string(),
104 category: "test".to_string(),
105 parameters: vec![],
106 return_type: "string".to_string(),
107 source: ToolSource::Custom,
108 server_id: None,
109 };
110
111 registry.register_tool(tool.clone()).unwrap();
112 let result = registry.register_tool(tool);
113 assert!(result.is_err());
114 }
115
116 #[test]
117 fn test_get_tool() {
118 let mut registry = ToolRegistry::new();
119 let tool = ToolMetadata {
120 id: "test-tool".to_string(),
121 name: "Test Tool".to_string(),
122 description: "A test tool".to_string(),
123 category: "test".to_string(),
124 parameters: vec![],
125 return_type: "string".to_string(),
126 source: ToolSource::Custom,
127 server_id: None,
128 };
129
130 registry.register_tool(tool).unwrap();
131 let retrieved = registry.get_tool("test-tool");
132 assert!(retrieved.is_some());
133 assert_eq!(retrieved.unwrap().name, "Test Tool");
134 }
135
136 #[test]
137 fn test_list_tools_by_category() {
138 let mut registry = ToolRegistry::new();
139 let tool1 = ToolMetadata {
140 id: "tool1".to_string(),
141 name: "Tool 1".to_string(),
142 description: "Tool 1".to_string(),
143 category: "math".to_string(),
144 parameters: vec![],
145 return_type: "number".to_string(),
146 source: ToolSource::Custom,
147 server_id: None,
148 };
149
150 let tool2 = ToolMetadata {
151 id: "tool2".to_string(),
152 name: "Tool 2".to_string(),
153 description: "Tool 2".to_string(),
154 category: "string".to_string(),
155 parameters: vec![],
156 return_type: "string".to_string(),
157 source: ToolSource::Custom,
158 server_id: None,
159 };
160
161 registry.register_tool(tool1).unwrap();
162 registry.register_tool(tool2).unwrap();
163
164 let math_tools = registry.list_tools_by_category("math");
165 assert_eq!(math_tools.len(), 1);
166 assert_eq!(math_tools[0].id, "tool1");
167 }
168}