rustapi_mcp/types.rs
1//! Core MCP data types (tool definitions, requests, responses, capabilities).
2//!
3//! These types are intentionally high-level for the foundation phase.
4//! They will be expanded with full JSON-RPC message shapes when we implement transports.
5
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9/// A capability that this MCP server advertises during `initialize`.
10#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
11#[serde(rename_all = "camelCase")]
12pub enum McpCapability {
13 /// The server can list and invoke tools.
14 Tools,
15 /// Future: resources, prompts, sampling, etc.
16 #[serde(other)]
17 Other,
18}
19
20/// A tool description that will be sent to MCP clients in `tools/list`.
21#[derive(Debug, Clone, Serialize, Deserialize)]
22#[serde(rename_all = "camelCase")]
23pub struct McpTool {
24 /// Stable name of the tool (usually derived from path + method or a slug).
25 pub name: String,
26
27 /// Human readable description (comes from OpenAPI `summary` / `description` when available).
28 #[serde(skip_serializing_if = "Option::is_none")]
29 pub description: Option<String>,
30
31 /// JSON Schema for the input parameters (reused from `rustapi-openapi` / `Schema` derive).
32 pub input_schema: serde_json::Value,
33
34 /// Optional JSON Schema for the output (when we have good response schemas).
35 #[serde(skip_serializing_if = "Option::is_none")]
36 pub output_schema: Option<serde_json::Value>,
37
38 /// Tags associated with this tool (used for filtering via `McpConfig`).
39 #[serde(default, skip_serializing_if = "Vec::is_empty")]
40 pub tags: Vec<String>,
41}
42
43/// Request from an MCP client to call a tool.
44#[derive(Debug, Clone, Deserialize)]
45#[serde(rename_all = "camelCase")]
46pub struct ToolCallRequest {
47 /// Name of the tool to invoke.
48 pub name: String,
49 /// Arguments passed to the tool (will be turned into extractors later).
50 #[serde(default)]
51 pub arguments: HashMap<String, serde_json::Value>,
52}
53
54/// Successful result of a tool call.
55#[derive(Debug, Clone, Serialize)]
56#[serde(rename_all = "camelCase")]
57pub struct ToolCallResponse {
58 /// The actual content returned by the underlying handler (serialized appropriately).
59 pub content: serde_json::Value,
60
61 /// Whether this result should be treated as an error by the agent (even if HTTP 2xx).
62 #[serde(default)]
63 pub is_error: bool,
64
65 /// Optional metadata (token counts when using TOON, execution path, etc.).
66 #[serde(skip_serializing_if = "Option::is_none")]
67 pub meta: Option<serde_json::Value>,
68}
69
70impl ToolCallResponse {
71 /// Construct a successful tool response.
72 pub fn success(content: impl Serialize) -> Self {
73 Self {
74 content: serde_json::to_value(content).unwrap_or(serde_json::json!({})),
75 is_error: false,
76 meta: None,
77 }
78 }
79
80 /// Construct an error tool response (from the agent's perspective).
81 pub fn error(message: impl Into<String>) -> Self {
82 Self {
83 content: serde_json::json!({ "error": message.into() }),
84 is_error: true,
85 meta: None,
86 }
87 }
88}