pulseengine_mcp_protocol/
model.rs

1//! MCP model types for protocol messages and data structures
2
3use crate::Error;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7/// JSON-RPC 2.0 Request
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct Request {
10    /// JSON-RPC version (always "2.0")
11    pub jsonrpc: String,
12    /// Request method name
13    pub method: String,
14    /// Request parameters
15    #[serde(default = "serde_json::Value::default")]
16    pub params: serde_json::Value,
17    /// Request ID (missing for notifications)
18    #[serde(default = "default_null")]
19    pub id: serde_json::Value,
20}
21
22fn default_null() -> serde_json::Value {
23    serde_json::Value::Null
24}
25
26/// JSON-RPC 2.0 Response
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct Response {
29    /// JSON-RPC version (always "2.0")
30    pub jsonrpc: String,
31    /// Response result (if successful)
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub result: Option<serde_json::Value>,
34    /// Response error (if failed)
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub error: Option<Error>,
37    /// Request ID
38    pub id: serde_json::Value,
39}
40
41/// Protocol version information
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct ProtocolVersion {
44    pub major: u32,
45    pub minor: u32,
46    pub patch: u32,
47}
48
49impl Default for ProtocolVersion {
50    fn default() -> Self {
51        Self {
52            major: 2024,
53            minor: 11,
54            patch: 5,
55        }
56    }
57}
58
59impl std::fmt::Display for ProtocolVersion {
60    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61        write!(f, "{:04}-{:02}-{:02}", self.major, self.minor, self.patch)
62    }
63}
64
65/// Server implementation information
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct Implementation {
68    pub name: String,
69    pub version: String,
70}
71
72/// Server capabilities configuration
73#[derive(Debug, Clone, Serialize, Deserialize, Default)]
74pub struct ServerCapabilities {
75    pub tools: Option<ToolsCapability>,
76    pub resources: Option<ResourcesCapability>,
77    pub prompts: Option<PromptsCapability>,
78    pub logging: Option<LoggingCapability>,
79    pub sampling: Option<SamplingCapability>,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize, Default)]
83pub struct ToolsCapability {
84    pub list_changed: Option<bool>,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize, Default)]
88pub struct ResourcesCapability {
89    pub subscribe: Option<bool>,
90    pub list_changed: Option<bool>,
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize, Default)]
94pub struct PromptsCapability {
95    pub list_changed: Option<bool>,
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize, Default)]
99pub struct LoggingCapability {
100    pub level: Option<String>,
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize, Default)]
104pub struct SamplingCapability {}
105
106impl ServerCapabilities {
107    pub fn builder() -> ServerCapabilitiesBuilder {
108        ServerCapabilitiesBuilder::default()
109    }
110}
111
112#[derive(Default)]
113pub struct ServerCapabilitiesBuilder {
114    capabilities: ServerCapabilities,
115}
116
117impl ServerCapabilitiesBuilder {
118    pub fn enable_tools(mut self) -> Self {
119        self.capabilities.tools = Some(ToolsCapability {
120            list_changed: Some(true),
121        });
122        self
123    }
124
125    pub fn enable_resources(mut self) -> Self {
126        self.capabilities.resources = Some(ResourcesCapability {
127            subscribe: Some(true),
128            list_changed: Some(true),
129        });
130        self
131    }
132
133    pub fn enable_prompts(mut self) -> Self {
134        self.capabilities.prompts = Some(PromptsCapability {
135            list_changed: Some(true),
136        });
137        self
138    }
139
140    pub fn enable_logging(mut self) -> Self {
141        self.capabilities.logging = Some(LoggingCapability {
142            level: Some("info".to_string()),
143        });
144        self
145    }
146
147    pub fn enable_sampling(mut self) -> Self {
148        self.capabilities.sampling = Some(SamplingCapability {});
149        self
150    }
151
152    pub fn build(self) -> ServerCapabilities {
153        self.capabilities
154    }
155}
156
157/// Server information response
158#[derive(Debug, Clone, Serialize, Deserialize)]
159pub struct ServerInfo {
160    pub protocol_version: ProtocolVersion,
161    pub capabilities: ServerCapabilities,
162    pub server_info: Implementation,
163    pub instructions: Option<String>,
164}
165
166/// Tool definition
167#[derive(Debug, Clone, Serialize, Deserialize)]
168#[serde(rename_all = "camelCase")]
169pub struct Tool {
170    pub name: String,
171    pub description: String,
172    pub input_schema: serde_json::Value,
173}
174
175/// List tools result
176#[derive(Debug, Clone, Serialize, Deserialize)]
177#[serde(rename_all = "camelCase")]
178pub struct ListToolsResult {
179    pub tools: Vec<Tool>,
180    #[serde(skip_serializing_if = "Option::is_none")]
181    pub next_cursor: Option<String>,
182}
183
184/// Pagination parameters
185#[derive(Debug, Clone, Serialize, Deserialize)]
186pub struct PaginatedRequestParam {
187    pub cursor: Option<String>,
188}
189
190/// Tool call parameters
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct CallToolRequestParam {
193    pub name: String,
194    pub arguments: Option<serde_json::Value>,
195}
196
197/// Content types for tool responses
198#[derive(Debug, Clone, Serialize, Deserialize)]
199#[serde(tag = "type")]
200pub enum Content {
201    #[serde(rename = "text")]
202    Text { text: String },
203    #[serde(rename = "image")]
204    Image { data: String, mime_type: String },
205    #[serde(rename = "resource")]
206    Resource {
207        resource: String,
208        text: Option<String>,
209    },
210}
211
212impl Content {
213    pub fn text(text: impl Into<String>) -> Self {
214        Self::Text { text: text.into() }
215    }
216
217    pub fn image(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
218        Self::Image {
219            data: data.into(),
220            mime_type: mime_type.into(),
221        }
222    }
223
224    pub fn resource(resource: impl Into<String>, text: Option<String>) -> Self {
225        Self::Resource {
226            resource: resource.into(),
227            text,
228        }
229    }
230
231    /// Get text content if this is a text content type
232    pub fn as_text(&self) -> Option<&Self> {
233        match self {
234            Self::Text { .. } => Some(self),
235            _ => None,
236        }
237    }
238}
239
240/// Text content struct for compatibility
241pub struct TextContent {
242    pub text: String,
243}
244
245impl Content {
246    /// Get text content as TextContent struct for compatibility
247    pub fn as_text_content(&self) -> Option<TextContent> {
248        match self {
249            Self::Text { text } => Some(TextContent { text: text.clone() }),
250            _ => None,
251        }
252    }
253}
254
255/// Tool call result
256#[derive(Debug, Clone, Serialize, Deserialize)]
257pub struct CallToolResult {
258    pub content: Vec<Content>,
259    pub is_error: Option<bool>,
260}
261
262impl CallToolResult {
263    pub fn success(content: Vec<Content>) -> Self {
264        Self {
265            content,
266            is_error: Some(false),
267        }
268    }
269
270    pub fn error(content: Vec<Content>) -> Self {
271        Self {
272            content,
273            is_error: Some(true),
274        }
275    }
276
277    pub fn text(text: impl Into<String>) -> Self {
278        Self::success(vec![Content::text(text)])
279    }
280
281    pub fn error_text(text: impl Into<String>) -> Self {
282        Self::error(vec![Content::text(text)])
283    }
284}
285
286/// Resource definition
287#[derive(Debug, Clone, Serialize, Deserialize)]
288pub struct Resource {
289    pub uri: String,
290    pub name: String,
291    pub description: Option<String>,
292    pub mime_type: Option<String>,
293    pub annotations: Option<Annotations>,
294    #[serde(skip_serializing_if = "Option::is_none")]
295    pub raw: Option<RawResource>,
296}
297
298/// Resource annotations
299#[derive(Debug, Clone, Serialize, Deserialize, Default)]
300pub struct Annotations {
301    pub audience: Option<Vec<String>>,
302    pub priority: Option<f32>,
303}
304
305/// List resources result
306#[derive(Debug, Clone, Serialize, Deserialize)]
307pub struct ListResourcesResult {
308    pub resources: Vec<Resource>,
309    #[serde(skip_serializing_if = "Option::is_none")]
310    pub next_cursor: Option<String>,
311}
312
313/// Read resource parameters
314#[derive(Debug, Clone, Serialize, Deserialize)]
315pub struct ReadResourceRequestParam {
316    pub uri: String,
317}
318
319/// Resource contents wrapper
320#[derive(Debug, Clone, Serialize, Deserialize)]
321pub struct ResourceContents {
322    pub uri: String,
323    pub mime_type: Option<String>,
324    pub text: Option<String>,
325    pub blob: Option<String>,
326}
327
328/// Read resource result
329#[derive(Debug, Clone, Serialize, Deserialize)]
330pub struct ReadResourceResult {
331    pub contents: Vec<ResourceContents>,
332}
333
334/// Raw resource (for internal use)
335#[derive(Debug, Clone, Serialize, Deserialize)]
336pub struct RawResource {
337    pub uri: String,
338    pub data: Vec<u8>,
339    pub mime_type: Option<String>,
340    pub name: Option<String>,
341    pub description: Option<String>,
342    pub size: Option<usize>,
343}
344
345impl PromptMessage {
346    /// Create a new text message
347    pub fn new_text(role: PromptMessageRole, text: impl Into<String>) -> Self {
348        Self {
349            role,
350            content: PromptMessageContent::Text { text: text.into() },
351        }
352    }
353
354    /// Create a new image message
355    pub fn new_image(
356        role: PromptMessageRole,
357        data: impl Into<String>,
358        mime_type: impl Into<String>,
359    ) -> Self {
360        Self {
361            role,
362            content: PromptMessageContent::Image {
363                data: data.into(),
364                mime_type: mime_type.into(),
365            },
366        }
367    }
368}
369
370impl CompleteResult {
371    /// Create a simple completion result
372    pub fn simple(completion: impl Into<String>) -> Self {
373        Self {
374            completion: vec![CompletionInfo {
375                completion: completion.into(),
376                has_more: Some(false),
377            }],
378        }
379    }
380}
381
382/// Prompt definition
383#[derive(Debug, Clone, Serialize, Deserialize)]
384pub struct Prompt {
385    pub name: String,
386    pub description: Option<String>,
387    pub arguments: Option<Vec<PromptArgument>>,
388}
389
390/// Prompt argument definition
391#[derive(Debug, Clone, Serialize, Deserialize)]
392pub struct PromptArgument {
393    pub name: String,
394    pub description: Option<String>,
395    pub required: Option<bool>,
396}
397
398/// List prompts result
399#[derive(Debug, Clone, Serialize, Deserialize)]
400pub struct ListPromptsResult {
401    pub prompts: Vec<Prompt>,
402    #[serde(skip_serializing_if = "Option::is_none")]
403    pub next_cursor: Option<String>,
404}
405
406/// Get prompt parameters
407#[derive(Debug, Clone, Serialize, Deserialize)]
408pub struct GetPromptRequestParam {
409    pub name: String,
410    pub arguments: Option<HashMap<String, String>>,
411}
412
413/// Prompt message role
414#[derive(Debug, Clone, Serialize, Deserialize)]
415#[serde(rename_all = "lowercase")]
416pub enum PromptMessageRole {
417    User,
418    Assistant,
419    System,
420}
421
422/// Prompt message content
423#[derive(Debug, Clone, Serialize, Deserialize)]
424#[serde(tag = "type")]
425pub enum PromptMessageContent {
426    #[serde(rename = "text")]
427    Text { text: String },
428    #[serde(rename = "image")]
429    Image { data: String, mime_type: String },
430}
431
432/// Prompt message
433#[derive(Debug, Clone, Serialize, Deserialize)]
434pub struct PromptMessage {
435    pub role: PromptMessageRole,
436    pub content: PromptMessageContent,
437}
438
439/// Get prompt result
440#[derive(Debug, Clone, Serialize, Deserialize)]
441pub struct GetPromptResult {
442    pub description: Option<String>,
443    pub messages: Vec<PromptMessage>,
444}
445
446/// Initialize request parameters
447#[derive(Debug, Clone, Serialize, Deserialize)]
448pub struct InitializeRequestParam {
449    #[serde(rename = "protocolVersion")]
450    pub protocol_version: String,
451    pub capabilities: serde_json::Value,
452    #[serde(rename = "clientInfo")]
453    pub client_info: Implementation,
454}
455
456/// Initialize result
457#[derive(Debug, Clone, Serialize, Deserialize)]
458pub struct InitializeResult {
459    #[serde(rename = "protocolVersion")]
460    pub protocol_version: String,
461    pub capabilities: ServerCapabilities,
462    #[serde(rename = "serverInfo")]
463    pub server_info: Implementation,
464    pub instructions: Option<String>,
465}
466
467/// Completion request parameters
468#[derive(Debug, Clone, Serialize, Deserialize)]
469pub struct CompleteRequestParam {
470    pub ref_: String,
471    pub argument: serde_json::Value,
472}
473
474/// Completion information
475#[derive(Debug, Clone, Serialize, Deserialize)]
476pub struct CompletionInfo {
477    pub completion: String,
478    pub has_more: Option<bool>,
479}
480
481/// Complete result
482#[derive(Debug, Clone, Serialize, Deserialize)]
483pub struct CompleteResult {
484    pub completion: Vec<CompletionInfo>,
485}
486
487/// Set logging level parameters
488#[derive(Debug, Clone, Serialize, Deserialize)]
489pub struct SetLevelRequestParam {
490    pub level: String,
491}
492
493/// Resource template definition
494#[derive(Debug, Clone, Serialize, Deserialize)]
495pub struct ResourceTemplate {
496    #[serde(rename = "uriTemplate")]
497    pub uri_template: String,
498    pub name: String,
499    pub description: Option<String>,
500    #[serde(rename = "mimeType")]
501    pub mime_type: Option<String>,
502}
503
504/// List resource templates result
505#[derive(Debug, Clone, Serialize, Deserialize)]
506pub struct ListResourceTemplatesResult {
507    #[serde(rename = "resourceTemplates")]
508    pub resource_templates: Vec<ResourceTemplate>,
509    #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
510    pub next_cursor: Option<String>,
511}
512
513/// Subscribe request parameters
514#[derive(Debug, Clone, Serialize, Deserialize)]
515pub struct SubscribeRequestParam {
516    pub uri: String,
517}
518
519/// Unsubscribe request parameters
520#[derive(Debug, Clone, Serialize, Deserialize)]
521pub struct UnsubscribeRequestParam {
522    pub uri: String,
523}