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;
6use std::sync::Arc;
7
8/// Metadata for MCP protocol messages (MCP 2025-06-18)
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct Meta {
11    /// Progress token for tracking long-running operations
12    #[serde(rename = "progressToken", skip_serializing_if = "Option::is_none")]
13    pub progress_token: Option<String>,
14}
15
16/// A flexible identifier type for JSON-RPC request IDs
17#[derive(Debug, Clone, Eq, PartialEq, Hash)]
18pub enum NumberOrString {
19    Number(i64),
20    String(Arc<str>),
21}
22
23impl NumberOrString {
24    pub fn into_json_value(self) -> serde_json::Value {
25        match self {
26            NumberOrString::Number(n) => serde_json::Value::Number(serde_json::Number::from(n)),
27            NumberOrString::String(s) => serde_json::Value::String(s.to_string()),
28        }
29    }
30
31    pub fn from_json_value(value: serde_json::Value) -> Option<Self> {
32        match value {
33            serde_json::Value::Number(n) => n.as_i64().map(NumberOrString::Number),
34            serde_json::Value::String(s) => Some(NumberOrString::String(Arc::from(s.as_str()))),
35            _ => None,
36        }
37    }
38}
39
40impl std::fmt::Display for NumberOrString {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        match self {
43            NumberOrString::Number(n) => write!(f, "{n}"),
44            NumberOrString::String(s) => write!(f, "{s}"),
45        }
46    }
47}
48
49impl Serialize for NumberOrString {
50    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
51    where
52        S: serde::Serializer,
53    {
54        match self {
55            NumberOrString::Number(n) => serializer.serialize_i64(*n),
56            NumberOrString::String(s) => serializer.serialize_str(s),
57        }
58    }
59}
60
61impl<'de> Deserialize<'de> for NumberOrString {
62    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
63    where
64        D: serde::Deserializer<'de>,
65    {
66        struct NumberOrStringVisitor;
67
68        impl<'de> serde::de::Visitor<'de> for NumberOrStringVisitor {
69            type Value = NumberOrString;
70
71            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
72                formatter.write_str("a number or string")
73            }
74
75            fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
76            where
77                E: serde::de::Error,
78            {
79                Ok(NumberOrString::Number(value))
80            }
81
82            fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
83            where
84                E: serde::de::Error,
85            {
86                Ok(NumberOrString::Number(value as i64))
87            }
88
89            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
90            where
91                E: serde::de::Error,
92            {
93                Ok(NumberOrString::String(Arc::from(value)))
94            }
95
96            fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
97            where
98                E: serde::de::Error,
99            {
100                Ok(NumberOrString::String(Arc::from(value.as_str())))
101            }
102        }
103
104        deserializer.deserialize_any(NumberOrStringVisitor)
105    }
106}
107
108/// JSON-RPC 2.0 Request
109#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct Request {
111    /// JSON-RPC version (always "2.0")
112    pub jsonrpc: String,
113    /// Request method name
114    pub method: String,
115    /// Request parameters
116    #[serde(default = "serde_json::Value::default")]
117    pub params: serde_json::Value,
118    /// Request ID (None for notifications)
119    #[serde(skip_serializing_if = "Option::is_none")]
120    pub id: Option<NumberOrString>,
121}
122
123/// JSON-RPC 2.0 Response
124#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct Response {
126    /// JSON-RPC version (always "2.0")
127    pub jsonrpc: String,
128    /// Response result (if successful)
129    #[serde(skip_serializing_if = "Option::is_none")]
130    pub result: Option<serde_json::Value>,
131    /// Response error (if failed)
132    #[serde(skip_serializing_if = "Option::is_none")]
133    pub error: Option<Error>,
134    /// Request ID (can be null for error responses)
135    #[serde(skip_serializing_if = "Option::is_none")]
136    pub id: Option<NumberOrString>,
137}
138
139/// MCP Protocol version in date format (YYYY-MM-DD)
140#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Serialize, Deserialize)]
141pub struct ProtocolVersion(std::borrow::Cow<'static, str>);
142
143impl Default for ProtocolVersion {
144    fn default() -> Self {
145        Self::LATEST
146    }
147}
148
149impl std::fmt::Display for ProtocolVersion {
150    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151        self.0.fmt(f)
152    }
153}
154
155impl ProtocolVersion {
156    pub const V_2025_06_18: Self = Self(std::borrow::Cow::Borrowed("2025-06-18"));
157    pub const V_2025_03_26: Self = Self(std::borrow::Cow::Borrowed("2025-03-26"));
158    pub const V_2024_11_05: Self = Self(std::borrow::Cow::Borrowed("2024-11-05"));
159    pub const LATEST: Self = Self::V_2025_06_18;
160
161    pub fn new(version: impl Into<std::borrow::Cow<'static, str>>) -> Self {
162        Self(version.into())
163    }
164}
165
166/// Server implementation information
167#[derive(Debug, Clone, Serialize, Deserialize)]
168pub struct Implementation {
169    pub name: String,
170    pub version: String,
171}
172
173/// Server capabilities configuration
174#[derive(Debug, Clone, Serialize, Deserialize, Default)]
175pub struct ServerCapabilities {
176    #[serde(skip_serializing_if = "Option::is_none")]
177    pub tools: Option<ToolsCapability>,
178    #[serde(skip_serializing_if = "Option::is_none")]
179    pub resources: Option<ResourcesCapability>,
180    #[serde(skip_serializing_if = "Option::is_none")]
181    pub prompts: Option<PromptsCapability>,
182    #[serde(skip_serializing_if = "Option::is_none")]
183    pub logging: Option<LoggingCapability>,
184    #[serde(skip_serializing_if = "Option::is_none")]
185    pub sampling: Option<SamplingCapability>,
186    #[serde(skip_serializing_if = "Option::is_none")]
187    pub elicitation: Option<ElicitationCapability>,
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize, Default)]
191pub struct ToolsCapability {
192    #[serde(skip_serializing_if = "Option::is_none")]
193    pub list_changed: Option<bool>,
194}
195
196#[derive(Debug, Clone, Serialize, Deserialize, Default)]
197pub struct ResourcesCapability {
198    #[serde(skip_serializing_if = "Option::is_none")]
199    pub subscribe: Option<bool>,
200    #[serde(skip_serializing_if = "Option::is_none")]
201    pub list_changed: Option<bool>,
202}
203
204#[derive(Debug, Clone, Serialize, Deserialize, Default)]
205pub struct PromptsCapability {
206    #[serde(skip_serializing_if = "Option::is_none")]
207    pub list_changed: Option<bool>,
208}
209
210#[derive(Debug, Clone, Serialize, Deserialize, Default)]
211pub struct LoggingCapability {
212    #[serde(skip_serializing_if = "Option::is_none")]
213    pub level: Option<String>,
214}
215
216#[derive(Debug, Clone, Serialize, Deserialize, Default)]
217pub struct SamplingCapability {}
218
219#[derive(Debug, Clone, Serialize, Deserialize, Default)]
220pub struct ElicitationCapability {}
221
222impl ServerCapabilities {
223    pub fn builder() -> ServerCapabilitiesBuilder {
224        ServerCapabilitiesBuilder::default()
225    }
226}
227
228#[derive(Default)]
229pub struct ServerCapabilitiesBuilder {
230    capabilities: ServerCapabilities,
231}
232
233impl ServerCapabilitiesBuilder {
234    #[must_use]
235    pub fn enable_tools(mut self) -> Self {
236        self.capabilities.tools = Some(ToolsCapability {
237            list_changed: Some(true),
238        });
239        self
240    }
241
242    #[must_use]
243    pub fn enable_resources(mut self) -> Self {
244        self.capabilities.resources = Some(ResourcesCapability {
245            subscribe: Some(true),
246            list_changed: Some(true),
247        });
248        self
249    }
250
251    #[must_use]
252    pub fn enable_prompts(mut self) -> Self {
253        self.capabilities.prompts = Some(PromptsCapability {
254            list_changed: Some(true),
255        });
256        self
257    }
258
259    #[must_use]
260    pub fn enable_logging(mut self) -> Self {
261        self.capabilities.logging = Some(LoggingCapability {
262            level: Some("info".to_string()),
263        });
264        self
265    }
266
267    #[must_use]
268    pub fn enable_sampling(mut self) -> Self {
269        self.capabilities.sampling = Some(SamplingCapability {});
270        self
271    }
272
273    #[must_use]
274    pub fn enable_elicitation(mut self) -> Self {
275        self.capabilities.elicitation = Some(ElicitationCapability {});
276        self
277    }
278
279    pub fn build(self) -> ServerCapabilities {
280        self.capabilities
281    }
282}
283
284/// Server information response
285#[derive(Debug, Clone, Serialize, Deserialize)]
286pub struct ServerInfo {
287    pub protocol_version: ProtocolVersion,
288    pub capabilities: ServerCapabilities,
289    pub server_info: Implementation,
290    pub instructions: Option<String>,
291}
292
293/// Tool definition
294#[derive(Debug, Clone, Serialize, Deserialize)]
295#[serde(rename_all = "camelCase")]
296pub struct Tool {
297    pub name: String,
298    #[serde(skip_serializing_if = "Option::is_none")]
299    pub title: Option<String>,
300    pub description: String,
301    pub input_schema: serde_json::Value,
302    #[serde(skip_serializing_if = "Option::is_none")]
303    pub output_schema: Option<serde_json::Value>,
304    #[serde(skip_serializing_if = "Option::is_none")]
305    pub annotations: Option<ToolAnnotations>,
306    #[serde(skip_serializing_if = "Option::is_none")]
307    pub icons: Option<Vec<Icon>>,
308}
309
310/// Tool annotations for behavioral hints
311#[derive(Debug, Clone, Serialize, Deserialize, Default)]
312pub struct ToolAnnotations {
313    #[serde(skip_serializing_if = "Option::is_none")]
314    pub read_only_hint: Option<bool>,
315    #[serde(skip_serializing_if = "Option::is_none")]
316    pub destructive_hint: Option<bool>,
317    #[serde(skip_serializing_if = "Option::is_none")]
318    pub idempotent_hint: Option<bool>,
319    #[serde(skip_serializing_if = "Option::is_none")]
320    pub open_world_hint: Option<bool>,
321}
322
323/// Icon definition for tools and other resources
324#[derive(Debug, Clone, Serialize, Deserialize)]
325pub struct Icon {
326    pub uri: String,
327    #[serde(skip_serializing_if = "Option::is_none")]
328    pub mime_type: Option<String>,
329}
330
331/// List tools result
332#[derive(Debug, Clone, Serialize, Deserialize)]
333#[serde(rename_all = "camelCase")]
334pub struct ListToolsResult {
335    pub tools: Vec<Tool>,
336    #[serde(skip_serializing_if = "Option::is_none")]
337    pub next_cursor: Option<String>,
338}
339
340/// Pagination parameters
341#[derive(Debug, Clone, Serialize, Deserialize)]
342pub struct PaginatedRequestParam {
343    pub cursor: Option<String>,
344}
345
346/// Tool call parameters
347#[derive(Debug, Clone, Serialize, Deserialize)]
348pub struct CallToolRequestParam {
349    pub name: String,
350    pub arguments: Option<serde_json::Value>,
351}
352
353/// Content types for tool responses
354#[derive(Debug, Clone, Serialize, Deserialize)]
355#[serde(tag = "type")]
356pub enum Content {
357    #[serde(rename = "text")]
358    Text {
359        text: String,
360        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
361        _meta: Option<Meta>,
362    },
363    #[serde(rename = "image")]
364    Image {
365        data: String,
366        mime_type: String,
367        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
368        _meta: Option<Meta>,
369    },
370    #[serde(rename = "resource")]
371    Resource {
372        resource: String,
373        text: Option<String>,
374        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
375        _meta: Option<Meta>,
376    },
377}
378
379impl Content {
380    pub fn text(text: impl Into<String>) -> Self {
381        Self::Text {
382            text: text.into(),
383            _meta: None,
384        }
385    }
386
387    pub fn image(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
388        Self::Image {
389            data: data.into(),
390            mime_type: mime_type.into(),
391            _meta: None,
392        }
393    }
394
395    pub fn resource(resource: impl Into<String>, text: Option<String>) -> Self {
396        Self::Resource {
397            resource: resource.into(),
398            text,
399            _meta: None,
400        }
401    }
402
403    /// Get text content if this is a text content type
404    pub fn as_text(&self) -> Option<&Self> {
405        match self {
406            Self::Text { .. } => Some(self),
407            _ => None,
408        }
409    }
410}
411
412/// Text content struct for compatibility
413pub struct TextContent {
414    pub text: String,
415}
416
417impl Content {
418    /// Get text content as `TextContent` struct for compatibility
419    pub fn as_text_content(&self) -> Option<TextContent> {
420        match self {
421            Self::Text { text, .. } => Some(TextContent { text: text.clone() }),
422            _ => None,
423        }
424    }
425}
426
427/// Tool call result
428#[derive(Debug, Clone, Serialize, Deserialize)]
429#[serde(rename_all = "camelCase")]
430pub struct CallToolResult {
431    pub content: Vec<Content>,
432    pub is_error: Option<bool>,
433    #[serde(skip_serializing_if = "Option::is_none")]
434    pub structured_content: Option<serde_json::Value>,
435    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
436    pub _meta: Option<Meta>,
437}
438
439impl CallToolResult {
440    pub fn success(content: Vec<Content>) -> Self {
441        Self {
442            content,
443            is_error: Some(false),
444            structured_content: None,
445            _meta: None,
446        }
447    }
448
449    pub fn error(content: Vec<Content>) -> Self {
450        Self {
451            content,
452            is_error: Some(true),
453            structured_content: None,
454            _meta: None,
455        }
456    }
457
458    pub fn text(text: impl Into<String>) -> Self {
459        Self::success(vec![Content::text(text)])
460    }
461
462    pub fn error_text(text: impl Into<String>) -> Self {
463        Self::error(vec![Content::text(text)])
464    }
465
466    /// Create a success result with structured content
467    pub fn structured(content: Vec<Content>, structured_content: serde_json::Value) -> Self {
468        Self {
469            content,
470            is_error: Some(false),
471            structured_content: Some(structured_content),
472            _meta: None,
473        }
474    }
475
476    /// Create an error result with structured content
477    pub fn structured_error(content: Vec<Content>, structured_content: serde_json::Value) -> Self {
478        Self {
479            content,
480            is_error: Some(true),
481            structured_content: Some(structured_content),
482            _meta: None,
483        }
484    }
485
486    /// Create a result with both text and structured content
487    pub fn text_with_structured(
488        text: impl Into<String>,
489        structured_content: serde_json::Value,
490    ) -> Self {
491        Self::structured(vec![Content::text(text)], structured_content)
492    }
493
494    /// Validate structured content against a schema
495    ///
496    /// # Errors
497    ///
498    /// Returns an error if the structured content doesn't match the provided schema
499    pub fn validate_structured_content(
500        &self,
501        output_schema: &serde_json::Value,
502    ) -> crate::Result<()> {
503        use crate::validation::Validator;
504
505        if let Some(structured_content) = &self.structured_content {
506            Validator::validate_structured_content(structured_content, output_schema)?;
507        }
508        Ok(())
509    }
510}
511
512/// Resource definition
513#[derive(Debug, Clone, Serialize, Deserialize)]
514pub struct Resource {
515    pub uri: String,
516    pub name: String,
517    #[serde(skip_serializing_if = "Option::is_none")]
518    pub title: Option<String>,
519    pub description: Option<String>,
520    pub mime_type: Option<String>,
521    pub annotations: Option<Annotations>,
522    #[serde(skip_serializing_if = "Option::is_none")]
523    pub icons: Option<Vec<Icon>>,
524    #[serde(skip_serializing_if = "Option::is_none")]
525    pub raw: Option<RawResource>,
526}
527
528/// Resource annotations
529#[derive(Debug, Clone, Serialize, Deserialize, Default)]
530pub struct Annotations {
531    pub audience: Option<Vec<String>>,
532    pub priority: Option<f32>,
533}
534
535/// List resources result
536#[derive(Debug, Clone, Serialize, Deserialize)]
537pub struct ListResourcesResult {
538    pub resources: Vec<Resource>,
539    #[serde(skip_serializing_if = "Option::is_none")]
540    pub next_cursor: Option<String>,
541}
542
543/// Read resource parameters
544#[derive(Debug, Clone, Serialize, Deserialize)]
545pub struct ReadResourceRequestParam {
546    pub uri: String,
547}
548
549/// Resource contents wrapper
550#[derive(Debug, Clone, Serialize, Deserialize)]
551pub struct ResourceContents {
552    pub uri: String,
553    pub mime_type: Option<String>,
554    pub text: Option<String>,
555    pub blob: Option<String>,
556    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
557    pub _meta: Option<Meta>,
558}
559
560/// Read resource result
561#[derive(Debug, Clone, Serialize, Deserialize)]
562pub struct ReadResourceResult {
563    pub contents: Vec<ResourceContents>,
564}
565
566/// Raw resource (for internal use)
567#[derive(Debug, Clone, Serialize, Deserialize)]
568pub struct RawResource {
569    pub uri: String,
570    pub data: Vec<u8>,
571    pub mime_type: Option<String>,
572    pub name: Option<String>,
573    pub description: Option<String>,
574    pub size: Option<usize>,
575}
576
577impl PromptMessage {
578    /// Create a new text message
579    pub fn new_text(role: PromptMessageRole, text: impl Into<String>) -> Self {
580        Self {
581            role,
582            content: PromptMessageContent::Text { text: text.into() },
583        }
584    }
585
586    /// Create a new image message
587    pub fn new_image(
588        role: PromptMessageRole,
589        data: impl Into<String>,
590        mime_type: impl Into<String>,
591    ) -> Self {
592        Self {
593            role,
594            content: PromptMessageContent::Image {
595                data: data.into(),
596                mime_type: mime_type.into(),
597            },
598        }
599    }
600}
601
602impl CompleteResult {
603    /// Create a simple completion result
604    pub fn simple(completion: impl Into<String>) -> Self {
605        Self {
606            completion: vec![CompletionInfo {
607                completion: completion.into(),
608                has_more: Some(false),
609            }],
610        }
611    }
612}
613
614/// Prompt definition
615#[derive(Debug, Clone, Serialize, Deserialize)]
616pub struct Prompt {
617    pub name: String,
618    #[serde(skip_serializing_if = "Option::is_none")]
619    pub title: Option<String>,
620    pub description: Option<String>,
621    pub arguments: Option<Vec<PromptArgument>>,
622    #[serde(skip_serializing_if = "Option::is_none")]
623    pub icons: Option<Vec<Icon>>,
624}
625
626/// Prompt argument definition
627#[derive(Debug, Clone, Serialize, Deserialize)]
628pub struct PromptArgument {
629    pub name: String,
630    pub description: Option<String>,
631    pub required: Option<bool>,
632}
633
634/// List prompts result
635#[derive(Debug, Clone, Serialize, Deserialize)]
636pub struct ListPromptsResult {
637    pub prompts: Vec<Prompt>,
638    #[serde(skip_serializing_if = "Option::is_none")]
639    pub next_cursor: Option<String>,
640}
641
642/// Get prompt parameters
643#[derive(Debug, Clone, Serialize, Deserialize)]
644pub struct GetPromptRequestParam {
645    pub name: String,
646    pub arguments: Option<HashMap<String, String>>,
647}
648
649/// Prompt message role
650#[derive(Debug, Clone, Serialize, Deserialize)]
651#[serde(rename_all = "lowercase")]
652pub enum PromptMessageRole {
653    User,
654    Assistant,
655    System,
656}
657
658/// Prompt message content
659#[derive(Debug, Clone, Serialize, Deserialize)]
660#[serde(tag = "type")]
661pub enum PromptMessageContent {
662    #[serde(rename = "text")]
663    Text { text: String },
664    #[serde(rename = "image")]
665    Image { data: String, mime_type: String },
666}
667
668/// Prompt message
669#[derive(Debug, Clone, Serialize, Deserialize)]
670pub struct PromptMessage {
671    pub role: PromptMessageRole,
672    pub content: PromptMessageContent,
673}
674
675/// Get prompt result
676#[derive(Debug, Clone, Serialize, Deserialize)]
677pub struct GetPromptResult {
678    pub description: Option<String>,
679    pub messages: Vec<PromptMessage>,
680}
681
682/// Initialize request parameters
683#[derive(Debug, Clone, Serialize, Deserialize)]
684pub struct InitializeRequestParam {
685    #[serde(rename = "protocolVersion")]
686    pub protocol_version: String,
687    pub capabilities: serde_json::Value,
688    #[serde(rename = "clientInfo")]
689    pub client_info: Implementation,
690}
691
692/// Initialize result
693#[derive(Debug, Clone, Serialize, Deserialize)]
694pub struct InitializeResult {
695    #[serde(rename = "protocolVersion")]
696    pub protocol_version: String,
697    pub capabilities: ServerCapabilities,
698    #[serde(rename = "serverInfo")]
699    pub server_info: Implementation,
700    #[serde(skip_serializing_if = "Option::is_none")]
701    pub instructions: Option<String>,
702}
703
704/// Completion context for context-aware completion (MCP 2025-06-18)
705#[derive(Debug, Clone, Serialize, Deserialize)]
706#[serde(rename_all = "camelCase")]
707pub struct CompletionContext {
708    /// Names of arguments that have already been provided
709    pub argument_names: Vec<String>,
710    /// Values of arguments that have already been provided
711    pub values: HashMap<String, serde_json::Value>,
712}
713
714impl CompletionContext {
715    /// Create a new completion context
716    pub fn new(argument_names: Vec<String>, values: HashMap<String, serde_json::Value>) -> Self {
717        Self {
718            argument_names,
719            values,
720        }
721    }
722
723    /// Get an iterator over argument names
724    pub fn argument_names_iter(&self) -> impl Iterator<Item = &String> {
725        self.argument_names.iter()
726    }
727}
728
729/// Completion request parameters
730#[derive(Debug, Clone, Serialize, Deserialize)]
731pub struct CompleteRequestParam {
732    pub ref_: String,
733    pub argument: serde_json::Value,
734    /// Optional context for context-aware completion (MCP 2025-06-18)
735    #[serde(skip_serializing_if = "Option::is_none")]
736    pub context: Option<CompletionContext>,
737}
738
739/// Completion information
740#[derive(Debug, Clone, Serialize, Deserialize)]
741pub struct CompletionInfo {
742    pub completion: String,
743    pub has_more: Option<bool>,
744}
745
746/// Complete result
747#[derive(Debug, Clone, Serialize, Deserialize)]
748pub struct CompleteResult {
749    pub completion: Vec<CompletionInfo>,
750}
751
752/// Set logging level parameters
753#[derive(Debug, Clone, Serialize, Deserialize)]
754pub struct SetLevelRequestParam {
755    pub level: String,
756}
757
758/// Resource template definition
759#[derive(Debug, Clone, Serialize, Deserialize)]
760pub struct ResourceTemplate {
761    #[serde(rename = "uriTemplate")]
762    pub uri_template: String,
763    pub name: String,
764    pub description: Option<String>,
765    #[serde(rename = "mimeType")]
766    pub mime_type: Option<String>,
767}
768
769/// List resource templates result
770#[derive(Debug, Clone, Serialize, Deserialize)]
771pub struct ListResourceTemplatesResult {
772    #[serde(rename = "resourceTemplates")]
773    pub resource_templates: Vec<ResourceTemplate>,
774    #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
775    pub next_cursor: Option<String>,
776}
777
778/// Subscribe request parameters
779#[derive(Debug, Clone, Serialize, Deserialize)]
780pub struct SubscribeRequestParam {
781    pub uri: String,
782}
783
784/// Unsubscribe request parameters
785#[derive(Debug, Clone, Serialize, Deserialize)]
786pub struct UnsubscribeRequestParam {
787    pub uri: String,
788}
789
790/// Elicitation request parameters
791#[derive(Debug, Clone, Serialize, Deserialize)]
792pub struct ElicitationRequestParam {
793    pub message: String,
794    #[serde(rename = "requestedSchema")]
795    pub requested_schema: serde_json::Value,
796}
797
798/// Elicitation response actions
799#[derive(Debug, Clone, Serialize, Deserialize)]
800#[serde(rename_all = "lowercase")]
801pub enum ElicitationAction {
802    Accept,
803    Decline,
804    Cancel,
805}
806
807/// Elicitation response
808#[derive(Debug, Clone, Serialize, Deserialize)]
809pub struct ElicitationResponse {
810    pub action: ElicitationAction,
811    #[serde(skip_serializing_if = "Option::is_none")]
812    pub data: Option<serde_json::Value>,
813}
814
815/// Elicitation result
816#[derive(Debug, Clone, Serialize, Deserialize)]
817pub struct ElicitationResult {
818    pub response: ElicitationResponse,
819}
820
821impl ElicitationResult {
822    /// Create an accept result with data
823    pub fn accept(data: serde_json::Value) -> Self {
824        Self {
825            response: ElicitationResponse {
826                action: ElicitationAction::Accept,
827                data: Some(data),
828            },
829        }
830    }
831
832    /// Create a decline result
833    pub fn decline() -> Self {
834        Self {
835            response: ElicitationResponse {
836                action: ElicitationAction::Decline,
837                data: None,
838            },
839        }
840    }
841
842    /// Create a cancel result
843    pub fn cancel() -> Self {
844        Self {
845            response: ElicitationResponse {
846                action: ElicitationAction::Cancel,
847                data: None,
848            },
849        }
850    }
851}