rmcp_openapi/tool/
metadata.rs

1use rmcp::model::{Tool, ToolAnnotations};
2use serde_json::Value;
3use std::sync::Arc;
4
5/// Internal metadata for tools generated from OpenAPI operations.
6///
7/// This struct contains all the information needed to execute HTTP requests
8/// and is used internally by the OpenAPI server. It includes fields that are
9/// not part of the MCP specification but are necessary for HTTP execution.
10///
11/// For MCP compliance, this struct is converted to `rmcp::model::Tool` using
12/// the `From` trait implementation, which only includes MCP-compliant fields.
13#[derive(Debug, Clone, serde::Serialize)]
14pub struct ToolMetadata {
15    /// Tool name - exposed to MCP clients
16    pub name: String,
17    /// Tool title - human-readable display name exposed to MCP clients
18    pub title: Option<String>,
19    /// Tool description - exposed to MCP clients  
20    pub description: String,
21    /// Input parameters schema - exposed to MCP clients as `inputSchema`
22    pub parameters: Value,
23    /// Output schema - exposed to MCP clients as `outputSchema`
24    pub output_schema: Option<Value>,
25    /// HTTP method (GET, POST, etc.) - internal only, not exposed to MCP
26    pub method: String,
27    /// URL path for the API endpoint - internal only, not exposed to MCP
28    pub path: String,
29}
30
31/// Converts internal `ToolMetadata` to MCP-compliant `Tool`.
32///
33/// This implementation ensures that only MCP-compliant fields are exposed to clients.
34/// Internal fields like `method` and `path` are not included in the conversion.
35impl From<&ToolMetadata> for Tool {
36    fn from(metadata: &ToolMetadata) -> Self {
37        // Convert parameters to the expected Arc<Map> format
38        let input_schema = if let Value::Object(obj) = &metadata.parameters {
39            Arc::new(obj.clone())
40        } else {
41            Arc::new(serde_json::Map::new())
42        };
43
44        // Convert output_schema to the expected Arc<Map> format if present
45        let output_schema = metadata.output_schema.as_ref().and_then(|schema| {
46            if let Value::Object(obj) = schema {
47                Some(Arc::new(obj.clone()))
48            } else {
49                None
50            }
51        });
52
53        // Create annotations with title if present
54        let annotations = metadata.title.as_ref().map(|title| ToolAnnotations {
55            title: Some(title.clone()),
56            ..Default::default()
57        });
58
59        Tool {
60            name: metadata.name.clone().into(),
61            description: Some(metadata.description.clone().into()),
62            input_schema,
63            output_schema,
64            annotations,
65            // TODO: Consider migration to Tool.title when rmcp supports MCP 2025-06-18 (see issue #26)
66        }
67    }
68}