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