Skip to main content

mcp_plugin_api/
tool.rs

1//! Type-safe tool definitions
2//!
3//! This module provides a high-level API for defining tools with
4//! compile-time type checking and automatic JSON schema generation.
5
6use serde_json::{json, Value};
7
8/// A parameter definition for a tool
9#[derive(Debug, Clone)]
10pub struct ToolParam {
11    pub name: String,
12    pub description: String,
13    pub param_type: ParamType,
14    pub required: bool,
15}
16
17/// Parameter type enumeration
18#[derive(Debug, Clone)]
19pub enum ParamType {
20    String,
21    Integer,
22    Number,
23    Boolean,
24    Object,
25    Array,
26}
27
28impl ParamType {
29    /// Convert to JSON Schema type string
30    pub fn to_json_type(&self) -> &'static str {
31        match self {
32            ParamType::String => "string",
33            ParamType::Integer => "integer",
34            ParamType::Number => "number",
35            ParamType::Boolean => "boolean",
36            ParamType::Object => "object",
37            ParamType::Array => "array",
38        }
39    }
40}
41
42/// Tool handler function type
43///
44/// A tool handler takes JSON arguments and returns either a JSON result
45/// or an error message.
46pub type ToolHandler = fn(&Value) -> Result<Value, String>;
47
48/// A tool definition
49///
50/// This represents a single tool with its metadata and handler function.
51pub struct Tool {
52    pub name: String,
53    pub description: String,
54    pub params: Vec<ToolParam>,
55    pub handler: ToolHandler,
56}
57
58impl Tool {
59    /// Create a new tool definition with a builder
60    ///
61    /// # Example
62    ///
63    /// ```ignore
64    /// Tool::new("get_price", "Get the price of a product")
65    ///     .param_i64("product_id", "The product ID", true)
66    ///     .handler(handle_get_price)
67    /// ```
68    pub fn builder(name: &str, description: &str) -> ToolBuilder {
69        ToolBuilder {
70            name: name.to_string(),
71            description: description.to_string(),
72            params: Vec::new(),
73        }
74    }
75    
76    /// Convert tool definition to JSON Schema format
77    ///
78    /// Returns a JSON object compatible with MCP protocol:
79    /// ```json
80    /// {
81    ///   "name": "tool_name",
82    ///   "description": "Tool description",
83    ///   "inputSchema": {
84    ///     "type": "object",
85    ///     "properties": { ... },
86    ///     "required": [ ... ]
87    ///   }
88    /// }
89    /// ```
90    pub fn to_json_schema(&self) -> Value {
91        let mut properties = serde_json::Map::new();
92        let mut required = Vec::new();
93        
94        for param in &self.params {
95            properties.insert(
96                param.name.clone(),
97                json!({
98                    "type": param.param_type.to_json_type(),
99                    "description": param.description
100                })
101            );
102            
103            if param.required {
104                required.push(param.name.clone());
105            }
106        }
107        
108        json!({
109            "name": self.name,
110            "description": self.description,
111            "inputSchema": {
112                "type": "object",
113                "properties": properties,
114                "required": required
115            }
116        })
117    }
118}
119
120/// Builder for creating tools with a fluent API
121pub struct ToolBuilder {
122    name: String,
123    description: String,
124    params: Vec<ToolParam>,
125}
126
127impl ToolBuilder {
128    /// Add a string parameter
129    ///
130    /// # Arguments
131    /// * `name` - Parameter name
132    /// * `description` - Parameter description
133    /// * `required` - Whether the parameter is required
134    pub fn param_string(mut self, name: &str, description: &str, required: bool) -> Self {
135        self.params.push(ToolParam {
136            name: name.to_string(),
137            description: description.to_string(),
138            param_type: ParamType::String,
139            required,
140        });
141        self
142    }
143    
144    /// Add an integer parameter (i64)
145    pub fn param_i64(mut self, name: &str, description: &str, required: bool) -> Self {
146        self.params.push(ToolParam {
147            name: name.to_string(),
148            description: description.to_string(),
149            param_type: ParamType::Integer,
150            required,
151        });
152        self
153    }
154    
155    /// Add a number parameter (f64)
156    pub fn param_f64(mut self, name: &str, description: &str, required: bool) -> Self {
157        self.params.push(ToolParam {
158            name: name.to_string(),
159            description: description.to_string(),
160            param_type: ParamType::Number,
161            required,
162        });
163        self
164    }
165    
166    /// Add a boolean parameter
167    pub fn param_bool(mut self, name: &str, description: &str, required: bool) -> Self {
168        self.params.push(ToolParam {
169            name: name.to_string(),
170            description: description.to_string(),
171            param_type: ParamType::Boolean,
172            required,
173        });
174        self
175    }
176    
177    /// Add an object parameter
178    pub fn param_object(mut self, name: &str, description: &str, required: bool) -> Self {
179        self.params.push(ToolParam {
180            name: name.to_string(),
181            description: description.to_string(),
182            param_type: ParamType::Object,
183            required,
184        });
185        self
186    }
187    
188    /// Add an array parameter
189    pub fn param_array(mut self, name: &str, description: &str, required: bool) -> Self {
190        self.params.push(ToolParam {
191            name: name.to_string(),
192            description: description.to_string(),
193            param_type: ParamType::Array,
194            required,
195        });
196        self
197    }
198    
199    /// Set the handler function and finalize the tool
200    ///
201    /// This consumes the builder and returns the completed Tool.
202    pub fn handler(self, handler: ToolHandler) -> Tool {
203        Tool {
204            name: self.name,
205            description: self.description,
206            params: self.params,
207            handler,
208        }
209    }
210}
211