chasm_cli/mcp/
types.rs

1// Copyright (c) 2024-2026 Nervosys LLC
2// SPDX-License-Identifier: Apache-2.0
3//! MCP Server Types - JSON-RPC message definitions for MCP protocol
4
5#![allow(dead_code)]
6
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9
10/// JSON-RPC Request
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct JsonRpcRequest {
13    pub jsonrpc: String,
14    pub id: Option<serde_json::Value>,
15    pub method: String,
16    #[serde(default)]
17    pub params: serde_json::Value,
18}
19
20/// JSON-RPC Response
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct JsonRpcResponse {
23    pub jsonrpc: String,
24    pub id: Option<serde_json::Value>,
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub result: Option<serde_json::Value>,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub error: Option<JsonRpcError>,
29}
30
31/// JSON-RPC Error
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct JsonRpcError {
34    pub code: i32,
35    pub message: String,
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub data: Option<serde_json::Value>,
38}
39
40impl JsonRpcResponse {
41    pub fn success(id: Option<serde_json::Value>, result: serde_json::Value) -> Self {
42        Self {
43            jsonrpc: "2.0".to_string(),
44            id,
45            result: Some(result),
46            error: None,
47        }
48    }
49
50    pub fn error(id: Option<serde_json::Value>, code: i32, message: String) -> Self {
51        Self {
52            jsonrpc: "2.0".to_string(),
53            id,
54            result: None,
55            error: Some(JsonRpcError {
56                code,
57                message,
58                data: None,
59            }),
60        }
61    }
62}
63
64// ============================================================================
65// MCP Protocol Types
66// ============================================================================
67
68/// Server capabilities
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct ServerCapabilities {
71    #[serde(skip_serializing_if = "Option::is_none")]
72    pub tools: Option<ToolsCapability>,
73    #[serde(skip_serializing_if = "Option::is_none")]
74    pub resources: Option<ResourcesCapability>,
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub prompts: Option<PromptsCapability>,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct ToolsCapability {
81    #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
82    pub list_changed: Option<bool>,
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct ResourcesCapability {
87    #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
88    pub list_changed: Option<bool>,
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub subscribe: Option<bool>,
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct PromptsCapability {
95    #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
96    pub list_changed: Option<bool>,
97}
98
99/// Initialize request params
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct InitializeParams {
102    #[serde(rename = "protocolVersion")]
103    pub protocol_version: String,
104    pub capabilities: ClientCapabilities,
105    #[serde(rename = "clientInfo")]
106    pub client_info: ClientInfo,
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct ClientCapabilities {
111    #[serde(skip_serializing_if = "Option::is_none")]
112    pub roots: Option<serde_json::Value>,
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub sampling: Option<serde_json::Value>,
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize)]
118pub struct ClientInfo {
119    pub name: String,
120    #[serde(skip_serializing_if = "Option::is_none")]
121    pub version: Option<String>,
122}
123
124/// Initialize response
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct InitializeResult {
127    #[serde(rename = "protocolVersion")]
128    pub protocol_version: String,
129    pub capabilities: ServerCapabilities,
130    #[serde(rename = "serverInfo")]
131    pub server_info: ServerInfo,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct ServerInfo {
136    pub name: String,
137    #[serde(skip_serializing_if = "Option::is_none")]
138    pub version: Option<String>,
139}
140
141// ============================================================================
142// Tool Types
143// ============================================================================
144
145/// Tool definition
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct Tool {
148    pub name: String,
149    #[serde(skip_serializing_if = "Option::is_none")]
150    pub description: Option<String>,
151    #[serde(rename = "inputSchema")]
152    pub input_schema: serde_json::Value,
153}
154
155/// Tool call request params
156#[derive(Debug, Clone, Serialize, Deserialize)]
157pub struct CallToolParams {
158    pub name: String,
159    #[serde(default)]
160    pub arguments: HashMap<String, serde_json::Value>,
161}
162
163/// Tool call result
164#[derive(Debug, Clone, Serialize, Deserialize)]
165pub struct CallToolResult {
166    pub content: Vec<ToolContent>,
167    #[serde(rename = "isError", skip_serializing_if = "Option::is_none")]
168    pub is_error: Option<bool>,
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
172#[serde(tag = "type")]
173pub enum ToolContent {
174    #[serde(rename = "text")]
175    Text { text: String },
176    #[serde(rename = "image")]
177    Image { data: String, mime_type: String },
178    #[serde(rename = "resource")]
179    Resource { resource: ResourceContent },
180}
181
182// ============================================================================
183// Resource Types
184// ============================================================================
185
186/// Resource definition
187#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct Resource {
189    pub uri: String,
190    pub name: String,
191    #[serde(skip_serializing_if = "Option::is_none")]
192    pub description: Option<String>,
193    #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
194    pub mime_type: Option<String>,
195}
196
197/// Resource content
198#[derive(Debug, Clone, Serialize, Deserialize)]
199pub struct ResourceContent {
200    pub uri: String,
201    #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
202    pub mime_type: Option<String>,
203    #[serde(skip_serializing_if = "Option::is_none")]
204    pub text: Option<String>,
205    #[serde(skip_serializing_if = "Option::is_none")]
206    pub blob: Option<String>,
207}
208
209/// Read resource params
210#[derive(Debug, Clone, Serialize, Deserialize)]
211pub struct ReadResourceParams {
212    pub uri: String,
213}
214
215/// Read resource result
216#[derive(Debug, Clone, Serialize, Deserialize)]
217pub struct ReadResourceResult {
218    pub contents: Vec<ResourceContent>,
219}
220
221// ============================================================================
222// CSM-Specific Types
223// ============================================================================
224
225/// Workspace info for MCP responses
226#[derive(Debug, Clone, Serialize, Deserialize)]
227pub struct WorkspaceInfo {
228    pub hash: String,
229    pub project_path: String,
230    pub session_count: usize,
231    pub has_chats: bool,
232}
233
234/// Session info for MCP responses
235#[derive(Debug, Clone, Serialize, Deserialize)]
236pub struct SessionInfo {
237    pub id: String,
238    pub title: String,
239    pub message_count: usize,
240    pub last_modified: String,
241    pub is_orphaned: bool,
242    pub workspace_hash: String,
243    pub file_path: String,
244}
245
246/// Orphaned session info
247#[derive(Debug, Clone, Serialize, Deserialize)]
248pub struct OrphanedSessionInfo {
249    pub id: String,
250    pub title: String,
251    pub message_count: usize,
252    pub file_path: String,
253}