mcp_protocol_sdk/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//! enhanced 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 — optimized 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 — optimized 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 Enhanced)
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 entirely 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 complete with 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// Tool Types (2025-06-18 with Title and Structured Content)
467// ============================================================================
468
469/// Tool-specific annotations (2025-06-18 Schema Compliance)
470///
471/// NOTE: all properties in ToolAnnotations are **hints**.
472/// They are not guaranteed to provide a faithful description of
473/// tool behavior (including descriptive properties like `title`).
474///
475/// Clients should never make tool use decisions based on ToolAnnotations
476/// received from untrusted servers.
477#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
478pub struct ToolAnnotations {
479    /// A human-readable title for the tool
480    #[serde(skip_serializing_if = "Option::is_none")]
481    pub title: Option<String>,
482
483    /// If true, the tool does not modify its environment
484    /// Default: false
485    #[serde(rename = "readOnlyHint", skip_serializing_if = "Option::is_none")]
486    pub read_only_hint: Option<bool>,
487
488    /// If true, the tool may perform destructive updates to its environment
489    /// If false, the tool performs only additive updates
490    /// (This property is meaningful only when `readOnlyHint == false`)
491    /// Default: true
492    #[serde(rename = "destructiveHint", skip_serializing_if = "Option::is_none")]
493    pub destructive_hint: Option<bool>,
494
495    /// If true, calling the tool repeatedly with the same arguments
496    /// will have no additional effect on its environment
497    /// (This property is meaningful only when `readOnlyHint == false`)
498    /// Default: false
499    #[serde(rename = "idempotentHint", skip_serializing_if = "Option::is_none")]
500    pub idempotent_hint: Option<bool>,
501
502    /// If true, this tool may interact with an "open world" of external entities
503    /// If false, the tool's domain of interaction is closed
504    /// For example, the world of a web search tool is open, whereas that
505    /// of a memory tool is not
506    /// Default: true
507    #[serde(rename = "openWorldHint", skip_serializing_if = "Option::is_none")]
508    pub open_world_hint: Option<bool>,
509}
510
511impl ToolAnnotations {
512    /// Create new empty tool annotations
513    pub fn new() -> Self {
514        Self::default()
515    }
516
517    /// Set the human-readable title for the tool
518    pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
519        self.title = Some(title.into());
520        self
521    }
522
523    /// Mark tool as read-only (does not modify environment)
524    pub fn read_only(mut self) -> Self {
525        self.read_only_hint = Some(true);
526        self
527    }
528
529    /// Mark tool as destructive (may perform destructive updates)
530    pub fn destructive(mut self) -> Self {
531        self.destructive_hint = Some(true);
532        self
533    }
534
535    /// Mark tool as idempotent (same input produces same result)
536    pub fn idempotent(mut self) -> Self {
537        self.idempotent_hint = Some(true);
538        self
539    }
540
541    /// Mark tool as interacting with open world of external entities
542    pub fn open_world(mut self) -> Self {
543        self.open_world_hint = Some(true);
544        self
545    }
546
547    /// Mark tool as interacting with closed world (limited domain)
548    pub fn closed_world(mut self) -> Self {
549        self.open_world_hint = Some(false);
550        self
551    }
552}
553
554// ============================================================================
555// Tool Annotations Integration with Enhanced Metadata
556// ============================================================================
557
558impl From<&crate::core::tool_metadata::ToolBehaviorHints> for ToolAnnotations {
559    fn from(hints: &crate::core::tool_metadata::ToolBehaviorHints) -> Self {
560        Self {
561            title: None, // Title should be set separately at tool level
562            read_only_hint: hints.read_only,
563            destructive_hint: hints.destructive,
564            idempotent_hint: hints.idempotent,
565            // Map open_world_hint: if requires_auth or resource_intensive, likely open world
566            open_world_hint: if hints.requires_auth.unwrap_or(false)
567                || hints.resource_intensive.unwrap_or(false)
568            {
569                Some(true)
570            } else {
571                None
572            },
573        }
574    }
575}
576
577impl From<&crate::core::tool_metadata::EnhancedToolMetadata> for ToolAnnotations {
578    fn from(metadata: &crate::core::tool_metadata::EnhancedToolMetadata) -> Self {
579        ToolAnnotations::from(&metadata.behavior_hints)
580    }
581}
582
583impl ToolAnnotations {
584    /// Create ToolAnnotations from enhanced metadata with explicit title override
585    pub fn from_enhanced_metadata(
586        metadata: &crate::core::tool_metadata::EnhancedToolMetadata,
587        title_override: Option<String>,
588    ) -> Self {
589        let mut annotations = Self::from(metadata);
590        if let Some(title) = title_override {
591            annotations.title = Some(title);
592        }
593        annotations
594    }
595
596    /// Create minimal ToolAnnotations from behavior hints
597    pub fn from_behavior_hints(hints: &crate::core::tool_metadata::ToolBehaviorHints) -> Self {
598        Self::from(hints)
599    }
600}
601
602/// Tool definition with annotations and title (2025-06-18)
603#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
604pub struct Tool {
605    /// Intended for programmatic or logical use
606    pub name: String,
607    /// Description of what the tool does
608    #[serde(skip_serializing_if = "Option::is_none")]
609    pub description: Option<String>,
610    /// JSON Schema describing the tool's input parameters
611    #[serde(rename = "inputSchema")]
612    pub input_schema: ToolInputSchema,
613    /// Tool behavior annotations (2025-06-18)
614    #[serde(skip_serializing_if = "Option::is_none")]
615    pub annotations: Option<ToolAnnotations>,
616    /// Intended for UI and end-user contexts
617    #[serde(skip_serializing_if = "Option::is_none")]
618    pub title: Option<String>,
619    /// Metadata field for future extensions
620    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
621    pub meta: Option<HashMap<String, serde_json::Value>>,
622}
623
624/// Tool input schema
625#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
626pub struct ToolInputSchema {
627    /// Schema type (always "object")
628    #[serde(rename = "type")]
629    pub schema_type: String,
630    /// Schema properties
631    #[serde(skip_serializing_if = "Option::is_none")]
632    pub properties: Option<HashMap<String, serde_json::Value>>,
633    /// Required properties
634    #[serde(skip_serializing_if = "Option::is_none")]
635    pub required: Option<Vec<String>>,
636    /// Additional schema properties
637    #[serde(flatten)]
638    pub additional_properties: HashMap<String, serde_json::Value>,
639}
640
641/// Result of a tool execution (2025-06-18 with structured content)
642#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
643pub struct CallToolResult {
644    /// Content returned by the tool
645    pub content: Vec<ContentBlock>,
646    /// Whether this result represents an error
647    #[serde(rename = "isError", skip_serializing_if = "Option::is_none")]
648    pub is_error: Option<bool>,
649    /// An optional JSON object that represents the structured result of the tool call
650    #[serde(rename = "structuredContent", skip_serializing_if = "Option::is_none")]
651    pub structured_content: Option<serde_json::Value>,
652    /// Result metadata (2025-06-18)
653    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
654    pub meta: Option<HashMap<String, serde_json::Value>>,
655}
656
657// Re-export types with legacy names for compatibility
658pub type ToolInfo = Tool;
659pub type ToolResult = CallToolResult;
660
661// ============================================================================
662// Resource Types (2025-06-18)
663// ============================================================================
664
665/// Resource definition
666#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
667pub struct Resource {
668    /// URI of the resource
669    pub uri: String,
670    /// Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).
671    pub name: String,
672    /// Description of the resource
673    #[serde(skip_serializing_if = "Option::is_none")]
674    pub description: Option<String>,
675    /// MIME type of the resource
676    #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
677    pub mime_type: Option<String>,
678    /// Resource annotations (2025-06-18)
679    #[serde(skip_serializing_if = "Option::is_none")]
680    pub annotations: Option<Annotations>,
681    /// Resource size in bytes (2025-06-18)
682    #[serde(skip_serializing_if = "Option::is_none")]
683    pub size: Option<u64>,
684    /// Intended for UI and end-user contexts
685    #[serde(skip_serializing_if = "Option::is_none")]
686    pub title: Option<String>,
687    /// Metadata field for future extensions
688    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
689    pub meta: Option<HashMap<String, serde_json::Value>>,
690}
691
692/// Resource template for URI patterns
693#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
694pub struct ResourceTemplate {
695    /// URI template with variables
696    #[serde(rename = "uriTemplate")]
697    pub uri_template: String,
698    /// Intended for programmatic or logical use
699    pub name: String,
700    /// Description of the resource template
701    #[serde(skip_serializing_if = "Option::is_none")]
702    pub description: Option<String>,
703    /// MIME type of resources from this template
704    #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
705    pub mime_type: Option<String>,
706    /// Resource annotations (2025-06-18)
707    #[serde(skip_serializing_if = "Option::is_none")]
708    pub annotations: Option<Annotations>,
709    /// Intended for UI and end-user contexts
710    #[serde(skip_serializing_if = "Option::is_none")]
711    pub title: Option<String>,
712    /// Metadata field for future extensions
713    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
714    pub meta: Option<HashMap<String, serde_json::Value>>,
715}
716
717/// Content of a resource (2025-06-18)
718#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
719#[serde(untagged)]
720pub enum ResourceContents {
721    /// Text resource content
722    Text {
723        /// URI of the resource
724        uri: String,
725        /// MIME type
726        #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
727        mime_type: Option<String>,
728        /// Text content
729        text: String,
730        /// Metadata field for future extensions
731        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
732        meta: Option<HashMap<String, serde_json::Value>>,
733    },
734    /// Binary resource content
735    Blob {
736        /// URI of the resource
737        uri: String,
738        /// MIME type
739        #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
740        mime_type: Option<String>,
741        /// Base64-encoded binary data
742        blob: String,
743        /// Metadata field for future extensions
744        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
745        meta: Option<HashMap<String, serde_json::Value>>,
746    },
747}
748
749impl ResourceContents {
750    /// Get the URI of the resource
751    pub fn uri(&self) -> &str {
752        match self {
753            ResourceContents::Text { uri, .. } => uri,
754            ResourceContents::Blob { uri, .. } => uri,
755        }
756    }
757}
758
759// Legacy type aliases for compatibility
760pub type ResourceInfo = Resource;
761
762// ============================================================================
763// Prompt Types (2025-06-18)
764// ============================================================================
765
766/// Prompt definition
767#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
768pub struct Prompt {
769    /// Intended for programmatic or logical use
770    pub name: String,
771    /// Description of what the prompt does
772    #[serde(skip_serializing_if = "Option::is_none")]
773    pub description: Option<String>,
774    /// Arguments that the prompt accepts
775    #[serde(skip_serializing_if = "Option::is_none")]
776    pub arguments: Option<Vec<PromptArgument>>,
777    /// Intended for UI and end-user contexts
778    #[serde(skip_serializing_if = "Option::is_none")]
779    pub title: Option<String>,
780    /// Metadata field for future extensions
781    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
782    pub meta: Option<HashMap<String, serde_json::Value>>,
783}
784
785/// Argument for a prompt
786#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
787pub struct PromptArgument {
788    /// Intended for programmatic or logical use
789    pub name: String,
790    /// Description of the argument
791    #[serde(skip_serializing_if = "Option::is_none")]
792    pub description: Option<String>,
793    /// Whether this argument is required
794    #[serde(skip_serializing_if = "Option::is_none")]
795    pub required: Option<bool>,
796    /// Intended for UI and end-user contexts
797    #[serde(skip_serializing_if = "Option::is_none")]
798    pub title: Option<String>,
799}
800
801/// Message role
802#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
803#[serde(rename_all = "lowercase")]
804pub enum Role {
805    User,
806    Assistant,
807}
808
809/// Message in a prompt result (2025-06-18 with ContentBlock support)
810#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
811pub struct PromptMessage {
812    /// Role of the message
813    pub role: Role,
814    /// Content of the message (supports all content types including resource_link)
815    pub content: ContentBlock,
816}
817
818/// Result of prompt execution (2025-06-18 with metadata)
819#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
820pub struct GetPromptResult {
821    /// Description of the prompt result
822    #[serde(skip_serializing_if = "Option::is_none")]
823    pub description: Option<String>,
824    /// Messages generated by the prompt
825    pub messages: Vec<PromptMessage>,
826    /// Result metadata (2025-06-18)
827    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
828    pub meta: Option<HashMap<String, serde_json::Value>>,
829}
830
831// Legacy type aliases for compatibility
832pub type PromptInfo = Prompt;
833pub type PromptResult = GetPromptResult;
834
835// ============================================================================
836// Sampling Types (2025-06-18)
837// ============================================================================
838
839/// A message in a sampling conversation (2025-06-18 with ContentBlock)
840#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
841pub struct SamplingMessage {
842    /// Role of the message
843    pub role: Role,
844    /// Content of the message (text, image, or audio only - no resource_link in sampling)
845    pub content: SamplingContent,
846}
847
848/// Content types allowed in sampling (subset of ContentBlock)
849#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
850#[serde(tag = "type")]
851pub enum SamplingContent {
852    /// Text content
853    #[serde(rename = "text")]
854    Text {
855        /// The text content
856        text: String,
857        /// Content annotations (2025-06-18)
858        #[serde(skip_serializing_if = "Option::is_none")]
859        annotations: Option<Annotations>,
860        /// Metadata field for future extensions
861        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
862        meta: Option<HashMap<String, serde_json::Value>>,
863    },
864    /// Image content
865    #[serde(rename = "image")]
866    Image {
867        /// Base64-encoded image data
868        data: String,
869        /// MIME type of the image
870        #[serde(rename = "mimeType")]
871        mime_type: String,
872        /// Content annotations (2025-06-18)
873        #[serde(skip_serializing_if = "Option::is_none")]
874        annotations: Option<Annotations>,
875        /// Metadata field for future extensions
876        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
877        meta: Option<HashMap<String, serde_json::Value>>,
878    },
879    /// Audio content (2025-06-18)
880    #[serde(rename = "audio")]
881    Audio {
882        /// Base64-encoded audio data
883        data: String,
884        /// MIME type of the audio
885        #[serde(rename = "mimeType")]
886        mime_type: String,
887        /// Content annotations (2025-06-18)
888        #[serde(skip_serializing_if = "Option::is_none")]
889        annotations: Option<Annotations>,
890        /// Metadata field for future extensions
891        #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
892        meta: Option<HashMap<String, serde_json::Value>>,
893    },
894}
895
896/// Model hint for model selection (2025-06-18)
897#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
898pub struct ModelHint {
899    /// A hint for a model name.
900    ///
901    /// The client SHOULD treat this as a substring of a model name; for example:
902    /// - `claude-3-5-sonnet` should match `claude-3-5-sonnet-20241022`
903    /// - `sonnet` should match `claude-3-5-sonnet-20241022`, `claude-3-sonnet-20240229`, etc.
904    /// - `claude` should match any Claude model
905    #[serde(skip_serializing_if = "Option::is_none")]
906    pub name: Option<String>,
907}
908
909/// Model preferences for sampling (2025-06-18 enhanced)
910#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
911pub struct ModelPreferences {
912    /// How much to prioritize cost when selecting a model
913    #[serde(rename = "costPriority", skip_serializing_if = "Option::is_none")]
914    pub cost_priority: Option<f64>,
915    /// How much to prioritize sampling speed (latency) when selecting a model
916    #[serde(rename = "speedPriority", skip_serializing_if = "Option::is_none")]
917    pub speed_priority: Option<f64>,
918    /// How much to prioritize intelligence and capabilities when selecting a model
919    #[serde(
920        rename = "intelligencePriority",
921        skip_serializing_if = "Option::is_none"
922    )]
923    pub intelligence_priority: Option<f64>,
924    /// Optional hints to use for model selection
925    #[serde(skip_serializing_if = "Option::is_none")]
926    pub hints: Option<Vec<ModelHint>>,
927}
928
929/// Result of sampling/createMessage (2025-06-18)
930#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
931pub struct CreateMessageResult {
932    /// Role of the generated message
933    pub role: Role,
934    /// Content of the generated message
935    pub content: SamplingContent,
936    /// Model used for generation
937    pub model: String,
938    /// Stop reason
939    #[serde(rename = "stopReason", skip_serializing_if = "Option::is_none")]
940    pub stop_reason: Option<StopReason>,
941    /// Result metadata (2025-06-18)
942    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
943    pub meta: Option<HashMap<String, serde_json::Value>>,
944}
945
946/// Reasons why sampling stopped
947#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
948#[serde(rename_all = "camelCase")]
949pub enum StopReason {
950    EndTurn,
951    StopSequence,
952    MaxTokens,
953    #[serde(untagged)]
954    Other(String),
955}
956
957// ============================================================================
958// Elicitation Types (2025-06-18 NEW)
959// ============================================================================
960
961/// Primitive schema definition for elicitation
962#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
963#[serde(tag = "type")]
964pub enum PrimitiveSchemaDefinition {
965    #[serde(rename = "string")]
966    String {
967        #[serde(skip_serializing_if = "Option::is_none")]
968        title: Option<String>,
969        #[serde(skip_serializing_if = "Option::is_none")]
970        description: Option<String>,
971        #[serde(rename = "minLength", skip_serializing_if = "Option::is_none")]
972        min_length: Option<u32>,
973        #[serde(rename = "maxLength", skip_serializing_if = "Option::is_none")]
974        max_length: Option<u32>,
975        #[serde(skip_serializing_if = "Option::is_none")]
976        format: Option<String>,
977        #[serde(rename = "enum", skip_serializing_if = "Option::is_none")]
978        enum_values: Option<Vec<String>>,
979        #[serde(rename = "enumNames", skip_serializing_if = "Option::is_none")]
980        enum_names: Option<Vec<String>>,
981    },
982    #[serde(rename = "number")]
983    Number {
984        #[serde(skip_serializing_if = "Option::is_none")]
985        title: Option<String>,
986        #[serde(skip_serializing_if = "Option::is_none")]
987        description: Option<String>,
988        #[serde(skip_serializing_if = "Option::is_none")]
989        minimum: Option<i32>,
990        #[serde(skip_serializing_if = "Option::is_none")]
991        maximum: Option<i32>,
992    },
993    #[serde(rename = "integer")]
994    Integer {
995        #[serde(skip_serializing_if = "Option::is_none")]
996        title: Option<String>,
997        #[serde(skip_serializing_if = "Option::is_none")]
998        description: Option<String>,
999        #[serde(skip_serializing_if = "Option::is_none")]
1000        minimum: Option<i32>,
1001        #[serde(skip_serializing_if = "Option::is_none")]
1002        maximum: Option<i32>,
1003    },
1004    #[serde(rename = "boolean")]
1005    Boolean {
1006        #[serde(skip_serializing_if = "Option::is_none")]
1007        title: Option<String>,
1008        #[serde(skip_serializing_if = "Option::is_none")]
1009        description: Option<String>,
1010        #[serde(skip_serializing_if = "Option::is_none")]
1011        default: Option<bool>,
1012    },
1013}
1014
1015/// Restricted schema for elicitation (only top-level properties allowed)
1016#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1017pub struct ElicitationSchema {
1018    /// Schema type (always "object")
1019    #[serde(rename = "type")]
1020    pub schema_type: String,
1021    /// Top-level properties
1022    pub properties: HashMap<String, PrimitiveSchemaDefinition>,
1023    /// Required properties
1024    #[serde(skip_serializing_if = "Option::is_none")]
1025    pub required: Option<Vec<String>>,
1026}
1027
1028/// Elicitation user action
1029#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1030#[serde(rename_all = "lowercase")]
1031pub enum ElicitationAction {
1032    /// User submitted the form/confirmed the action
1033    Accept,
1034    /// User explicitly declined the action
1035    Decline,
1036    /// User dismissed without making an explicit choice
1037    Cancel,
1038}
1039
1040// ============================================================================
1041// Logging Types (2025-06-18)
1042// ============================================================================
1043
1044/// Logging level enumeration (2025-06-18)
1045#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1046#[serde(rename_all = "lowercase")]
1047pub enum LoggingLevel {
1048    Debug,
1049    Info,
1050    Notice,
1051    Warning,
1052    Error,
1053    Critical,
1054    Alert,
1055    Emergency,
1056}
1057
1058// ============================================================================
1059// JSON-RPC Types (2025-03-26 with Batching)
1060// ============================================================================
1061
1062/// JSON-RPC request message
1063#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1064pub struct JsonRpcRequest {
1065    /// JSON-RPC version (always "2.0")
1066    pub jsonrpc: String,
1067    /// Request ID for correlation
1068    pub id: RequestId,
1069    /// Method name being called
1070    pub method: String,
1071    /// Method parameters
1072    #[serde(skip_serializing_if = "Option::is_none")]
1073    pub params: Option<serde_json::Value>,
1074}
1075
1076/// JSON-RPC response message
1077#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1078pub struct JsonRpcResponse {
1079    /// JSON-RPC version (always "2.0")
1080    pub jsonrpc: String,
1081    /// Request ID for correlation
1082    pub id: RequestId,
1083    /// Result of the method call
1084    #[serde(skip_serializing_if = "Option::is_none")]
1085    pub result: Option<serde_json::Value>,
1086}
1087
1088/// JSON-RPC error message
1089#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1090pub struct JsonRpcError {
1091    /// JSON-RPC version (always "2.0")
1092    pub jsonrpc: String,
1093    /// Request ID for correlation
1094    pub id: RequestId,
1095    /// Error information
1096    pub error: ErrorObject,
1097}
1098
1099/// Error object
1100#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1101pub struct ErrorObject {
1102    /// Error code
1103    pub code: i32,
1104    /// Error message
1105    pub message: String,
1106    /// Additional error data
1107    #[serde(skip_serializing_if = "Option::is_none")]
1108    pub data: Option<serde_json::Value>,
1109}
1110
1111/// JSON-RPC notification message
1112#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1113pub struct JsonRpcNotification {
1114    /// JSON-RPC version (always "2.0")
1115    pub jsonrpc: String,
1116    /// Method name being called
1117    pub method: String,
1118    /// Method parameters
1119    #[serde(skip_serializing_if = "Option::is_none")]
1120    pub params: Option<serde_json::Value>,
1121}
1122
1123/// Complete JSON-RPC message types (2025-06-18)
1124#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1125#[serde(untagged)]
1126pub enum JsonRpcMessage {
1127    Request(JsonRpcRequest),
1128    Response(JsonRpcResponse),
1129    Error(JsonRpcError),
1130    Notification(JsonRpcNotification),
1131}
1132
1133// ============================================================================
1134// Request/Response Metadata (2025-03-26 NEW)
1135// ============================================================================
1136
1137/// Base request with metadata support
1138#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1139pub struct Request {
1140    /// Method name
1141    pub method: String,
1142    /// Parameters with metadata support
1143    #[serde(skip_serializing_if = "Option::is_none")]
1144    pub params: Option<RequestParams>,
1145}
1146
1147/// Request parameters with metadata
1148#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1149pub struct RequestParams {
1150    /// Request metadata (2025-03-26 NEW)
1151    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1152    pub meta: Option<RequestMeta>,
1153    /// Additional parameters
1154    #[serde(flatten)]
1155    pub params: HashMap<String, serde_json::Value>,
1156}
1157
1158/// Request metadata
1159#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1160pub struct RequestMeta {
1161    /// Progress token for out-of-band progress notifications
1162    #[serde(rename = "progressToken", skip_serializing_if = "Option::is_none")]
1163    pub progress_token: Option<ProgressToken>,
1164}
1165
1166/// Base notification with metadata support
1167#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1168pub struct Notification {
1169    /// Method name
1170    pub method: String,
1171    /// Parameters with metadata support
1172    #[serde(skip_serializing_if = "Option::is_none")]
1173    pub params: Option<NotificationParams>,
1174}
1175
1176/// Notification parameters with metadata
1177#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1178pub struct NotificationParams {
1179    /// Notification metadata (2025-03-26 NEW)
1180    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1181    pub meta: Option<HashMap<String, serde_json::Value>>,
1182    /// Additional parameters
1183    #[serde(flatten)]
1184    pub params: HashMap<String, serde_json::Value>,
1185}
1186
1187// ============================================================================
1188// Pagination Support
1189// ============================================================================
1190
1191/// Base for paginated requests
1192#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1193pub struct PaginatedRequest {
1194    /// Cursor for pagination
1195    #[serde(skip_serializing_if = "Option::is_none")]
1196    pub cursor: Option<Cursor>,
1197}
1198
1199/// Base for paginated results
1200#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1201pub struct PaginatedResult {
1202    /// Cursor for next page
1203    #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
1204    pub next_cursor: Option<Cursor>,
1205}
1206
1207// ============================================================================
1208// Helper Constructors
1209// ============================================================================
1210
1211impl ContentBlock {
1212    /// Create text content
1213    pub fn text<S: Into<String>>(text: S) -> Self {
1214        Self::Text {
1215            text: text.into(),
1216            annotations: None,
1217            meta: None,
1218        }
1219    }
1220
1221    /// Create image content
1222    pub fn image<S: Into<String>>(data: S, mime_type: S) -> Self {
1223        Self::Image {
1224            data: data.into(),
1225            mime_type: mime_type.into(),
1226            annotations: None,
1227            meta: None,
1228        }
1229    }
1230
1231    /// Create audio content (2025-06-18)
1232    pub fn audio<S: Into<String>>(data: S, mime_type: S) -> Self {
1233        Self::Audio {
1234            data: data.into(),
1235            mime_type: mime_type.into(),
1236            annotations: None,
1237            meta: None,
1238        }
1239    }
1240
1241    /// Create resource link content (2025-06-18 NEW)
1242    pub fn resource_link<S: Into<String>>(uri: S, name: S) -> Self {
1243        Self::ResourceLink {
1244            uri: uri.into(),
1245            name: name.into(),
1246            description: None,
1247            mime_type: None,
1248            size: None,
1249            title: None,
1250            annotations: None,
1251            meta: None,
1252        }
1253    }
1254
1255    /// Create embedded resource content (2025-06-18)
1256    pub fn embedded_resource(resource: ResourceContents) -> Self {
1257        Self::Resource {
1258            resource,
1259            annotations: None,
1260            meta: None,
1261        }
1262    }
1263
1264    /// Create resource content (legacy compatibility)
1265    pub fn resource<S: Into<String>>(uri: S) -> Self {
1266        let uri_str = uri.into();
1267        Self::resource_link(uri_str.clone(), uri_str)
1268    }
1269}
1270
1271impl SamplingContent {
1272    /// Create text content for sampling
1273    pub fn text<S: Into<String>>(text: S) -> Self {
1274        Self::Text {
1275            text: text.into(),
1276            annotations: None,
1277            meta: None,
1278        }
1279    }
1280
1281    /// Create image content for sampling
1282    pub fn image<S: Into<String>>(data: S, mime_type: S) -> Self {
1283        Self::Image {
1284            data: data.into(),
1285            mime_type: mime_type.into(),
1286            annotations: None,
1287            meta: None,
1288        }
1289    }
1290
1291    /// Create audio content for sampling
1292    pub fn audio<S: Into<String>>(data: S, mime_type: S) -> Self {
1293        Self::Audio {
1294            data: data.into(),
1295            mime_type: mime_type.into(),
1296            annotations: None,
1297            meta: None,
1298        }
1299    }
1300}
1301
1302impl Annotations {
1303    /// Create new annotations
1304    pub fn new() -> Self {
1305        Self {
1306            audience: None,
1307            priority: None,
1308            last_modified: None,
1309            danger: None,
1310            destructive: None,
1311            read_only: None,
1312        }
1313    }
1314
1315    /// Set priority (0.0 = least important, 1.0 = most important)
1316    pub fn with_priority(mut self, priority: f64) -> Self {
1317        self.priority = Some(priority.clamp(0.0, 1.0));
1318        self
1319    }
1320
1321    /// Set audience
1322    pub fn for_audience(mut self, audience: Vec<Role>) -> Self {
1323        self.audience = Some(audience);
1324        self
1325    }
1326
1327    /// Set last modified timestamp (ISO 8601 format)
1328    pub fn with_last_modified<S: Into<String>>(mut self, timestamp: S) -> Self {
1329        self.last_modified = Some(timestamp.into());
1330        self
1331    }
1332
1333    /// Set audience (legacy compatibility)
1334    pub fn for_audience_legacy(self, _audience: Vec<AnnotationAudience>) -> Self {
1335        // Legacy compatibility - ignore audience in new API
1336        self
1337    }
1338
1339    /// Set danger level (legacy compatibility)
1340    pub fn with_danger_level(self, _level: DangerLevel) -> Self {
1341        // Legacy compatibility - ignore danger level in new API
1342        self
1343    }
1344
1345    /// Legacy danger field (always returns None for compatibility)
1346    pub fn danger(&self) -> Option<DangerLevel> {
1347        None
1348    }
1349
1350    /// Legacy audience field (always returns None for compatibility)
1351    pub fn audience(&self) -> Option<Vec<AnnotationAudience>> {
1352        None
1353    }
1354
1355    /// Set as read-only (legacy compatibility)
1356    pub fn read_only(mut self) -> Self {
1357        self.read_only = Some(true);
1358        self
1359    }
1360
1361    /// Set as destructive (legacy compatibility)
1362    pub fn destructive(mut self, level: DangerLevel) -> Self {
1363        self.destructive = Some(true);
1364        self.danger = Some(level);
1365        self
1366    }
1367}
1368
1369impl Tool {
1370    /// Create a new tool
1371    pub fn new<S: Into<String>>(name: S, description: S) -> Self {
1372        Self {
1373            name: name.into(),
1374            description: Some(description.into()),
1375            input_schema: ToolInputSchema {
1376                schema_type: "object".to_string(),
1377                properties: None,
1378                required: None,
1379                additional_properties: HashMap::new(),
1380            },
1381            annotations: None,
1382            title: None,
1383            meta: None,
1384        }
1385    }
1386
1387    /// Add title to the tool
1388    pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1389        self.title = Some(title.into());
1390        self
1391    }
1392
1393    /// Add annotations to the tool
1394    pub fn with_annotations(mut self, annotations: ToolAnnotations) -> Self {
1395        self.annotations = Some(annotations);
1396        self
1397    }
1398}
1399
1400impl Resource {
1401    /// Create a new resource
1402    pub fn new<S: Into<String>>(uri: S, name: S) -> Self {
1403        Self {
1404            uri: uri.into(),
1405            name: name.into(),
1406            description: None,
1407            mime_type: None,
1408            annotations: None,
1409            size: None,
1410            title: None,
1411            meta: None,
1412        }
1413    }
1414
1415    /// Create a resource from legacy format (name was optional)
1416    pub fn from_legacy<S: Into<String>>(uri: S, name: Option<S>) -> Self {
1417        Self {
1418            uri: uri.into(),
1419            name: name
1420                .map(|n| n.into())
1421                .unwrap_or_else(|| "Unnamed Resource".to_string()),
1422            description: None,
1423            mime_type: None,
1424            annotations: None,
1425            size: None,
1426            title: None,
1427            meta: None,
1428        }
1429    }
1430
1431    /// Add title to the resource
1432    pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1433        self.title = Some(title.into());
1434        self
1435    }
1436
1437    /// Add description to the resource
1438    pub fn with_description<S: Into<String>>(mut self, description: S) -> Self {
1439        self.description = Some(description.into());
1440        self
1441    }
1442}
1443
1444impl ResourceTemplate {
1445    /// Create a new resource template
1446    pub fn new<S: Into<String>>(uri_template: S, name: S) -> Self {
1447        Self {
1448            uri_template: uri_template.into(),
1449            name: name.into(),
1450            description: None,
1451            mime_type: None,
1452            annotations: None,
1453            title: None,
1454            meta: None,
1455        }
1456    }
1457
1458    /// Create a resource template from legacy format (name was optional)
1459    pub fn from_legacy<S: Into<String>>(uri_template: S, name: Option<S>) -> Self {
1460        Self {
1461            uri_template: uri_template.into(),
1462            name: name
1463                .map(|n| n.into())
1464                .unwrap_or_else(|| "Unnamed Template".to_string()),
1465            description: None,
1466            mime_type: None,
1467            annotations: None,
1468            title: None,
1469            meta: None,
1470        }
1471    }
1472
1473    /// Add title to the resource template
1474    pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1475        self.title = Some(title.into());
1476        self
1477    }
1478}
1479
1480impl Prompt {
1481    /// Create a new prompt
1482    pub fn new<S: Into<String>>(name: S) -> Self {
1483        Self {
1484            name: name.into(),
1485            description: None,
1486            arguments: None,
1487            title: None,
1488            meta: None,
1489        }
1490    }
1491
1492    /// Add title to the prompt
1493    pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1494        self.title = Some(title.into());
1495        self
1496    }
1497
1498    /// Add description to the prompt
1499    pub fn with_description<S: Into<String>>(mut self, description: S) -> Self {
1500        self.description = Some(description.into());
1501        self
1502    }
1503}
1504
1505impl PromptArgument {
1506    /// Create a new prompt argument
1507    pub fn new<S: Into<String>>(name: S) -> Self {
1508        Self {
1509            name: name.into(),
1510            description: None,
1511            required: None,
1512            title: None,
1513        }
1514    }
1515
1516    /// Add title to the prompt argument
1517    pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1518        self.title = Some(title.into());
1519        self
1520    }
1521
1522    /// Mark as required
1523    pub fn required(mut self, required: bool) -> Self {
1524        self.required = Some(required);
1525        self
1526    }
1527}
1528
1529impl JsonRpcRequest {
1530    /// Create a new JSON-RPC request
1531    pub fn new<T: Serialize>(
1532        id: RequestId,
1533        method: String,
1534        params: Option<T>,
1535    ) -> std::result::Result<Self, serde_json::Error> {
1536        let params = match params {
1537            Some(p) => Some(serde_json::to_value(p)?),
1538            None => None,
1539        };
1540
1541        Ok(Self {
1542            jsonrpc: JSONRPC_VERSION.to_string(),
1543            id,
1544            method,
1545            params,
1546        })
1547    }
1548}
1549
1550impl JsonRpcResponse {
1551    /// Create a successful JSON-RPC response
1552    pub fn success<T: Serialize>(
1553        id: RequestId,
1554        result: T,
1555    ) -> std::result::Result<Self, serde_json::Error> {
1556        Ok(Self {
1557            jsonrpc: JSONRPC_VERSION.to_string(),
1558            id,
1559            result: Some(serde_json::to_value(result)?),
1560        })
1561    }
1562}
1563
1564impl JsonRpcError {
1565    /// Create an error JSON-RPC response
1566    pub fn error(
1567        id: RequestId,
1568        code: i32,
1569        message: String,
1570        data: Option<serde_json::Value>,
1571    ) -> Self {
1572        Self {
1573            jsonrpc: JSONRPC_VERSION.to_string(),
1574            id,
1575            error: ErrorObject {
1576                code,
1577                message,
1578                data,
1579            },
1580        }
1581    }
1582}
1583
1584impl JsonRpcNotification {
1585    /// Create a new JSON-RPC notification
1586    pub fn new<T: Serialize>(
1587        method: String,
1588        params: Option<T>,
1589    ) -> std::result::Result<Self, serde_json::Error> {
1590        let params = match params {
1591            Some(p) => Some(serde_json::to_value(p)?),
1592            None => None,
1593        };
1594
1595        Ok(Self {
1596            jsonrpc: JSONRPC_VERSION.to_string(),
1597            method,
1598            params,
1599        })
1600    }
1601}
1602
1603impl SamplingMessage {
1604    /// Create a user text message
1605    pub fn user_text<S: Into<String>>(text: S) -> Self {
1606        Self {
1607            role: Role::User,
1608            content: SamplingContent::text(text),
1609        }
1610    }
1611
1612    /// Create an assistant text message
1613    pub fn assistant_text<S: Into<String>>(text: S) -> Self {
1614        Self {
1615            role: Role::Assistant,
1616            content: SamplingContent::text(text),
1617        }
1618    }
1619
1620    /// Create a user image message
1621    pub fn user_image<S: Into<String>>(data: S, mime_type: S) -> Self {
1622        Self {
1623            role: Role::User,
1624            content: SamplingContent::image(data, mime_type),
1625        }
1626    }
1627
1628    /// Create a user audio message
1629    pub fn user_audio<S: Into<String>>(data: S, mime_type: S) -> Self {
1630        Self {
1631            role: Role::User,
1632            content: SamplingContent::audio(data, mime_type),
1633        }
1634    }
1635}
1636
1637// ============================================================================
1638// Error Codes
1639// ============================================================================
1640
1641/// Standard JSON-RPC error codes
1642pub mod error_codes {
1643    /// Invalid JSON was received
1644    pub const PARSE_ERROR: i32 = -32700;
1645    /// The JSON sent is not a valid Request object
1646    pub const INVALID_REQUEST: i32 = -32600;
1647    /// The method does not exist / is not available
1648    pub const METHOD_NOT_FOUND: i32 = -32601;
1649    /// Invalid method parameter(s)
1650    pub const INVALID_PARAMS: i32 = -32602;
1651    /// Internal JSON-RPC error
1652    pub const INTERNAL_ERROR: i32 = -32603;
1653
1654    /// MCP-specific error codes
1655    pub const TOOL_NOT_FOUND: i32 = -32000;
1656    pub const RESOURCE_NOT_FOUND: i32 = -32001;
1657    pub const PROMPT_NOT_FOUND: i32 = -32002;
1658}
1659
1660#[cfg(test)]
1661mod tests {
1662    use super::*;
1663    use serde_json::json;
1664
1665    #[test]
1666    fn test_protocol_version() {
1667        assert_eq!(LATEST_PROTOCOL_VERSION, "2025-06-18");
1668        assert_eq!(JSONRPC_VERSION, "2.0");
1669    }
1670
1671    #[test]
1672    fn test_content_block_types() {
1673        // Test text content
1674        let text = ContentBlock::text("Hello, world!");
1675        let json = serde_json::to_value(&text).unwrap();
1676        assert_eq!(json["type"], "text");
1677        assert_eq!(json["text"], "Hello, world!");
1678
1679        // Test audio content (2025-06-18)
1680        let audio = ContentBlock::audio("base64data", "audio/wav");
1681        let json = serde_json::to_value(&audio).unwrap();
1682        assert_eq!(json["type"], "audio");
1683        assert_eq!(json["data"], "base64data");
1684        assert_eq!(json["mimeType"], "audio/wav");
1685
1686        // Test resource link content (new in 2025-06-18)
1687        let resource_link = ContentBlock::resource_link("file:///test.txt", "test file");
1688        let json = serde_json::to_value(&resource_link).unwrap();
1689        assert_eq!(json["type"], "resource_link");
1690        assert_eq!(json["uri"], "file:///test.txt");
1691        assert_eq!(json["name"], "test file");
1692    }
1693
1694    #[test]
1695    fn test_annotations() {
1696        let annotations = Annotations::new()
1697            .with_priority(0.8)
1698            .for_audience(vec![Role::User, Role::Assistant])
1699            .with_last_modified("2025-01-12T15:00:58Z");
1700
1701        assert_eq!(annotations.priority, Some(0.8));
1702        assert_eq!(
1703            annotations.audience,
1704            Some(vec![Role::User, Role::Assistant])
1705        );
1706        assert_eq!(
1707            annotations.last_modified,
1708            Some("2025-01-12T15:00:58Z".to_string())
1709        );
1710    }
1711
1712    #[test]
1713    fn test_tool_with_title() {
1714        let tool = Tool::new("file_reader", "Read files safely")
1715            .with_title("File Reader Tool")
1716            .with_annotations(ToolAnnotations::new().with_title("File Reader"));
1717
1718        assert_eq!(tool.name, "file_reader");
1719        assert_eq!(tool.title, Some("File Reader Tool".to_string()));
1720        assert!(tool.annotations.is_some());
1721        assert_eq!(
1722            tool.annotations.unwrap().title,
1723            Some("File Reader".to_string())
1724        );
1725    }
1726
1727    #[test]
1728    fn test_server_capabilities_2025_06_18() {
1729        let caps = ServerCapabilities {
1730            tools: Some(ToolsCapability {
1731                list_changed: Some(true),
1732            }),
1733            completions: Some(CompletionsCapability::default()),
1734            logging: Some(LoggingCapability::default()),
1735            experimental: Some(HashMap::new()),
1736            ..Default::default()
1737        };
1738
1739        let json = serde_json::to_value(&caps).unwrap();
1740        assert!(json["tools"]["listChanged"].as_bool().unwrap());
1741        assert!(json["completions"].is_object());
1742        assert!(json["logging"].is_object());
1743        assert!(json["experimental"].is_object());
1744    }
1745
1746    #[test]
1747    fn test_client_capabilities_with_elicitation() {
1748        let caps = ClientCapabilities {
1749            elicitation: Some(ElicitationCapability::default()),
1750            roots: Some(RootsCapability {
1751                list_changed: Some(true),
1752            }),
1753            ..Default::default()
1754        };
1755
1756        let json = serde_json::to_value(&caps).unwrap();
1757        assert!(json["elicitation"].is_object());
1758        assert!(json["roots"]["listChanged"].as_bool().unwrap());
1759    }
1760
1761    #[test]
1762    fn test_implementation_with_title() {
1763        let impl_info = Implementation::with_title("my-server", "1.0.0", "My Awesome Server");
1764
1765        assert_eq!(impl_info.name, "my-server");
1766        assert_eq!(impl_info.version, "1.0.0");
1767        assert_eq!(impl_info.title, Some("My Awesome Server".to_string()));
1768    }
1769
1770    #[test]
1771    fn test_model_preferences_enhanced() {
1772        let prefs = ModelPreferences {
1773            cost_priority: Some(0.3),
1774            speed_priority: Some(0.7),
1775            intelligence_priority: Some(0.9),
1776            hints: Some(vec![ModelHint {
1777                name: Some("claude".to_string()),
1778            }]),
1779        };
1780
1781        let json = serde_json::to_value(&prefs).unwrap();
1782        assert_eq!(json["costPriority"], 0.3);
1783        assert_eq!(json["speedPriority"], 0.7);
1784        assert_eq!(json["intelligencePriority"], 0.9);
1785        assert!(json["hints"].is_array());
1786    }
1787
1788    #[test]
1789    fn test_call_tool_result_with_structured_content() {
1790        let result = CallToolResult {
1791            content: vec![ContentBlock::text("Operation completed")],
1792            is_error: Some(false),
1793            structured_content: Some(json!({"status": "success", "count": 42})),
1794            meta: None,
1795        };
1796
1797        let json = serde_json::to_value(&result).unwrap();
1798        assert!(json["content"].is_array());
1799        assert_eq!(json["isError"], false);
1800        assert_eq!(json["structuredContent"]["status"], "success");
1801        assert_eq!(json["structuredContent"]["count"], 42);
1802    }
1803
1804    #[test]
1805    fn test_sampling_content_types() {
1806        // Test that SamplingContent doesn't include resource_link
1807        let text = SamplingContent::text("Hello");
1808        let image = SamplingContent::image("data", "image/png");
1809        let audio = SamplingContent::audio("data", "audio/wav");
1810
1811        let text_json = serde_json::to_value(&text).unwrap();
1812        let image_json = serde_json::to_value(&image).unwrap();
1813        let audio_json = serde_json::to_value(&audio).unwrap();
1814
1815        assert_eq!(text_json["type"], "text");
1816        assert_eq!(image_json["type"], "image");
1817        assert_eq!(audio_json["type"], "audio");
1818    }
1819}
1820
1821// ============================================================================
1822// Legacy/Compatibility Types for Tests
1823// ============================================================================
1824
1825/// Batch request type alias for compatibility
1826pub type JsonRpcBatchRequest = Vec<JsonRpcRequest>;
1827
1828/// Batch response type alias for compatibility  
1829pub type JsonRpcBatchResponse = Vec<JsonRpcResponse>;
1830
1831/// Request or notification union for compatibility
1832#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1833#[serde(untagged)]
1834pub enum JsonRpcRequestOrNotification {
1835    Request(JsonRpcRequest),
1836    Notification(JsonRpcNotification),
1837}
1838
1839/// Response or error union for compatibility
1840#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1841#[serde(untagged)]
1842pub enum JsonRpcResponseOrError {
1843    Response(JsonRpcResponse),
1844    Error(JsonRpcError),
1845}
1846
1847/// Annotation audience for content targeting (legacy)
1848#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1849pub enum AnnotationAudience {
1850    User,
1851    Developer,
1852    System,
1853}
1854
1855/// Danger level for tool safety annotations (legacy)
1856#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1857pub enum DangerLevel {
1858    Safe,
1859    Low,
1860    Medium,
1861    High,
1862}