prism_mcp_rs/protocol/
types.rs

1//! Complete MCP Protocol Types for 2025-06-18 Specification
2//!
3//! This module contains all the core types defined by the Model Context Protocol
4//! specification version 2025-06-18, with simplified JSON-RPC (no batching) and
5//! improved metadata handling
6
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9
10// ============================================================================
11// Core Protocol Constants
12// ============================================================================
13
14/// MCP Protocol version (2025-06-18)
15pub const LATEST_PROTOCOL_VERSION: &str = "2025-06-18";
16pub const JSONRPC_VERSION: &str = "2.0";
17
18// Legacy constant for compatibility
19pub const PROTOCOL_VERSION: &str = LATEST_PROTOCOL_VERSION;
20
21// ============================================================================
22// Type Aliases
23// ============================================================================
24
25/// Progress token for associating notifications with requests
26pub type ProgressToken = serde_json::Value; // string | number
27
28/// Cursor for pagination
29pub type Cursor = String;
30
31/// Request ID for JSON-RPC correlation
32pub type RequestId = serde_json::Value; // string | number | null
33
34/// JSON-RPC ID type for better type safety
35#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
36#[serde(untagged)]
37pub enum JsonRpcId {
38    String(String),
39    Number(i64),
40    Null,
41}
42
43impl From<i64> for JsonRpcId {
44    fn from(value: i64) -> Self {
45        JsonRpcId::Number(value)
46    }
47}
48
49impl From<String> for JsonRpcId {
50    fn from(value: String) -> Self {
51        JsonRpcId::String(value)
52    }
53}
54
55impl From<&str> for JsonRpcId {
56    fn from(value: &str) -> Self {
57        JsonRpcId::String(value.to_string())
58    }
59}
60
61// ============================================================================
62// BaseMetadata Interface (2025-06-18)
63// ============================================================================
64
65/// Base interface for metadata with name (identifier) and title (display name) properties.
66#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
67pub struct BaseMetadata {
68    /// Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).
69    pub name: String,
70    /// Intended for UI and end-user contexts — improved to be human-readable and easily understood,
71    /// even by those unfamiliar with domain-specific terminology.
72    ///
73    /// If not provided, the name should be used for display (except for Tool,
74    /// where `annotations.title` should be given precedence over using `name`, if present).
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub title: Option<String>,
77}
78
79// ============================================================================
80// Core Implementation Info
81// ============================================================================
82
83/// Information about an MCP implementation (2025-06-18 with title support)
84#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
85pub struct Implementation {
86    /// Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).
87    pub name: String,
88    /// Version of the implementation
89    pub version: String,
90    /// Intended for UI and end-user contexts — improved to be human-readable and easily understood,
91    /// even by those unfamiliar with domain-specific terminology.
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub title: Option<String>,
94}
95
96impl Implementation {
97    /// Create a new implementation with name and version
98    pub fn new<S: Into<String>>(name: S, version: S) -> Self {
99        Self {
100            name: name.into(),
101            version: version.into(),
102            title: None,
103        }
104    }
105
106    /// Create implementation with title
107    pub fn with_title<S: Into<String>>(name: S, version: S, title: S) -> Self {
108        Self {
109            name: name.into(),
110            version: version.into(),
111            title: Some(title.into()),
112        }
113    }
114}
115
116// Type aliases for compatibility
117pub type ServerInfo = Implementation;
118pub type ClientInfo = Implementation;
119
120// ============================================================================
121// Capabilities (2025-06-18)
122// ============================================================================
123
124/// Server capabilities for 2025-06-18
125#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
126pub struct ServerCapabilities {
127    /// Prompt-related capabilities
128    #[serde(skip_serializing_if = "Option::is_none")]
129    pub prompts: Option<PromptsCapability>,
130    /// Resource-related capabilities
131    #[serde(skip_serializing_if = "Option::is_none")]
132    pub resources: Option<ResourcesCapability>,
133    /// Tool-related capabilities
134    #[serde(skip_serializing_if = "Option::is_none")]
135    pub tools: Option<ToolsCapability>,
136    /// Sampling-related capabilities (client to server)
137    #[serde(skip_serializing_if = "Option::is_none")]
138    pub sampling: Option<SamplingCapability>,
139    /// Logging capabilities (2025-06-18)
140    #[serde(skip_serializing_if = "Option::is_none")]
141    pub logging: Option<LoggingCapability>,
142    /// Autocompletion capabilities (2025-06-18)
143    #[serde(skip_serializing_if = "Option::is_none")]
144    pub completions: Option<CompletionsCapability>,
145    /// Experimental capabilities (2025-06-18)
146    #[serde(skip_serializing_if = "Option::is_none")]
147    pub experimental: Option<HashMap<String, serde_json::Value>>,
148}
149
150/// Client capabilities for 2025-06-18
151#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
152pub struct ClientCapabilities {
153    /// Sampling-related capabilities
154    #[serde(skip_serializing_if = "Option::is_none")]
155    pub sampling: Option<SamplingCapability>,
156    /// Roots listing capabilities (2025-06-18)
157    #[serde(skip_serializing_if = "Option::is_none")]
158    pub roots: Option<RootsCapability>,
159    /// Elicitation support (2025-06-18 NEW)
160    #[serde(skip_serializing_if = "Option::is_none")]
161    pub elicitation: Option<ElicitationCapability>,
162    /// Experimental capabilities (2025-06-18)
163    #[serde(skip_serializing_if = "Option::is_none")]
164    pub experimental: Option<HashMap<String, serde_json::Value>>,
165}
166
167/// Prompt-related server capabilities
168#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
169pub struct PromptsCapability {
170    /// Whether the server supports prompt list change notifications
171    #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
172    pub list_changed: Option<bool>,
173}
174
175/// Resource-related server capabilities
176#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
177pub struct ResourcesCapability {
178    /// Whether the server supports resource subscriptions
179    #[serde(skip_serializing_if = "Option::is_none")]
180    pub subscribe: Option<bool>,
181    /// Whether the server supports resource list change notifications
182    #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
183    pub list_changed: Option<bool>,
184}
185
186/// Tool-related server capabilities
187#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
188pub struct ToolsCapability {
189    /// Whether the server supports tool list change notifications
190    #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
191    pub list_changed: Option<bool>,
192}
193
194/// Sampling-related capabilities
195#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
196pub struct SamplingCapability {
197    /// Additional properties
198    #[serde(flatten)]
199    pub additional_properties: HashMap<String, serde_json::Value>,
200}
201
202/// Logging capabilities (2025-03-26)
203#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
204pub struct LoggingCapability {
205    /// Additional properties
206    #[serde(flatten)]
207    pub additional_properties: HashMap<String, serde_json::Value>,
208}
209
210/// Autocompletion capabilities (2025-03-26)
211#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
212pub struct CompletionsCapability {
213    /// Additional properties
214    #[serde(flatten)]
215    pub additional_properties: HashMap<String, serde_json::Value>,
216}
217
218/// Roots capability for clients (2025-06-18)
219#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
220pub struct RootsCapability {
221    /// Whether the client supports notifications for changes to the roots list
222    #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
223    pub list_changed: Option<bool>,
224}
225
226/// Elicitation capabilities (2025-06-18 NEW)
227#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
228pub struct ElicitationCapability {
229    /// Additional properties for elicitation capability
230    #[serde(flatten)]
231    pub additional_properties: HashMap<String, serde_json::Value>,
232}
233
234// ============================================================================
235// Annotations (2025-06-18 improved)
236// ============================================================================
237
238/// Optional annotations for the client. The client can use annotations to inform how objects are used or displayed.
239#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
240pub struct Annotations {
241    /// Describes who the intended customer of this object or data is.
242    ///
243    /// It can include multiple entries to indicate content useful for multiple audiences (e.g., `["user", "assistant"]`).
244    #[serde(skip_serializing_if = "Option::is_none")]
245    pub audience: Option<Vec<Role>>,
246    /// Describes how important this data is for operating the server.
247    ///
248    /// A value of 1 means "most important," and indicates that the data is
249    /// effectively required, while 0 means "least important," and indicates that
250    /// the data is fully optional.
251    #[serde(skip_serializing_if = "Option::is_none")]
252    pub priority: Option<f64>,
253    /// The moment the resource was last modified, as an ISO 8601 formatted string.
254    ///
255    /// Should be an ISO 8601 formatted string (e.g., "2025-01-12T15:00:58Z").
256    ///
257    /// Examples: last activity timestamp in an open file, timestamp when the resource
258    /// was attached, etc.
259    #[serde(rename = "lastModified", skip_serializing_if = "Option::is_none")]
260    pub last_modified: Option<String>,
261    /// Legacy danger level field for test compatibility
262    #[serde(skip_serializing_if = "Option::is_none")]
263    pub danger: Option<DangerLevel>,
264    /// Legacy destructive field for test compatibility
265    #[serde(skip_serializing_if = "Option::is_none")]
266    pub destructive: Option<bool>,
267    /// Legacy read_only field for test compatibility
268    #[serde(skip_serializing_if = "Option::is_none")]
269    pub read_only: Option<bool>,
270}
271
272// ============================================================================
273// Content Types (2025-06-18 with ResourceLink)
274// ============================================================================
275
276/// Text content
277#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
278pub struct TextContent {
279    /// Content type identifier
280    #[serde(rename = "type")]
281    pub content_type: String, // "text"
282    /// The text content
283    pub text: String,
284    /// Content annotations (2025-06-18)
285    #[serde(skip_serializing_if = "Option::is_none")]
286    pub annotations: Option<Annotations>,
287    /// Metadata field for future extensions
288    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
289    pub meta: Option<HashMap<String, serde_json::Value>>,
290}
291
292/// Image content
293#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
294pub struct ImageContent {
295    /// Content type identifier
296    #[serde(rename = "type")]
297    pub content_type: String, // "image"
298    /// Base64-encoded image data
299    pub data: String,
300    /// MIME type of the image
301    #[serde(rename = "mimeType")]
302    pub mime_type: String,
303    /// Content annotations (2025-06-18)
304    #[serde(skip_serializing_if = "Option::is_none")]
305    pub annotations: Option<Annotations>,
306    /// Metadata field for future extensions
307    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
308    pub meta: Option<HashMap<String, serde_json::Value>>,
309}
310
311/// Audio content (2025-06-18)
312#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
313pub struct AudioContent {
314    /// Content type identifier
315    #[serde(rename = "type")]
316    pub content_type: String, // "audio"
317    /// Base64-encoded audio data
318    pub data: String,
319    /// MIME type of the audio
320    #[serde(rename = "mimeType")]
321    pub mime_type: String,
322    /// Content annotations (2025-06-18)
323    #[serde(skip_serializing_if = "Option::is_none")]
324    pub annotations: Option<Annotations>,
325    /// Metadata field for future extensions
326    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
327    pub meta: Option<HashMap<String, serde_json::Value>>,
328}
329
330/// ResourceLink content (2025-06-18 NEW)
331#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
332pub struct ResourceLink {
333    /// Content type identifier
334    #[serde(rename = "type")]
335    pub content_type: String, // "resource_link"
336    /// URI of the resource
337    pub uri: String,
338    /// Human-readable name of the resource
339    pub name: String,
340    /// Description of the resource
341    #[serde(skip_serializing_if = "Option::is_none")]
342    pub description: Option<String>,
343    /// MIME type of the resource
344    #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
345    pub mime_type: Option<String>,
346    /// Size of the resource in bytes
347    #[serde(skip_serializing_if = "Option::is_none")]
348    pub size: Option<u64>,
349    /// Title for UI display
350    #[serde(skip_serializing_if = "Option::is_none")]
351    pub title: Option<String>,
352    /// Content annotations (2025-06-18)
353    #[serde(skip_serializing_if = "Option::is_none")]
354    pub annotations: Option<Annotations>,
355    /// Metadata field for future extensions
356    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
357    pub meta: Option<HashMap<String, serde_json::Value>>,
358}
359
360/// Embedded resource content (2025-06-18)
361#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
362pub struct EmbeddedResource {
363    /// Content type identifier
364    #[serde(rename = "type")]
365    pub content_type: String, // "resource"
366    /// Resource contents
367    pub resource: ResourceContents,
368    /// Content annotations (2025-06-18)
369    #[serde(skip_serializing_if = "Option::is_none")]
370    pub annotations: Option<Annotations>,
371    /// Metadata field for future extensions
372    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
373    pub meta: Option<HashMap<String, serde_json::Value>>,
374}
375
376/// ContentBlock union type (2025-06-18 including ResourceLink)
377#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
378#[serde(tag = "type")]
379pub enum ContentBlock {
380    /// Text content
381    #[serde(rename = "text")]
382    Text {
383        /// The text content
384        text: String,
385        /// Content annotations (2025-06-18)
386        #[serde(skip_serializing_if = "Option::is_none")]
387        annotations: Option<Annotations>,
388        /// Metadata field for future extensions
389        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
390        meta: Option<HashMap<String, serde_json::Value>>,
391    },
392    /// Image content
393    #[serde(rename = "image")]
394    Image {
395        /// Base64-encoded image data
396        data: String,
397        /// MIME type of the image
398        #[serde(rename = "mimeType")]
399        mime_type: String,
400        /// Content annotations (2025-06-18)
401        #[serde(skip_serializing_if = "Option::is_none")]
402        annotations: Option<Annotations>,
403        /// Metadata field for future extensions
404        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
405        meta: Option<HashMap<String, serde_json::Value>>,
406    },
407    /// Audio content (2025-06-18)
408    #[serde(rename = "audio")]
409    Audio {
410        /// Base64-encoded audio data
411        data: String,
412        /// MIME type of the audio
413        #[serde(rename = "mimeType")]
414        mime_type: String,
415        /// Content annotations (2025-06-18)
416        #[serde(skip_serializing_if = "Option::is_none")]
417        annotations: Option<Annotations>,
418        /// Metadata field for future extensions
419        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
420        meta: Option<HashMap<String, serde_json::Value>>,
421    },
422    /// ResourceLink content (2025-06-18 NEW)
423    #[serde(rename = "resource_link")]
424    ResourceLink {
425        /// URI of the resource
426        uri: String,
427        /// Human-readable name of the resource
428        name: String,
429        /// Description of the resource
430        #[serde(skip_serializing_if = "Option::is_none")]
431        description: Option<String>,
432        /// MIME type of the resource
433        #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
434        mime_type: Option<String>,
435        /// Size of the resource in bytes
436        #[serde(skip_serializing_if = "Option::is_none")]
437        size: Option<u64>,
438        /// Title for UI display
439        #[serde(skip_serializing_if = "Option::is_none")]
440        title: Option<String>,
441        /// Content annotations (2025-06-18)
442        #[serde(skip_serializing_if = "Option::is_none")]
443        annotations: Option<Annotations>,
444        /// Metadata field for future extensions
445        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
446        meta: Option<HashMap<String, serde_json::Value>>,
447    },
448    /// Embedded resource content (2025-06-18)
449    #[serde(rename = "resource")]
450    Resource {
451        /// Resource contents
452        resource: ResourceContents,
453        /// Content annotations (2025-06-18)
454        #[serde(skip_serializing_if = "Option::is_none")]
455        annotations: Option<Annotations>,
456        /// Metadata field for future extensions
457        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
458        meta: Option<HashMap<String, serde_json::Value>>,
459    },
460}
461
462// Legacy alias for backwards compatibility
463pub type Content = ContentBlock;
464
465// ============================================================================
466// ContentBlock Convenience Methods
467// ============================================================================
468
469impl ContentBlock {
470    /// Create a text content block
471    pub fn text<S: Into<String>>(text: S) -> Self {
472        ContentBlock::Text {
473            text: text.into(),
474            annotations: None,
475            meta: None,
476        }
477    }
478
479    /// Create a text content block with annotations
480    pub fn text_with_annotations<S: Into<String>>(text: S, annotations: Annotations) -> Self {
481        ContentBlock::Text {
482            text: text.into(),
483            annotations: Some(annotations),
484            meta: None,
485        }
486    }
487
488    /// Create an image content block
489    pub fn image<S: Into<String>>(data: S, mime_type: S) -> Self {
490        ContentBlock::Image {
491            data: data.into(),
492            mime_type: mime_type.into(),
493            annotations: None,
494            meta: None,
495        }
496    }
497
498    /// Create an audio content block
499    pub fn audio<S: Into<String>>(data: S, mime_type: S) -> Self {
500        ContentBlock::Audio {
501            data: data.into(),
502            mime_type: mime_type.into(),
503            annotations: None,
504            meta: None,
505        }
506    }
507
508    /// Create a resource link content block
509    pub fn resource_link<S: Into<String>>(uri: S, name: S) -> Self {
510        ContentBlock::ResourceLink {
511            uri: uri.into(),
512            name: name.into(),
513            description: None,
514            mime_type: None,
515            size: None,
516            title: None,
517            annotations: None,
518            meta: None,
519        }
520    }
521
522    /// Create an embedded resource content block
523    pub fn embedded_resource(resource: ResourceContents) -> Self {
524        ContentBlock::Resource {
525            resource,
526            annotations: None,
527            meta: None,
528        }
529    }
530
531    /// Create a resource content block (alias for resource_link for compatibility)
532    pub fn resource<S: Into<String>>(uri: S) -> Self {
533        // For simple resource references, use resource_link with empty name
534        // This is provided for backwards compatibility
535        let uri_str = uri.into();
536        ContentBlock::ResourceLink {
537            uri: uri_str.clone(),
538            name: uri_str,
539            description: None,
540            mime_type: None,
541            size: None,
542            title: None,
543            annotations: None,
544            meta: None,
545        }
546    }
547}
548
549// ============================================================================
550// Tool Types (2025-06-18 with Title and Structured Content)
551// ============================================================================
552
553/// Tool-specific annotations (2025-06-18 Schema Compliance)
554///
555/// NOTE: all properties in ToolAnnotations are **hints**.
556/// They are not guaranteed to provide a faithful description of
557/// tool behavior (including descriptive properties like `title`).
558///
559/// Clients should never make tool use decisions based on ToolAnnotations
560/// received from untrusted servers.
561#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
562pub struct ToolAnnotations {
563    /// A human-readable title for the tool
564    #[serde(skip_serializing_if = "Option::is_none")]
565    pub title: Option<String>,
566
567    /// If true, the tool does not modify its environment
568    /// Default: false
569    #[serde(rename = "readOnlyHint", skip_serializing_if = "Option::is_none")]
570    pub read_only_hint: Option<bool>,
571
572    /// If true, the tool may perform destructive updates to its environment
573    /// If false, the tool performs only additive updates
574    /// (This property is meaningful only when `readOnlyHint == false`)
575    /// Default: true
576    #[serde(rename = "destructiveHint", skip_serializing_if = "Option::is_none")]
577    pub destructive_hint: Option<bool>,
578
579    /// If true, calling the tool repeatedly with the same arguments
580    /// will have no additional effect on its environment
581    /// (This property is meaningful only when `readOnlyHint == false`)
582    /// Default: false
583    #[serde(rename = "idempotentHint", skip_serializing_if = "Option::is_none")]
584    pub idempotent_hint: Option<bool>,
585
586    /// If true, this tool may interact with an "open world" of external entities
587    /// If false, the tool's domain of interaction is closed
588    /// For example, the world of a web search tool is open, whereas that
589    /// of a memory tool is not
590    /// Default: true
591    #[serde(rename = "openWorldHint", skip_serializing_if = "Option::is_none")]
592    pub open_world_hint: Option<bool>,
593}
594
595impl ToolAnnotations {
596    /// Create new empty tool annotations
597    pub fn new() -> Self {
598        Self::default()
599    }
600
601    /// Set the human-readable title for the tool
602    pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
603        self.title = Some(title.into());
604        self
605    }
606
607    /// Mark tool as read-only (does not modify environment)
608    pub fn read_only(mut self) -> Self {
609        self.read_only_hint = Some(true);
610        self
611    }
612
613    /// Mark tool as destructive (may perform destructive updates)
614    pub fn destructive(mut self) -> Self {
615        self.destructive_hint = Some(true);
616        self
617    }
618
619    /// Mark tool as idempotent (same input produces same result)
620    pub fn idempotent(mut self) -> Self {
621        self.idempotent_hint = Some(true);
622        self
623    }
624
625    /// Mark tool as interacting with open world of external entities
626    pub fn open_world(mut self) -> Self {
627        self.open_world_hint = Some(true);
628        self
629    }
630
631    /// Mark tool as interacting with closed world (limited domain)
632    pub fn closed_world(mut self) -> Self {
633        self.open_world_hint = Some(false);
634        self
635    }
636}
637
638// ============================================================================
639// Tool Annotations Integration with improved Metadata
640// ============================================================================
641
642impl From<&crate::core::tool_metadata::ToolBehaviorHints> for ToolAnnotations {
643    fn from(hints: &crate::core::tool_metadata::ToolBehaviorHints) -> Self {
644        Self {
645            title: None, // Title should be set separately at tool level
646            read_only_hint: hints.read_only,
647            destructive_hint: hints.destructive,
648            idempotent_hint: hints.idempotent,
649            // Map open_world_hint: if requires_auth or resource_intensive, likely open world
650            open_world_hint: if hints.requires_auth.unwrap_or(false)
651                || hints.resource_intensive.unwrap_or(false)
652            {
653                Some(true)
654            } else {
655                None
656            },
657        }
658    }
659}
660
661impl From<&crate::core::tool_metadata::ImprovedToolMetadata> for ToolAnnotations {
662    fn from(metadata: &crate::core::tool_metadata::ImprovedToolMetadata) -> Self {
663        ToolAnnotations::from(&metadata.behavior_hints)
664    }
665}
666
667impl ToolAnnotations {
668    /// Create ToolAnnotations from improved metadata with explicit title override
669    pub fn from_improved_metadata(
670        metadata: &crate::core::tool_metadata::ImprovedToolMetadata,
671        title_override: Option<String>,
672    ) -> Self {
673        let mut annotations = Self::from(metadata);
674        if let Some(title) = title_override {
675            annotations.title = Some(title);
676        }
677        annotations
678    }
679
680    /// Create minimal ToolAnnotations from behavior hints
681    pub fn from_behavior_hints(hints: &crate::core::tool_metadata::ToolBehaviorHints) -> Self {
682        Self::from(hints)
683    }
684}
685
686/// Tool definition with annotations and title (2025-06-18)
687#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
688pub struct Tool {
689    /// Intended for programmatic or logical use
690    pub name: String,
691    /// Description of what the tool does
692    #[serde(skip_serializing_if = "Option::is_none")]
693    pub description: Option<String>,
694    /// JSON Schema describing the tool's input parameters
695    #[serde(rename = "inputSchema")]
696    pub input_schema: ToolInputSchema,
697    /// Optional JSON Schema object defining the structure of the tool's output returned in
698    /// the structuredContent field of a CallToolResult (2025-06-18 NEW)
699    #[serde(rename = "outputSchema", skip_serializing_if = "Option::is_none")]
700    pub output_schema: Option<ToolOutputSchema>,
701    /// Tool behavior annotations (2025-06-18)
702    #[serde(skip_serializing_if = "Option::is_none")]
703    pub annotations: Option<ToolAnnotations>,
704    /// Intended for UI and end-user contexts
705    #[serde(skip_serializing_if = "Option::is_none")]
706    pub title: Option<String>,
707    /// Metadata field for future extensions
708    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
709    pub meta: Option<HashMap<String, serde_json::Value>>,
710}
711
712/// Tool input schema
713#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
714pub struct ToolInputSchema {
715    /// Schema type (always "object")
716    #[serde(rename = "type")]
717    pub schema_type: String,
718    /// Schema properties
719    #[serde(skip_serializing_if = "Option::is_none")]
720    pub properties: Option<HashMap<String, serde_json::Value>>,
721    /// Required properties
722    #[serde(skip_serializing_if = "Option::is_none")]
723    pub required: Option<Vec<String>>,
724    /// Additional schema properties
725    #[serde(flatten)]
726    pub additional_properties: HashMap<String, serde_json::Value>,
727}
728
729/// Tool output schema (2025-06-18 NEW)
730#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
731pub struct ToolOutputSchema {
732    /// Schema type (always "object")
733    #[serde(rename = "type")]
734    pub schema_type: String,
735    /// Schema properties
736    #[serde(skip_serializing_if = "Option::is_none")]
737    pub properties: Option<HashMap<String, serde_json::Value>>,
738    /// Required properties
739    #[serde(skip_serializing_if = "Option::is_none")]
740    pub required: Option<Vec<String>>,
741}
742
743impl ToolOutputSchema {
744    /// Create a new tool output schema
745    pub fn new() -> Self {
746        Self {
747            schema_type: "object".to_string(),
748            properties: None,
749            required: None,
750        }
751    }
752
753    /// Create a tool output schema with properties
754    pub fn with_properties(properties: HashMap<String, serde_json::Value>) -> Self {
755        Self {
756            schema_type: "object".to_string(),
757            properties: Some(properties),
758            required: None,
759        }
760    }
761
762    /// Add required fields to the schema
763    pub fn with_required(mut self, required: Vec<String>) -> Self {
764        self.required = Some(required);
765        self
766    }
767
768    /// Add properties to the schema
769    pub fn with_properties_map(mut self, properties: HashMap<String, serde_json::Value>) -> Self {
770        self.properties = Some(properties);
771        self
772    }
773}
774
775impl Default for ToolOutputSchema {
776    fn default() -> Self {
777        Self::new()
778    }
779}
780
781/// Result of a tool execution (2025-06-18 with structured content)
782#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
783pub struct CallToolResult {
784    /// Content returned by the tool
785    pub content: Vec<ContentBlock>,
786    /// Whether this result represents an error
787    #[serde(rename = "isError", skip_serializing_if = "Option::is_none")]
788    pub is_error: Option<bool>,
789    /// An optional JSON object that represents the structured result of the tool call
790    #[serde(rename = "structuredContent", skip_serializing_if = "Option::is_none")]
791    pub structured_content: Option<serde_json::Value>,
792    /// Result metadata (2025-06-18)
793    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
794    pub meta: Option<HashMap<String, serde_json::Value>>,
795}
796
797// ============================================================================
798// CallToolResult/ToolResult Convenience Methods
799// ============================================================================
800
801impl CallToolResult {
802    /// Create a successful text result
803    pub fn text<S: Into<String>>(text: S) -> Self {
804        Self {
805            content: vec![ContentBlock::text(text)],
806            is_error: Some(false),
807            structured_content: None,
808            meta: None,
809        }
810    }
811
812    /// Create an error result
813    pub fn error<S: Into<String>>(message: S) -> Self {
814        Self {
815            content: vec![ContentBlock::text(message)],
816            is_error: Some(true),
817            structured_content: None,
818            meta: None,
819        }
820    }
821
822    /// Create a result with multiple content blocks
823    pub fn with_content(content: Vec<ContentBlock>) -> Self {
824        Self {
825            content,
826            is_error: Some(false),
827            structured_content: None,
828            meta: None,
829        }
830    }
831
832    /// Create a result with structured content
833    pub fn with_structured(content: Vec<ContentBlock>, structured: serde_json::Value) -> Self {
834        Self {
835            content,
836            is_error: Some(false),
837            structured_content: Some(structured),
838            meta: None,
839        }
840    }
841}
842
843// Re-export types with legacy names for compatibility
844pub type ToolInfo = Tool;
845pub type ToolResult = CallToolResult;
846
847// Additional compatibility aliases for documentation examples
848// Note: Content type alias is defined earlier in the file
849
850// ============================================================================
851// Resource Types (2025-06-18)
852// ============================================================================
853
854/// Resource definition
855#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
856pub struct Resource {
857    /// URI of the resource
858    pub uri: String,
859    /// Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).
860    pub name: String,
861    /// Description of the resource
862    #[serde(skip_serializing_if = "Option::is_none")]
863    pub description: Option<String>,
864    /// MIME type of the resource
865    #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
866    pub mime_type: Option<String>,
867    /// Resource annotations (2025-06-18)
868    #[serde(skip_serializing_if = "Option::is_none")]
869    pub annotations: Option<Annotations>,
870    /// Resource size in bytes (2025-06-18)
871    #[serde(skip_serializing_if = "Option::is_none")]
872    pub size: Option<u64>,
873    /// Intended for UI and end-user contexts
874    #[serde(skip_serializing_if = "Option::is_none")]
875    pub title: Option<String>,
876    /// Metadata field for future extensions
877    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
878    pub meta: Option<HashMap<String, serde_json::Value>>,
879}
880
881/// Resource template for URI patterns
882#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
883pub struct ResourceTemplate {
884    /// URI template with variables
885    #[serde(rename = "uriTemplate")]
886    pub uri_template: String,
887    /// Intended for programmatic or logical use
888    pub name: String,
889    /// Description of the resource template
890    #[serde(skip_serializing_if = "Option::is_none")]
891    pub description: Option<String>,
892    /// MIME type of resources from this template
893    #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
894    pub mime_type: Option<String>,
895    /// Resource annotations (2025-06-18)
896    #[serde(skip_serializing_if = "Option::is_none")]
897    pub annotations: Option<Annotations>,
898    /// Intended for UI and end-user contexts
899    #[serde(skip_serializing_if = "Option::is_none")]
900    pub title: Option<String>,
901    /// Metadata field for future extensions
902    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
903    pub meta: Option<HashMap<String, serde_json::Value>>,
904}
905
906/// Content of a resource (2025-06-18)
907#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
908#[serde(untagged)]
909pub enum ResourceContents {
910    /// Text resource content
911    Text {
912        /// URI of the resource
913        uri: String,
914        /// MIME type
915        #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
916        mime_type: Option<String>,
917        /// Text content
918        text: String,
919        /// Metadata field for future extensions
920        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
921        meta: Option<HashMap<String, serde_json::Value>>,
922    },
923    /// Binary resource content
924    Blob {
925        /// URI of the resource
926        uri: String,
927        /// MIME type
928        #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
929        mime_type: Option<String>,
930        /// Base64-encoded binary data
931        blob: String,
932        /// Metadata field for future extensions
933        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
934        meta: Option<HashMap<String, serde_json::Value>>,
935    },
936}
937
938impl ResourceContents {
939    /// Get the URI of the resource
940    pub fn uri(&self) -> &str {
941        match self {
942            ResourceContents::Text { uri, .. } => uri,
943            ResourceContents::Blob { uri, .. } => uri,
944        }
945    }
946}
947
948// Legacy type aliases for compatibility
949pub type ResourceInfo = Resource;
950
951// ============================================================================
952// Prompt Types (2025-06-18)
953// ============================================================================
954
955/// Prompt definition
956#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
957pub struct Prompt {
958    /// Intended for programmatic or logical use
959    pub name: String,
960    /// Description of what the prompt does
961    #[serde(skip_serializing_if = "Option::is_none")]
962    pub description: Option<String>,
963    /// Arguments that the prompt accepts
964    #[serde(skip_serializing_if = "Option::is_none")]
965    pub arguments: Option<Vec<PromptArgument>>,
966    /// Intended for UI and end-user contexts
967    #[serde(skip_serializing_if = "Option::is_none")]
968    pub title: Option<String>,
969    /// Metadata field for future extensions
970    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
971    pub meta: Option<HashMap<String, serde_json::Value>>,
972}
973
974/// Argument for a prompt
975#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
976pub struct PromptArgument {
977    /// Intended for programmatic or logical use
978    pub name: String,
979    /// Description of the argument
980    #[serde(skip_serializing_if = "Option::is_none")]
981    pub description: Option<String>,
982    /// Whether this argument is required
983    #[serde(skip_serializing_if = "Option::is_none")]
984    pub required: Option<bool>,
985    /// Intended for UI and end-user contexts
986    #[serde(skip_serializing_if = "Option::is_none")]
987    pub title: Option<String>,
988}
989
990/// Message role
991#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
992#[serde(rename_all = "lowercase")]
993pub enum Role {
994    User,
995    Assistant,
996}
997
998/// Message in a prompt result (2025-06-18 with ContentBlock support)
999#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1000pub struct PromptMessage {
1001    /// Role of the message
1002    pub role: Role,
1003    /// Content of the message (supports all content types including resource_link)
1004    pub content: ContentBlock,
1005}
1006
1007/// Result of prompt execution (2025-06-18 with metadata)
1008#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1009pub struct GetPromptResult {
1010    /// Description of the prompt result
1011    #[serde(skip_serializing_if = "Option::is_none")]
1012    pub description: Option<String>,
1013    /// Messages generated by the prompt
1014    pub messages: Vec<PromptMessage>,
1015    /// Result metadata (2025-06-18)
1016    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1017    pub meta: Option<HashMap<String, serde_json::Value>>,
1018}
1019
1020// Legacy type aliases for compatibility
1021pub type PromptInfo = Prompt;
1022pub type PromptResult = GetPromptResult;
1023
1024// ============================================================================
1025// Sampling Types (2025-06-18)
1026// ============================================================================
1027
1028/// A message in a sampling conversation (2025-06-18 with ContentBlock)
1029#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1030pub struct SamplingMessage {
1031    /// Role of the message
1032    pub role: Role,
1033    /// Content of the message (text, image, or audio only - no resource_link in sampling)
1034    pub content: SamplingContent,
1035}
1036
1037/// Content types allowed in sampling (subset of ContentBlock)
1038#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1039#[serde(tag = "type")]
1040pub enum SamplingContent {
1041    /// Text content
1042    #[serde(rename = "text")]
1043    Text {
1044        /// The text content
1045        text: String,
1046        /// Content annotations (2025-06-18)
1047        #[serde(skip_serializing_if = "Option::is_none")]
1048        annotations: Option<Annotations>,
1049        /// Metadata field for future extensions
1050        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1051        meta: Option<HashMap<String, serde_json::Value>>,
1052    },
1053    /// Image content
1054    #[serde(rename = "image")]
1055    Image {
1056        /// Base64-encoded image data
1057        data: String,
1058        /// MIME type of the image
1059        #[serde(rename = "mimeType")]
1060        mime_type: String,
1061        /// Content annotations (2025-06-18)
1062        #[serde(skip_serializing_if = "Option::is_none")]
1063        annotations: Option<Annotations>,
1064        /// Metadata field for future extensions
1065        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1066        meta: Option<HashMap<String, serde_json::Value>>,
1067    },
1068    /// Audio content (2025-06-18)
1069    #[serde(rename = "audio")]
1070    Audio {
1071        /// Base64-encoded audio data
1072        data: String,
1073        /// MIME type of the audio
1074        #[serde(rename = "mimeType")]
1075        mime_type: String,
1076        /// Content annotations (2025-06-18)
1077        #[serde(skip_serializing_if = "Option::is_none")]
1078        annotations: Option<Annotations>,
1079        /// Metadata field for future extensions
1080        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1081        meta: Option<HashMap<String, serde_json::Value>>,
1082    },
1083}
1084
1085/// Model hint for model selection (2025-06-18)
1086#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1087pub struct ModelHint {
1088    /// A hint for a model name.
1089    ///
1090    /// The client SHOULD treat this as a substring of a model name; for example:
1091    /// - `claude-3-5-sonnet` should match `claude-3-5-sonnet-20241022`
1092    /// - `sonnet` should match `claude-3-5-sonnet-20241022`, `claude-3-sonnet-20240229`, etc.
1093    /// - `claude` should match any Claude model
1094    #[serde(skip_serializing_if = "Option::is_none")]
1095    pub name: Option<String>,
1096
1097    /// Additional provider-specific hints for model selection.
1098    /// Keys not declared here are currently left unspecified by the spec and are up
1099    /// to the client to interpret. This allows provider-specific extensions.
1100    #[serde(flatten)]
1101    pub additional_hints: Option<HashMap<String, serde_json::Value>>,
1102}
1103
1104/// Model preferences for sampling (2025-06-18 improved)
1105#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
1106pub struct ModelPreferences {
1107    /// How much to prioritize cost when selecting a model
1108    #[serde(rename = "costPriority", skip_serializing_if = "Option::is_none")]
1109    pub cost_priority: Option<f64>,
1110    /// How much to prioritize sampling speed (latency) when selecting a model
1111    #[serde(rename = "speedPriority", skip_serializing_if = "Option::is_none")]
1112    pub speed_priority: Option<f64>,
1113    /// How much to prioritize intelligence and capabilities when selecting a model
1114    #[serde(
1115        rename = "intelligencePriority",
1116        skip_serializing_if = "Option::is_none"
1117    )]
1118    pub intelligence_priority: Option<f64>,
1119    /// Optional hints to use for model selection
1120    #[serde(skip_serializing_if = "Option::is_none")]
1121    pub hints: Option<Vec<ModelHint>>,
1122}
1123
1124/// Result of sampling/createMessage (2025-06-18)
1125#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1126pub struct CreateMessageResult {
1127    /// Role of the generated message
1128    pub role: Role,
1129    /// Content of the generated message
1130    pub content: SamplingContent,
1131    /// Model used for generation
1132    pub model: String,
1133    /// Stop reason
1134    #[serde(rename = "stopReason", skip_serializing_if = "Option::is_none")]
1135    pub stop_reason: Option<StopReason>,
1136    /// Result metadata (2025-06-18)
1137    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1138    pub meta: Option<HashMap<String, serde_json::Value>>,
1139}
1140
1141/// Reasons why sampling stopped
1142#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1143#[serde(rename_all = "camelCase")]
1144pub enum StopReason {
1145    EndTurn,
1146    StopSequence,
1147    MaxTokens,
1148    #[serde(untagged)]
1149    Other(String),
1150}
1151
1152// ============================================================================
1153// Elicitation Types (2025-06-18 NEW)
1154// ============================================================================
1155
1156/// Primitive schema definition for elicitation
1157#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1158#[serde(tag = "type")]
1159pub enum PrimitiveSchemaDefinition {
1160    #[serde(rename = "string")]
1161    String {
1162        #[serde(skip_serializing_if = "Option::is_none")]
1163        title: Option<String>,
1164        #[serde(skip_serializing_if = "Option::is_none")]
1165        description: Option<String>,
1166        #[serde(rename = "minLength", skip_serializing_if = "Option::is_none")]
1167        min_length: Option<u32>,
1168        #[serde(rename = "maxLength", skip_serializing_if = "Option::is_none")]
1169        max_length: Option<u32>,
1170        #[serde(skip_serializing_if = "Option::is_none")]
1171        format: Option<String>,
1172        #[serde(rename = "enum", skip_serializing_if = "Option::is_none")]
1173        enum_values: Option<Vec<String>>,
1174        #[serde(rename = "enumNames", skip_serializing_if = "Option::is_none")]
1175        enum_names: Option<Vec<String>>,
1176    },
1177    #[serde(rename = "number")]
1178    Number {
1179        #[serde(skip_serializing_if = "Option::is_none")]
1180        title: Option<String>,
1181        #[serde(skip_serializing_if = "Option::is_none")]
1182        description: Option<String>,
1183        #[serde(skip_serializing_if = "Option::is_none")]
1184        minimum: Option<i32>,
1185        #[serde(skip_serializing_if = "Option::is_none")]
1186        maximum: Option<i32>,
1187    },
1188    #[serde(rename = "integer")]
1189    Integer {
1190        #[serde(skip_serializing_if = "Option::is_none")]
1191        title: Option<String>,
1192        #[serde(skip_serializing_if = "Option::is_none")]
1193        description: Option<String>,
1194        #[serde(skip_serializing_if = "Option::is_none")]
1195        minimum: Option<i32>,
1196        #[serde(skip_serializing_if = "Option::is_none")]
1197        maximum: Option<i32>,
1198    },
1199    #[serde(rename = "boolean")]
1200    Boolean {
1201        #[serde(skip_serializing_if = "Option::is_none")]
1202        title: Option<String>,
1203        #[serde(skip_serializing_if = "Option::is_none")]
1204        description: Option<String>,
1205        #[serde(skip_serializing_if = "Option::is_none")]
1206        default: Option<bool>,
1207    },
1208}
1209
1210/// Restricted schema for elicitation (only top-level properties allowed)
1211#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1212pub struct ElicitationSchema {
1213    /// Schema type (always "object")
1214    #[serde(rename = "type")]
1215    pub schema_type: String,
1216    /// Top-level properties
1217    pub properties: HashMap<String, PrimitiveSchemaDefinition>,
1218    /// Required properties
1219    #[serde(skip_serializing_if = "Option::is_none")]
1220    pub required: Option<Vec<String>>,
1221}
1222
1223/// Elicitation user action
1224#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1225#[serde(rename_all = "lowercase")]
1226pub enum ElicitationAction {
1227    /// User submitted the form/confirmed the action
1228    Accept,
1229    /// User explicitly declined the action
1230    Decline,
1231    /// User dismissed without making an explicit choice
1232    Cancel,
1233}
1234
1235// ============================================================================
1236// Logging Types (2025-06-18)
1237// ============================================================================
1238
1239/// Logging level enumeration (2025-06-18)
1240#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1241#[serde(rename_all = "lowercase")]
1242pub enum LoggingLevel {
1243    Debug,
1244    Info,
1245    Notice,
1246    Warning,
1247    Error,
1248    Critical,
1249    Alert,
1250    Emergency,
1251}
1252
1253// ============================================================================
1254// JSON-RPC Types (2025-03-26 with Batching)
1255// ============================================================================
1256
1257/// JSON-RPC request message
1258#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1259pub struct JsonRpcRequest {
1260    /// JSON-RPC version (always "2.0")
1261    pub jsonrpc: String,
1262    /// Request ID for correlation
1263    pub id: RequestId,
1264    /// Method name being called
1265    pub method: String,
1266    /// Method parameters
1267    #[serde(skip_serializing_if = "Option::is_none")]
1268    pub params: Option<serde_json::Value>,
1269}
1270
1271/// JSON-RPC response message
1272#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1273pub struct JsonRpcResponse {
1274    /// JSON-RPC version (always "2.0")
1275    pub jsonrpc: String,
1276    /// Request ID for correlation
1277    pub id: RequestId,
1278    /// Result of the method call
1279    #[serde(skip_serializing_if = "Option::is_none")]
1280    pub result: Option<serde_json::Value>,
1281}
1282
1283/// JSON-RPC error message
1284#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1285pub struct JsonRpcError {
1286    /// JSON-RPC version (always "2.0")
1287    pub jsonrpc: String,
1288    /// Request ID for correlation
1289    pub id: RequestId,
1290    /// Error information
1291    pub error: ErrorObject,
1292}
1293
1294/// Error object
1295#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1296pub struct ErrorObject {
1297    /// Error code
1298    pub code: i32,
1299    /// Error message
1300    pub message: String,
1301    /// Additional error data
1302    #[serde(skip_serializing_if = "Option::is_none")]
1303    pub data: Option<serde_json::Value>,
1304}
1305
1306/// JSON-RPC notification message
1307#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1308pub struct JsonRpcNotification {
1309    /// JSON-RPC version (always "2.0")
1310    pub jsonrpc: String,
1311    /// Method name being called
1312    pub method: String,
1313    /// Method parameters
1314    #[serde(skip_serializing_if = "Option::is_none")]
1315    pub params: Option<serde_json::Value>,
1316}
1317
1318/// JSON-RPC message types (2025-06-18)
1319#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1320#[serde(untagged)]
1321pub enum JsonRpcMessage {
1322    Request(JsonRpcRequest),
1323    Response(JsonRpcResponse),
1324    Error(JsonRpcError),
1325    Notification(JsonRpcNotification),
1326}
1327
1328// ============================================================================
1329// Request/Response Metadata (2025-03-26 NEW)
1330// ============================================================================
1331
1332/// Base request with metadata support
1333#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1334pub struct Request {
1335    /// Method name
1336    pub method: String,
1337    /// Parameters with metadata support
1338    #[serde(skip_serializing_if = "Option::is_none")]
1339    pub params: Option<RequestParams>,
1340}
1341
1342/// Request parameters with metadata
1343#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1344pub struct RequestParams {
1345    /// Request metadata (2025-03-26 NEW)
1346    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1347    pub meta: Option<RequestMeta>,
1348    /// Additional parameters
1349    #[serde(flatten)]
1350    pub params: HashMap<String, serde_json::Value>,
1351}
1352
1353/// Request metadata
1354#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1355pub struct RequestMeta {
1356    /// Progress token for out-of-band progress notifications
1357    #[serde(rename = "progressToken", skip_serializing_if = "Option::is_none")]
1358    pub progress_token: Option<ProgressToken>,
1359}
1360
1361/// Base notification with metadata support
1362#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1363pub struct Notification {
1364    /// Method name
1365    pub method: String,
1366    /// Parameters with metadata support
1367    #[serde(skip_serializing_if = "Option::is_none")]
1368    pub params: Option<NotificationParams>,
1369}
1370
1371/// Notification parameters with metadata
1372#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1373pub struct NotificationParams {
1374    /// Notification metadata (2025-03-26 NEW)
1375    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1376    pub meta: Option<HashMap<String, serde_json::Value>>,
1377    /// Additional parameters
1378    #[serde(flatten)]
1379    pub params: HashMap<String, serde_json::Value>,
1380}
1381
1382// ============================================================================
1383// Pagination Support
1384// ============================================================================
1385
1386/// Base for paginated requests
1387#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1388pub struct PaginatedRequest {
1389    /// Cursor for pagination
1390    #[serde(skip_serializing_if = "Option::is_none")]
1391    pub cursor: Option<Cursor>,
1392}
1393
1394/// Base for paginated results
1395#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1396pub struct PaginatedResult {
1397    /// Cursor for next page
1398    #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
1399    pub next_cursor: Option<Cursor>,
1400}
1401
1402// ============================================================================
1403
1404impl SamplingContent {
1405    /// Create text content for sampling
1406    pub fn text<S: Into<String>>(text: S) -> Self {
1407        Self::Text {
1408            text: text.into(),
1409            annotations: None,
1410            meta: None,
1411        }
1412    }
1413
1414    /// Create image content for sampling
1415    pub fn image<S: Into<String>>(data: S, mime_type: S) -> Self {
1416        Self::Image {
1417            data: data.into(),
1418            mime_type: mime_type.into(),
1419            annotations: None,
1420            meta: None,
1421        }
1422    }
1423
1424    /// Create audio content for sampling
1425    pub fn audio<S: Into<String>>(data: S, mime_type: S) -> Self {
1426        Self::Audio {
1427            data: data.into(),
1428            mime_type: mime_type.into(),
1429            annotations: None,
1430            meta: None,
1431        }
1432    }
1433}
1434
1435impl Annotations {
1436    /// Create new annotations
1437    pub fn new() -> Self {
1438        Self {
1439            audience: None,
1440            priority: None,
1441            last_modified: None,
1442            danger: None,
1443            destructive: None,
1444            read_only: None,
1445        }
1446    }
1447
1448    /// Set priority (0.0 = least important, 1.0 = most important)
1449    pub fn with_priority(mut self, priority: f64) -> Self {
1450        self.priority = Some(priority.clamp(0.0, 1.0));
1451        self
1452    }
1453
1454    /// Set audience
1455    pub fn for_audience(mut self, audience: Vec<Role>) -> Self {
1456        self.audience = Some(audience);
1457        self
1458    }
1459
1460    /// Set last modified timestamp (ISO 8601 format)
1461    pub fn with_last_modified<S: Into<String>>(mut self, timestamp: S) -> Self {
1462        self.last_modified = Some(timestamp.into());
1463        self
1464    }
1465
1466    /// Set audience (legacy compatibility)
1467    pub fn for_audience_legacy(self, _audience: Vec<AnnotationAudience>) -> Self {
1468        // Legacy compatibility - ignore audience in new API
1469        self
1470    }
1471
1472    /// Set danger level (legacy compatibility)
1473    pub fn with_danger_level(mut self, level: DangerLevel) -> Self {
1474        // Legacy compatibility - set danger field for backward compatibility
1475        self.danger = Some(level);
1476        self
1477    }
1478
1479    /// Legacy danger field (always returns None for compatibility)
1480    pub fn danger(&self) -> Option<DangerLevel> {
1481        None
1482    }
1483
1484    /// Legacy audience field (always returns None for compatibility)
1485    pub fn audience(&self) -> Option<Vec<AnnotationAudience>> {
1486        None
1487    }
1488
1489    /// Set as read-only (legacy compatibility)
1490    pub fn read_only(mut self) -> Self {
1491        self.read_only = Some(true);
1492        self.destructive = Some(false);
1493        self
1494    }
1495
1496    /// Set as destructive (legacy compatibility)
1497    pub fn destructive(mut self, level: DangerLevel) -> Self {
1498        self.destructive = Some(true);
1499        self.read_only = Some(false);
1500        self.danger = Some(level);
1501        self
1502    }
1503}
1504
1505impl Tool {
1506    /// Create a new tool
1507    pub fn new<S: Into<String>>(name: S, description: S) -> Self {
1508        Self {
1509            name: name.into(),
1510            description: Some(description.into()),
1511            input_schema: ToolInputSchema {
1512                schema_type: "object".to_string(),
1513                properties: None,
1514                required: None,
1515                additional_properties: HashMap::new(),
1516            },
1517            output_schema: None,
1518            annotations: None,
1519            title: None,
1520            meta: None,
1521        }
1522    }
1523
1524    /// Add title to the tool
1525    pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1526        self.title = Some(title.into());
1527        self
1528    }
1529
1530    /// Add annotations to the tool
1531    pub fn with_annotations(mut self, annotations: ToolAnnotations) -> Self {
1532        self.annotations = Some(annotations);
1533        self
1534    }
1535
1536    /// Add output schema to the tool (2025-06-18 NEW)
1537    pub fn with_output_schema(mut self, output_schema: ToolOutputSchema) -> Self {
1538        self.output_schema = Some(output_schema);
1539        self
1540    }
1541}
1542
1543impl Resource {
1544    /// Create a new resource
1545    pub fn new<S: Into<String>>(uri: S, name: S) -> Self {
1546        Self {
1547            uri: uri.into(),
1548            name: name.into(),
1549            description: None,
1550            mime_type: None,
1551            annotations: None,
1552            size: None,
1553            title: None,
1554            meta: None,
1555        }
1556    }
1557
1558    /// Create a resource from legacy format (name was optional)
1559    pub fn from_legacy<S: Into<String>>(uri: S, name: Option<S>) -> Self {
1560        Self {
1561            uri: uri.into(),
1562            name: name
1563                .map(|n| n.into())
1564                .unwrap_or_else(|| "Unnamed Resource".to_string()),
1565            description: None,
1566            mime_type: None,
1567            annotations: None,
1568            size: None,
1569            title: None,
1570            meta: None,
1571        }
1572    }
1573
1574    /// Add title to the resource
1575    pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1576        self.title = Some(title.into());
1577        self
1578    }
1579
1580    /// Add description to the resource
1581    pub fn with_description<S: Into<String>>(mut self, description: S) -> Self {
1582        self.description = Some(description.into());
1583        self
1584    }
1585}
1586
1587impl ResourceTemplate {
1588    /// Create a new resource template
1589    pub fn new<S: Into<String>>(uri_template: S, name: S) -> Self {
1590        Self {
1591            uri_template: uri_template.into(),
1592            name: name.into(),
1593            description: None,
1594            mime_type: None,
1595            annotations: None,
1596            title: None,
1597            meta: None,
1598        }
1599    }
1600
1601    /// Create a resource template from legacy format (name was optional)
1602    pub fn from_legacy<S: Into<String>>(uri_template: S, name: Option<S>) -> Self {
1603        Self {
1604            uri_template: uri_template.into(),
1605            name: name
1606                .map(|n| n.into())
1607                .unwrap_or_else(|| "Unnamed Template".to_string()),
1608            description: None,
1609            mime_type: None,
1610            annotations: None,
1611            title: None,
1612            meta: None,
1613        }
1614    }
1615
1616    /// Add title to the resource template
1617    pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1618        self.title = Some(title.into());
1619        self
1620    }
1621}
1622
1623impl Prompt {
1624    /// Create a new prompt
1625    pub fn new<S: Into<String>>(name: S) -> Self {
1626        Self {
1627            name: name.into(),
1628            description: None,
1629            arguments: None,
1630            title: None,
1631            meta: None,
1632        }
1633    }
1634
1635    /// Add title to the prompt
1636    pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1637        self.title = Some(title.into());
1638        self
1639    }
1640
1641    /// Add description to the prompt
1642    pub fn with_description<S: Into<String>>(mut self, description: S) -> Self {
1643        self.description = Some(description.into());
1644        self
1645    }
1646}
1647
1648impl PromptArgument {
1649    /// Create a new prompt argument
1650    pub fn new<S: Into<String>>(name: S) -> Self {
1651        Self {
1652            name: name.into(),
1653            description: None,
1654            required: None,
1655            title: None,
1656        }
1657    }
1658
1659    /// Add title to the prompt argument
1660    pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1661        self.title = Some(title.into());
1662        self
1663    }
1664
1665    /// Mark as required
1666    pub fn required(mut self, required: bool) -> Self {
1667        self.required = Some(required);
1668        self
1669    }
1670}
1671
1672impl JsonRpcRequest {
1673    /// Create a new JSON-RPC request
1674    pub fn new<T: Serialize>(
1675        id: RequestId,
1676        method: String,
1677        params: Option<T>,
1678    ) -> std::result::Result<Self, serde_json::Error> {
1679        let params = match params {
1680            Some(p) => Some(serde_json::to_value(p)?),
1681            None => None,
1682        };
1683
1684        Ok(Self {
1685            jsonrpc: JSONRPC_VERSION.to_string(),
1686            id,
1687            method,
1688            params,
1689        })
1690    }
1691}
1692
1693impl JsonRpcResponse {
1694    /// Create a successful JSON-RPC response
1695    pub fn success<T: Serialize>(
1696        id: RequestId,
1697        result: T,
1698    ) -> std::result::Result<Self, serde_json::Error> {
1699        Ok(Self {
1700            jsonrpc: JSONRPC_VERSION.to_string(),
1701            id,
1702            result: Some(serde_json::to_value(result)?),
1703        })
1704    }
1705
1706    /// Create a successful JSON-RPC response with an already-serialized value
1707    /// This is an infallible version that takes a pre-serialized Value
1708    pub fn success_unchecked(id: RequestId, result: serde_json::Value) -> Self {
1709        Self {
1710            jsonrpc: JSONRPC_VERSION.to_string(),
1711            id,
1712            result: Some(result),
1713        }
1714    }
1715}
1716
1717impl JsonRpcError {
1718    /// Create an error JSON-RPC response
1719    pub fn error(
1720        id: RequestId,
1721        code: i32,
1722        message: String,
1723        data: Option<serde_json::Value>,
1724    ) -> Self {
1725        Self {
1726            jsonrpc: JSONRPC_VERSION.to_string(),
1727            id,
1728            error: ErrorObject {
1729                code,
1730                message,
1731                data,
1732            },
1733        }
1734    }
1735}
1736
1737impl JsonRpcNotification {
1738    /// Create a new JSON-RPC notification
1739    pub fn new<T: Serialize>(
1740        method: String,
1741        params: Option<T>,
1742    ) -> std::result::Result<Self, serde_json::Error> {
1743        let params = match params {
1744            Some(p) => Some(serde_json::to_value(p)?),
1745            None => None,
1746        };
1747
1748        Ok(Self {
1749            jsonrpc: JSONRPC_VERSION.to_string(),
1750            method,
1751            params,
1752        })
1753    }
1754}
1755
1756impl SamplingMessage {
1757    /// Create a user text message
1758    pub fn user_text<S: Into<String>>(text: S) -> Self {
1759        Self {
1760            role: Role::User,
1761            content: SamplingContent::text(text),
1762        }
1763    }
1764
1765    /// Create an assistant text message
1766    pub fn assistant_text<S: Into<String>>(text: S) -> Self {
1767        Self {
1768            role: Role::Assistant,
1769            content: SamplingContent::text(text),
1770        }
1771    }
1772
1773    /// Create a user image message
1774    pub fn user_image<S: Into<String>>(data: S, mime_type: S) -> Self {
1775        Self {
1776            role: Role::User,
1777            content: SamplingContent::image(data, mime_type),
1778        }
1779    }
1780
1781    /// Create a user audio message
1782    pub fn user_audio<S: Into<String>>(data: S, mime_type: S) -> Self {
1783        Self {
1784            role: Role::User,
1785            content: SamplingContent::audio(data, mime_type),
1786        }
1787    }
1788}
1789
1790// ============================================================================
1791// Error Codes
1792// ============================================================================
1793
1794/// Standard JSON-RPC error codes
1795pub mod error_codes {
1796    /// Invalid JSON was received
1797    pub const PARSE_ERROR: i32 = -32700;
1798    /// The JSON sent is not a valid Request object
1799    pub const INVALID_REQUEST: i32 = -32600;
1800    /// The method does not exist / is not available
1801    pub const METHOD_NOT_FOUND: i32 = -32601;
1802    /// Invalid method parameter(s)
1803    pub const INVALID_PARAMS: i32 = -32602;
1804    /// Internal JSON-RPC error
1805    pub const INTERNAL_ERROR: i32 = -32603;
1806
1807    /// MCP-specific error codes
1808    pub const TOOL_NOT_FOUND: i32 = -32000;
1809    pub const RESOURCE_NOT_FOUND: i32 = -32001;
1810    pub const PROMPT_NOT_FOUND: i32 = -32002;
1811}
1812
1813#[cfg(test)]
1814mod tests {
1815    use super::*;
1816    use serde_json::json;
1817
1818    #[test]
1819    fn test_protocol_version() {
1820        assert_eq!(LATEST_PROTOCOL_VERSION, "2025-06-18");
1821        assert_eq!(JSONRPC_VERSION, "2.0");
1822    }
1823
1824    #[test]
1825    fn test_content_block_types() {
1826        // Test text content
1827        let text = ContentBlock::text("Hello, world!");
1828        let json = serde_json::to_value(&text).unwrap();
1829        assert_eq!(json["type"], "text");
1830        assert_eq!(json["text"], "Hello, world!");
1831
1832        // Test audio content (2025-06-18)
1833        let audio = ContentBlock::audio("base64data", "audio/wav");
1834        let json = serde_json::to_value(&audio).unwrap();
1835        assert_eq!(json["type"], "audio");
1836        assert_eq!(json["data"], "base64data");
1837        assert_eq!(json["mimeType"], "audio/wav");
1838
1839        // Test resource link content (new in 2025-06-18)
1840        let resource_link = ContentBlock::resource_link("file:///test.txt", "test file");
1841        let json = serde_json::to_value(&resource_link).unwrap();
1842        assert_eq!(json["type"], "resource_link");
1843        assert_eq!(json["uri"], "file:///test.txt");
1844        assert_eq!(json["name"], "test file");
1845    }
1846
1847    #[test]
1848    fn test_annotations() {
1849        let annotations = Annotations::new()
1850            .with_priority(0.8)
1851            .for_audience(vec![Role::User, Role::Assistant])
1852            .with_last_modified("2025-01-12T15:00:58Z");
1853
1854        assert_eq!(annotations.priority, Some(0.8));
1855        assert_eq!(
1856            annotations.audience,
1857            Some(vec![Role::User, Role::Assistant])
1858        );
1859        assert_eq!(
1860            annotations.last_modified,
1861            Some("2025-01-12T15:00:58Z".to_string())
1862        );
1863    }
1864
1865    #[test]
1866    fn test_tool_with_title() {
1867        let tool = Tool::new("file_reader", "Read files safely")
1868            .with_title("File Reader Tool")
1869            .with_annotations(ToolAnnotations::new().with_title("File Reader"));
1870
1871        assert_eq!(tool.name, "file_reader");
1872        assert_eq!(tool.title, Some("File Reader Tool".to_string()));
1873        assert!(tool.annotations.is_some());
1874        assert_eq!(
1875            tool.annotations.unwrap().title,
1876            Some("File Reader".to_string())
1877        );
1878    }
1879
1880    #[test]
1881    fn test_tool_with_output_schema() {
1882        use serde_json::json;
1883
1884        // Create output schema
1885        let output_schema = ToolOutputSchema::with_properties(HashMap::from([
1886            ("result".to_string(), json!({"type": "string"})),
1887            ("count".to_string(), json!({"type": "number"})),
1888        ]))
1889        .with_required(vec!["result".to_string()]);
1890
1891        // Create tool with output schema
1892        let tool = Tool::new(
1893            "data_processor",
1894            "Processes data and returns structured output",
1895        )
1896        .with_title("Data Processor")
1897        .with_output_schema(output_schema);
1898
1899        // Verify fields
1900        assert_eq!(tool.name, "data_processor");
1901        assert_eq!(tool.title, Some("Data Processor".to_string()));
1902        assert!(tool.output_schema.is_some());
1903
1904        let schema = tool.output_schema.as_ref().unwrap();
1905        assert_eq!(schema.schema_type, "object");
1906        assert!(schema.properties.is_some());
1907        assert_eq!(schema.required, Some(vec!["result".to_string()]));
1908
1909        // Test serialization
1910        let json = serde_json::to_value(&tool).unwrap();
1911        assert_eq!(json["name"], "data_processor");
1912        assert!(json["inputSchema"].is_object());
1913        assert!(json["outputSchema"].is_object());
1914        assert_eq!(json["outputSchema"]["type"], "object");
1915        assert!(json["outputSchema"]["properties"].is_object());
1916        assert!(json["outputSchema"]["required"].is_array());
1917    }
1918
1919    #[test]
1920    fn test_server_capabilities_2025_06_18() {
1921        let caps = ServerCapabilities {
1922            tools: Some(ToolsCapability {
1923                list_changed: Some(true),
1924            }),
1925            completions: Some(CompletionsCapability::default()),
1926            logging: Some(LoggingCapability::default()),
1927            experimental: Some(HashMap::new()),
1928            ..Default::default()
1929        };
1930
1931        let json = serde_json::to_value(&caps).unwrap();
1932        assert!(json["tools"]["listChanged"].as_bool().unwrap());
1933        assert!(json["completions"].is_object());
1934        assert!(json["logging"].is_object());
1935        assert!(json["experimental"].is_object());
1936    }
1937
1938    #[test]
1939    fn test_client_capabilities_with_elicitation() {
1940        let caps = ClientCapabilities {
1941            elicitation: Some(ElicitationCapability::default()),
1942            roots: Some(RootsCapability {
1943                list_changed: Some(true),
1944            }),
1945            ..Default::default()
1946        };
1947
1948        let json = serde_json::to_value(&caps).unwrap();
1949        assert!(json["elicitation"].is_object());
1950        assert!(json["roots"]["listChanged"].as_bool().unwrap());
1951    }
1952
1953    #[test]
1954    fn test_implementation_with_title() {
1955        let impl_info = Implementation::with_title("my-server", "1.0.0", "My Awesome Server");
1956
1957        assert_eq!(impl_info.name, "my-server");
1958        assert_eq!(impl_info.version, "1.0.0");
1959        assert_eq!(impl_info.title, Some("My Awesome Server".to_string()));
1960    }
1961
1962    #[test]
1963    fn test_model_preferences_improved() {
1964        let prefs = ModelPreferences {
1965            cost_priority: Some(0.3),
1966            speed_priority: Some(0.7),
1967            intelligence_priority: Some(0.9),
1968            hints: Some(vec![ModelHint {
1969                name: Some("claude".to_string()),
1970                additional_hints: None,
1971            }]),
1972        };
1973
1974        let json = serde_json::to_value(&prefs).unwrap();
1975        assert_eq!(json["costPriority"], 0.3);
1976        assert_eq!(json["speedPriority"], 0.7);
1977        assert_eq!(json["intelligencePriority"], 0.9);
1978        assert!(json["hints"].is_array());
1979    }
1980
1981    #[test]
1982    fn test_call_tool_result_with_structured_content() {
1983        let result = CallToolResult {
1984            content: vec![ContentBlock::text("Operation completed")],
1985            is_error: Some(false),
1986            structured_content: Some(json!({"status": "success", "count": 42})),
1987            meta: None,
1988        };
1989
1990        let json = serde_json::to_value(&result).unwrap();
1991        assert!(json["content"].is_array());
1992        assert_eq!(json["isError"], false);
1993        assert_eq!(json["structuredContent"]["status"], "success");
1994        assert_eq!(json["structuredContent"]["count"], 42);
1995    }
1996
1997    #[test]
1998    fn test_sampling_content_types() {
1999        // Test that SamplingContent doesn't include resource_link
2000        let text = SamplingContent::text("Hello");
2001        let image = SamplingContent::image("data", "image/png");
2002        let audio = SamplingContent::audio("data", "audio/wav");
2003
2004        let text_json = serde_json::to_value(&text).unwrap();
2005        let image_json = serde_json::to_value(&image).unwrap();
2006        let audio_json = serde_json::to_value(&audio).unwrap();
2007
2008        assert_eq!(text_json["type"], "text");
2009        assert_eq!(image_json["type"], "image");
2010        assert_eq!(audio_json["type"], "audio");
2011    }
2012}
2013
2014// ============================================================================
2015// Legacy/Compatibility Types for Tests
2016// ============================================================================
2017
2018/// Batch request type alias for compatibility
2019pub type JsonRpcBatchRequest = Vec<JsonRpcRequest>;
2020
2021/// Batch response type alias for compatibility
2022pub type JsonRpcBatchResponse = Vec<JsonRpcResponse>;
2023
2024/// Request or notification union for compatibility
2025#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2026#[serde(untagged)]
2027pub enum JsonRpcRequestOrNotification {
2028    Request(JsonRpcRequest),
2029    Notification(JsonRpcNotification),
2030}
2031
2032/// Response or error union for compatibility
2033#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2034#[serde(untagged)]
2035pub enum JsonRpcResponseOrError {
2036    Response(JsonRpcResponse),
2037    Error(JsonRpcError),
2038}
2039
2040/// Annotation audience for content targeting (legacy)
2041#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2042pub enum AnnotationAudience {
2043    User,
2044    Developer,
2045    System,
2046}
2047
2048/// Danger level for tool safety annotations (legacy)
2049#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2050pub enum DangerLevel {
2051    Safe,
2052    Low,
2053    Medium,
2054    High,
2055}