Skip to main content

codemem_mcp/
types.rs

1//! Protocol types for the MCP JSON-RPC server.
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6// ── JSON-RPC Types ──────────────────────────────────────────────────────────
7
8/// JSON-RPC 2.0 request.
9#[derive(Debug, Deserialize, Serialize)]
10pub struct JsonRpcRequest {
11    pub jsonrpc: String,
12    /// Absent for notifications (no response expected).
13    pub id: Option<Value>,
14    pub method: String,
15    #[serde(default)]
16    pub params: Option<Value>,
17}
18
19/// JSON-RPC 2.0 response.
20#[derive(Debug, Serialize)]
21pub struct JsonRpcResponse {
22    pub jsonrpc: String,
23    pub id: Value,
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub result: Option<Value>,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub error: Option<JsonRpcError>,
28}
29
30/// JSON-RPC 2.0 error object.
31#[derive(Debug, Serialize)]
32pub struct JsonRpcError {
33    pub code: i64,
34    pub message: String,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub data: Option<Value>,
37}
38
39impl JsonRpcResponse {
40    pub fn success(id: Value, result: Value) -> Self {
41        Self {
42            jsonrpc: "2.0".to_string(),
43            id,
44            result: Some(result),
45            error: None,
46        }
47    }
48
49    pub fn error(id: Value, code: i64, message: impl Into<String>) -> Self {
50        Self {
51            jsonrpc: "2.0".to_string(),
52            id,
53            result: None,
54            error: Some(JsonRpcError {
55                code,
56                message: message.into(),
57                data: None,
58            }),
59        }
60    }
61}
62
63// ── Tool Result Types ───────────────────────────────────────────────────────
64
65/// MCP tool result (content array + isError flag).
66#[derive(Debug, Serialize)]
67pub struct ToolResult {
68    pub content: Vec<ToolContent>,
69    #[serde(rename = "isError")]
70    pub is_error: bool,
71}
72
73/// A single content block in a tool result.
74#[derive(Debug, Serialize)]
75pub struct ToolContent {
76    #[serde(rename = "type")]
77    pub content_type: String,
78    pub text: String,
79}
80
81impl ToolResult {
82    pub fn text(msg: impl Into<String>) -> Self {
83        Self {
84            content: vec![ToolContent {
85                content_type: "text".to_string(),
86                text: msg.into(),
87            }],
88            is_error: false,
89        }
90    }
91
92    pub fn tool_error(msg: impl Into<String>) -> Self {
93        Self {
94            content: vec![ToolContent {
95                content_type: "text".to_string(),
96                text: msg.into(),
97            }],
98            is_error: true,
99        }
100    }
101}
102
103// ── Index Cache ─────────────────────────────────────────────────────────────
104
105/// Cached code-index results for structural queries.
106pub(crate) struct IndexCache {
107    pub(crate) symbols: Vec<codemem_index::Symbol>,
108    #[allow(dead_code)]
109    pub(crate) chunks: Vec<codemem_index::CodeChunk>,
110    pub(crate) root_path: String,
111}
112
113#[cfg(test)]
114#[path = "tests/types_tests.rs"]
115mod tests;