Skip to main content

tower_mcp_types/
protocol.rs

1//! MCP protocol types based on JSON-RPC 2.0
2//!
3//! These types follow the MCP specification (2025-11-25):
4//! <https://modelcontextprotocol.io/specification/2025-11-25>
5
6use std::collections::HashMap;
7
8use serde::de::DeserializeOwned;
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11
12use crate::error::JsonRpcError;
13
14/// The JSON-RPC version. MUST be "2.0".
15pub const JSONRPC_VERSION: &str = "2.0";
16
17/// The latest supported MCP protocol version.
18pub const LATEST_PROTOCOL_VERSION: &str = "2025-11-25";
19
20/// All supported MCP protocol versions (newest first).
21///
22/// During initialization, the server negotiates the protocol version with the
23/// client. The server picks the newest version that both sides support.
24/// If no common version exists, the connection is rejected.
25///
26/// ```rust
27/// use tower_mcp_types::protocol::{LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS};
28///
29/// assert_eq!(LATEST_PROTOCOL_VERSION, "2025-11-25");
30/// assert!(SUPPORTED_PROTOCOL_VERSIONS.contains(&"2025-03-26"));
31/// ```
32pub const SUPPORTED_PROTOCOL_VERSIONS: &[&str] = &["2025-11-25", "2025-03-26"];
33
34/// JSON-RPC 2.0 request.
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct JsonRpcRequest {
37    /// JSON-RPC version, must be "2.0".
38    pub jsonrpc: String,
39    /// Request identifier.
40    pub id: RequestId,
41    /// Method name to invoke.
42    pub method: String,
43    /// Optional parameters for the method.
44    #[serde(default, skip_serializing_if = "Option::is_none")]
45    pub params: Option<Value>,
46}
47
48impl JsonRpcRequest {
49    /// Create a new JSON-RPC request.
50    pub fn new(id: impl Into<RequestId>, method: impl Into<String>) -> Self {
51        Self {
52            jsonrpc: JSONRPC_VERSION.to_string(),
53            id: id.into(),
54            method: method.into(),
55            params: None,
56        }
57    }
58
59    /// Add parameters to the request.
60    pub fn with_params(mut self, params: Value) -> Self {
61        self.params = Some(params);
62        self
63    }
64
65    /// Validate that this request conforms to JSON-RPC 2.0.
66    /// Returns an error if the jsonrpc version is not "2.0".
67    pub fn validate(&self) -> Result<(), JsonRpcError> {
68        if self.jsonrpc != JSONRPC_VERSION {
69            return Err(JsonRpcError::invalid_request(format!(
70                "Invalid JSON-RPC version: expected '{}', got '{}'",
71                JSONRPC_VERSION, self.jsonrpc
72            )));
73        }
74        Ok(())
75    }
76}
77
78/// JSON-RPC 2.0 success response.
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct JsonRpcResultResponse {
81    /// JSON-RPC version, always "2.0".
82    pub jsonrpc: String,
83    /// Request identifier (matches the request).
84    pub id: RequestId,
85    /// The result value.
86    pub result: Value,
87}
88
89/// JSON-RPC 2.0 error response.
90#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct JsonRpcErrorResponse {
92    /// JSON-RPC version, always "2.0".
93    pub jsonrpc: String,
94    /// Request identifier (may be null for parse errors).
95    #[serde(skip_serializing_if = "Option::is_none")]
96    pub id: Option<RequestId>,
97    /// The error details.
98    pub error: JsonRpcError,
99}
100
101/// JSON-RPC 2.0 response (either success or error).
102#[derive(Debug, Clone, Serialize, Deserialize)]
103#[serde(untagged)]
104#[non_exhaustive]
105pub enum JsonRpcResponse {
106    /// Successful response with result.
107    Result(JsonRpcResultResponse),
108    /// Error response.
109    Error(JsonRpcErrorResponse),
110}
111
112impl JsonRpcResponse {
113    /// Create a success response.
114    pub fn result(id: RequestId, result: Value) -> Self {
115        Self::Result(JsonRpcResultResponse {
116            jsonrpc: JSONRPC_VERSION.to_string(),
117            id,
118            result,
119        })
120    }
121
122    /// Create an error response.
123    pub fn error(id: Option<RequestId>, error: JsonRpcError) -> Self {
124        Self::Error(JsonRpcErrorResponse {
125            jsonrpc: JSONRPC_VERSION.to_string(),
126            id,
127            error,
128        })
129    }
130}
131
132/// JSON-RPC 2.0 message - can be a single request or a batch
133#[derive(Debug, Clone, Serialize, Deserialize)]
134#[serde(untagged)]
135#[non_exhaustive]
136pub enum JsonRpcMessage {
137    /// A single request
138    Single(JsonRpcRequest),
139    /// A batch of requests
140    Batch(Vec<JsonRpcRequest>),
141}
142
143impl JsonRpcMessage {
144    /// Returns true if this is a batch message
145    pub fn is_batch(&self) -> bool {
146        matches!(self, JsonRpcMessage::Batch(_))
147    }
148
149    /// Returns the number of requests in this message
150    pub fn len(&self) -> usize {
151        match self {
152            JsonRpcMessage::Single(_) => 1,
153            JsonRpcMessage::Batch(batch) => batch.len(),
154        }
155    }
156
157    /// Returns true if this message contains no requests
158    pub fn is_empty(&self) -> bool {
159        self.len() == 0
160    }
161}
162
163/// JSON-RPC 2.0 response message - can be a single response or a batch
164#[derive(Debug, Clone, Serialize, Deserialize)]
165#[serde(untagged)]
166#[non_exhaustive]
167pub enum JsonRpcResponseMessage {
168    /// A single response
169    Single(JsonRpcResponse),
170    /// A batch of responses
171    Batch(Vec<JsonRpcResponse>),
172}
173
174impl JsonRpcResponseMessage {
175    /// Returns true if this is a batch response
176    pub fn is_batch(&self) -> bool {
177        matches!(self, JsonRpcResponseMessage::Batch(_))
178    }
179}
180
181/// JSON-RPC 2.0 notification (no response expected)
182#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct JsonRpcNotification {
184    pub jsonrpc: String,
185    pub method: String,
186    #[serde(default, skip_serializing_if = "Option::is_none")]
187    pub params: Option<Value>,
188}
189
190impl JsonRpcNotification {
191    pub fn new(method: impl Into<String>) -> Self {
192        Self {
193            jsonrpc: JSONRPC_VERSION.to_string(),
194            method: method.into(),
195            params: None,
196        }
197    }
198
199    pub fn with_params(mut self, params: Value) -> Self {
200        self.params = Some(params);
201        self
202    }
203}
204
205/// MCP notification methods
206pub mod notifications {
207    /// Sent by client after receiving initialize response
208    pub const INITIALIZED: &str = "notifications/initialized";
209    /// Sent when a request is cancelled
210    pub const CANCELLED: &str = "notifications/cancelled";
211    /// Progress updates for long-running operations
212    pub const PROGRESS: &str = "notifications/progress";
213    /// Tool list has changed
214    pub const TOOLS_LIST_CHANGED: &str = "notifications/tools/list_changed";
215    /// Resource list has changed
216    pub const RESOURCES_LIST_CHANGED: &str = "notifications/resources/list_changed";
217    /// Specific resource has been updated
218    pub const RESOURCE_UPDATED: &str = "notifications/resources/updated";
219    /// Prompt list has changed
220    pub const PROMPTS_LIST_CHANGED: &str = "notifications/prompts/list_changed";
221    /// Roots list has changed (client to server)
222    pub const ROOTS_LIST_CHANGED: &str = "notifications/roots/list_changed";
223    /// Log message notification
224    pub const MESSAGE: &str = "notifications/message";
225    /// Task status changed
226    pub const TASK_STATUS_CHANGED: &str = "notifications/tasks/status";
227    /// Elicitation completed (for URL-based elicitation)
228    pub const ELICITATION_COMPLETE: &str = "notifications/elicitation/complete";
229}
230
231/// Log severity levels following RFC 5424 (syslog)
232///
233/// Levels are ordered from most severe (emergency) to least severe (debug).
234#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
235#[serde(rename_all = "lowercase")]
236#[non_exhaustive]
237pub enum LogLevel {
238    /// System is unusable
239    Emergency,
240    /// Action must be taken immediately
241    Alert,
242    /// Critical conditions
243    Critical,
244    /// Error conditions
245    Error,
246    /// Warning conditions
247    Warning,
248    /// Normal but significant events
249    Notice,
250    /// General informational messages
251    #[default]
252    Info,
253    /// Detailed debugging information
254    Debug,
255}
256
257impl std::fmt::Display for LogLevel {
258    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259        match self {
260            LogLevel::Emergency => write!(f, "emergency"),
261            LogLevel::Alert => write!(f, "alert"),
262            LogLevel::Critical => write!(f, "critical"),
263            LogLevel::Error => write!(f, "error"),
264            LogLevel::Warning => write!(f, "warning"),
265            LogLevel::Notice => write!(f, "notice"),
266            LogLevel::Info => write!(f, "info"),
267            LogLevel::Debug => write!(f, "debug"),
268        }
269    }
270}
271
272/// Parameters for logging message notification
273#[derive(Debug, Clone, Serialize, Deserialize)]
274pub struct LoggingMessageParams {
275    /// Severity level of the message
276    pub level: LogLevel,
277    /// Optional logger name (e.g., "database", "auth", "tools")
278    #[serde(skip_serializing_if = "Option::is_none")]
279    pub logger: Option<String>,
280    /// Structured data to be logged
281    #[serde(default)]
282    pub data: Value,
283    /// Optional protocol-level metadata
284    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
285    pub meta: Option<Value>,
286}
287
288impl LoggingMessageParams {
289    /// Create a new logging message with the given level and data
290    pub fn new(level: LogLevel, data: impl Into<Value>) -> Self {
291        Self {
292            level,
293            logger: None,
294            data: data.into(),
295            meta: None,
296        }
297    }
298
299    /// Set the logger name
300    pub fn with_logger(mut self, logger: impl Into<String>) -> Self {
301        self.logger = Some(logger.into());
302        self
303    }
304
305    /// Set the structured data
306    pub fn with_data(mut self, data: impl Into<Value>) -> Self {
307        self.data = data.into();
308        self
309    }
310}
311
312/// Parameters for setting log level
313#[derive(Debug, Clone, Deserialize)]
314pub struct SetLogLevelParams {
315    /// Minimum log level to receive
316    pub level: LogLevel,
317    /// Optional protocol-level metadata
318    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
319    pub meta: Option<RequestMeta>,
320}
321
322/// Request ID - can be string or number per JSON-RPC spec
323#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
324#[serde(untagged)]
325#[non_exhaustive]
326pub enum RequestId {
327    String(String),
328    Number(i64),
329}
330
331impl From<String> for RequestId {
332    fn from(s: String) -> Self {
333        RequestId::String(s)
334    }
335}
336
337impl From<&str> for RequestId {
338    fn from(s: &str) -> Self {
339        RequestId::String(s.to_string())
340    }
341}
342
343impl From<i64> for RequestId {
344    fn from(n: i64) -> Self {
345        RequestId::Number(n)
346    }
347}
348
349impl From<i32> for RequestId {
350    fn from(n: i32) -> Self {
351        RequestId::Number(n as i64)
352    }
353}
354
355// =============================================================================
356// MCP-specific request/response types
357// =============================================================================
358
359/// High-level MCP request (parsed from JSON-RPC)
360#[derive(Debug, Clone)]
361#[non_exhaustive]
362pub enum McpRequest {
363    /// Initialize session
364    Initialize(InitializeParams),
365    /// List available tools
366    ListTools(ListToolsParams),
367    /// Call a tool
368    CallTool(CallToolParams),
369    /// List available resources
370    ListResources(ListResourcesParams),
371    /// List resource templates
372    ListResourceTemplates(ListResourceTemplatesParams),
373    /// Read a resource
374    ReadResource(ReadResourceParams),
375    /// Subscribe to resource updates
376    SubscribeResource(SubscribeResourceParams),
377    /// Unsubscribe from resource updates
378    UnsubscribeResource(UnsubscribeResourceParams),
379    /// List available prompts
380    ListPrompts(ListPromptsParams),
381    /// Get a prompt
382    GetPrompt(GetPromptParams),
383    /// List tasks
384    ListTasks(ListTasksParams),
385    /// Get task info
386    GetTaskInfo(GetTaskInfoParams),
387    /// Get task result
388    GetTaskResult(GetTaskResultParams),
389    /// Cancel a task
390    CancelTask(CancelTaskParams),
391    /// Ping (keepalive)
392    Ping,
393    /// Set logging level
394    SetLoggingLevel(SetLogLevelParams),
395    /// Request completion suggestions
396    Complete(CompleteParams),
397    /// Unknown method
398    Unknown {
399        method: String,
400        params: Option<Value>,
401    },
402}
403
404impl McpRequest {
405    /// Get the method name for this request
406    pub fn method_name(&self) -> &str {
407        match self {
408            McpRequest::Initialize(_) => "initialize",
409            McpRequest::ListTools(_) => "tools/list",
410            McpRequest::CallTool(_) => "tools/call",
411            McpRequest::ListResources(_) => "resources/list",
412            McpRequest::ListResourceTemplates(_) => "resources/templates/list",
413            McpRequest::ReadResource(_) => "resources/read",
414            McpRequest::SubscribeResource(_) => "resources/subscribe",
415            McpRequest::UnsubscribeResource(_) => "resources/unsubscribe",
416            McpRequest::ListPrompts(_) => "prompts/list",
417            McpRequest::GetPrompt(_) => "prompts/get",
418            McpRequest::ListTasks(_) => "tasks/list",
419            McpRequest::GetTaskInfo(_) => "tasks/get",
420            McpRequest::GetTaskResult(_) => "tasks/result",
421            McpRequest::CancelTask(_) => "tasks/cancel",
422            McpRequest::Ping => "ping",
423            McpRequest::SetLoggingLevel(_) => "logging/setLevel",
424            McpRequest::Complete(_) => "completion/complete",
425            McpRequest::Unknown { method, .. } => method,
426        }
427    }
428}
429
430/// High-level MCP notification (parsed from JSON-RPC)
431#[derive(Debug, Clone)]
432#[non_exhaustive]
433pub enum McpNotification {
434    /// Client has completed initialization
435    Initialized,
436    /// Request cancellation
437    Cancelled(CancelledParams),
438    /// Progress update
439    Progress(ProgressParams),
440    /// Roots list has changed (client to server)
441    RootsListChanged,
442    /// Unknown notification
443    Unknown {
444        method: String,
445        params: Option<Value>,
446    },
447}
448
449/// Parameters for cancellation notification
450#[derive(Debug, Clone, Serialize, Deserialize)]
451#[serde(rename_all = "camelCase")]
452pub struct CancelledParams {
453    /// The ID of the request to cancel (required for non-task cancellations)
454    #[serde(default, skip_serializing_if = "Option::is_none")]
455    pub request_id: Option<RequestId>,
456    /// Optional reason for cancellation
457    #[serde(skip_serializing_if = "Option::is_none")]
458    pub reason: Option<String>,
459    /// Optional protocol-level metadata
460    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
461    pub meta: Option<Value>,
462}
463
464/// Parameters for progress notification
465#[derive(Debug, Clone, Serialize, Deserialize)]
466#[serde(rename_all = "camelCase")]
467pub struct ProgressParams {
468    /// The progress token from the original request
469    pub progress_token: ProgressToken,
470    /// Current progress value (must increase with each notification)
471    pub progress: f64,
472    /// Total expected value (if known)
473    #[serde(skip_serializing_if = "Option::is_none")]
474    pub total: Option<f64>,
475    /// Human-readable progress message
476    #[serde(skip_serializing_if = "Option::is_none")]
477    pub message: Option<String>,
478    /// Optional protocol-level metadata
479    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
480    pub meta: Option<Value>,
481}
482
483/// Progress token - can be string or number
484#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
485#[serde(untagged)]
486#[non_exhaustive]
487pub enum ProgressToken {
488    String(String),
489    Number(i64),
490}
491
492/// Request metadata that can include progress token
493#[derive(Debug, Clone, Default, Serialize, Deserialize)]
494#[serde(rename_all = "camelCase")]
495pub struct RequestMeta {
496    /// Progress token for receiving progress notifications
497    #[serde(skip_serializing_if = "Option::is_none")]
498    pub progress_token: Option<ProgressToken>,
499}
500
501/// High-level MCP response
502#[derive(Debug, Clone, Serialize, Deserialize)]
503#[serde(untagged)]
504#[non_exhaustive]
505pub enum McpResponse {
506    Initialize(InitializeResult),
507    ListTools(ListToolsResult),
508    CallTool(CallToolResult),
509    ListResources(ListResourcesResult),
510    ListResourceTemplates(ListResourceTemplatesResult),
511    ReadResource(ReadResourceResult),
512    SubscribeResource(EmptyResult),
513    UnsubscribeResource(EmptyResult),
514    ListPrompts(ListPromptsResult),
515    GetPrompt(GetPromptResult),
516    CreateTask(CreateTaskResult),
517    ListTasks(ListTasksResult),
518    GetTaskInfo(TaskObject),
519    GetTaskResult(CallToolResult),
520    CancelTask(TaskObject),
521    SetLoggingLevel(EmptyResult),
522    Complete(CompleteResult),
523    Pong(EmptyResult),
524    Empty(EmptyResult),
525    /// Raw JSON value for experimental/extension methods.
526    Raw(Value),
527}
528
529// =============================================================================
530// Initialize
531// =============================================================================
532
533#[derive(Debug, Clone, Serialize, Deserialize)]
534#[serde(rename_all = "camelCase")]
535pub struct InitializeParams {
536    pub protocol_version: String,
537    pub capabilities: ClientCapabilities,
538    pub client_info: Implementation,
539    /// Optional protocol-level metadata
540    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
541    pub meta: Option<Value>,
542}
543
544#[derive(Debug, Clone, Default, Serialize, Deserialize)]
545pub struct ClientCapabilities {
546    #[serde(default, skip_serializing_if = "Option::is_none")]
547    pub roots: Option<RootsCapability>,
548    #[serde(default, skip_serializing_if = "Option::is_none")]
549    pub sampling: Option<SamplingCapability>,
550    #[serde(default, skip_serializing_if = "Option::is_none")]
551    pub elicitation: Option<ElicitationCapability>,
552    #[serde(default, skip_serializing_if = "Option::is_none")]
553    pub tasks: Option<ClientTasksCapability>,
554    /// Experimental, non-standard capabilities
555    #[serde(default, skip_serializing_if = "Option::is_none")]
556    pub experimental: Option<HashMap<String, serde_json::Value>>,
557    /// Declared extension support (SEP-1724/SEP-2133)
558    #[serde(default, skip_serializing_if = "Option::is_none")]
559    pub extensions: Option<HashMap<String, serde_json::Value>>,
560}
561
562/// Client capability for elicitation (requesting user input)
563#[derive(Debug, Clone, Default, Serialize, Deserialize)]
564pub struct ElicitationCapability {
565    /// Support for form-based elicitation
566    #[serde(default, skip_serializing_if = "Option::is_none")]
567    pub form: Option<ElicitationFormCapability>,
568    /// Support for URL-based elicitation
569    #[serde(default, skip_serializing_if = "Option::is_none")]
570    pub url: Option<ElicitationUrlCapability>,
571}
572
573/// Marker for form-based elicitation support
574#[derive(Debug, Clone, Default, Serialize, Deserialize)]
575pub struct ElicitationFormCapability {}
576
577/// Marker for URL-based elicitation support
578#[derive(Debug, Clone, Default, Serialize, Deserialize)]
579pub struct ElicitationUrlCapability {}
580
581/// Client capability for async task management
582#[derive(Debug, Clone, Default, Serialize, Deserialize)]
583#[serde(rename_all = "camelCase")]
584pub struct ClientTasksCapability {
585    /// Support for listing tasks
586    #[serde(default, skip_serializing_if = "Option::is_none")]
587    pub list: Option<ClientTasksListCapability>,
588    /// Support for cancelling tasks
589    #[serde(default, skip_serializing_if = "Option::is_none")]
590    pub cancel: Option<ClientTasksCancelCapability>,
591    /// Which request types support task-augmented requests
592    #[serde(default, skip_serializing_if = "Option::is_none")]
593    pub requests: Option<ClientTasksRequestsCapability>,
594}
595
596/// Marker capability for client tasks/list support
597#[derive(Debug, Clone, Default, Serialize, Deserialize)]
598pub struct ClientTasksListCapability {}
599
600/// Marker capability for client tasks/cancel support
601#[derive(Debug, Clone, Default, Serialize, Deserialize)]
602pub struct ClientTasksCancelCapability {}
603
604/// Capability declaring which request types support task-augmented requests on the client
605#[derive(Debug, Clone, Default, Serialize, Deserialize)]
606#[serde(rename_all = "camelCase")]
607pub struct ClientTasksRequestsCapability {
608    /// Task support for sampling-related requests
609    #[serde(default, skip_serializing_if = "Option::is_none")]
610    pub sampling: Option<ClientTasksSamplingCapability>,
611    /// Task support for elicitation-related requests
612    #[serde(default, skip_serializing_if = "Option::is_none")]
613    pub elicitation: Option<ClientTasksElicitationCapability>,
614}
615
616/// Nested capability for task-augmented sampling requests
617#[derive(Debug, Clone, Default, Serialize, Deserialize)]
618#[serde(rename_all = "camelCase")]
619pub struct ClientTasksSamplingCapability {
620    /// Whether the client supports task-augmented sampling/createMessage requests
621    #[serde(default, skip_serializing_if = "Option::is_none")]
622    pub create_message: Option<ClientTasksSamplingCreateMessageCapability>,
623}
624
625/// Marker capability for task-augmented sampling/createMessage support
626#[derive(Debug, Clone, Default, Serialize, Deserialize)]
627pub struct ClientTasksSamplingCreateMessageCapability {}
628
629/// Nested capability for task-augmented elicitation requests
630#[derive(Debug, Clone, Default, Serialize, Deserialize)]
631#[serde(rename_all = "camelCase")]
632pub struct ClientTasksElicitationCapability {
633    /// Whether the client supports task-augmented elicitation/create requests
634    #[serde(default, skip_serializing_if = "Option::is_none")]
635    pub create: Option<ClientTasksElicitationCreateCapability>,
636}
637
638/// Marker capability for task-augmented elicitation/create support
639#[derive(Debug, Clone, Default, Serialize, Deserialize)]
640pub struct ClientTasksElicitationCreateCapability {}
641
642/// Client capability for roots (filesystem access)
643/// Capabilities related to filesystem roots.
644///
645/// When `list_changed` is `true`, the client supports sending
646/// `notifications/roots/list_changed` to inform the server that the
647/// available roots have been modified. Servers should re-request the
648/// roots list when they receive this notification.
649///
650/// # Example
651///
652/// ```rust
653/// use tower_mcp_types::protocol::RootsCapability;
654///
655/// // Client advertising roots with change notification support
656/// let cap = RootsCapability { list_changed: true };
657/// assert!(cap.list_changed);
658///
659/// // The notification method is defined as a constant:
660/// assert_eq!(
661///     tower_mcp_types::protocol::notifications::ROOTS_LIST_CHANGED,
662///     "notifications/roots/list_changed"
663/// );
664/// ```
665#[derive(Debug, Clone, Default, Serialize, Deserialize)]
666#[serde(rename_all = "camelCase")]
667pub struct RootsCapability {
668    /// Whether the client supports roots list changed notifications
669    #[serde(default)]
670    pub list_changed: bool,
671}
672
673/// Represents a root directory or file that the server can operate on.
674///
675/// Roots allow clients to expose filesystem roots to servers, enabling:
676/// - Scoped file access
677/// - Workspace awareness
678/// - Security boundaries
679///
680/// # Example
681///
682/// ```rust
683/// use tower_mcp_types::protocol::Root;
684///
685/// let root = Root::new("file:///home/user/project");
686/// assert_eq!(root.uri, "file:///home/user/project");
687/// assert!(root.name.is_none());
688///
689/// let root = Root::with_name("file:///workspace", "My Project");
690/// assert_eq!(root.name.unwrap(), "My Project");
691/// ```
692#[derive(Debug, Clone, Serialize, Deserialize)]
693pub struct Root {
694    /// The URI identifying the root. Must start with `file://` for now.
695    pub uri: String,
696    /// Optional human-readable name for the root
697    #[serde(default, skip_serializing_if = "Option::is_none")]
698    pub name: Option<String>,
699    /// Optional protocol-level metadata
700    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
701    pub meta: Option<Value>,
702}
703
704impl Root {
705    /// Create a new root with just a URI
706    pub fn new(uri: impl Into<String>) -> Self {
707        Self {
708            uri: uri.into(),
709            name: None,
710            meta: None,
711        }
712    }
713
714    /// Create a new root with a URI and name
715    pub fn with_name(uri: impl Into<String>, name: impl Into<String>) -> Self {
716        Self {
717            uri: uri.into(),
718            name: Some(name.into()),
719            meta: None,
720        }
721    }
722}
723
724/// Result of a roots/list request from the server.
725///
726/// Contains the list of roots the client has exposed. Clients notify
727/// the server of root changes via `notifications/roots/list_changed`.
728///
729/// Parameters for roots/list request (server to client)
730#[derive(Debug, Clone, Default, Serialize, Deserialize)]
731pub struct ListRootsParams {
732    /// Optional metadata
733    #[serde(default, rename = "_meta", skip_serializing_if = "Option::is_none")]
734    pub meta: Option<RequestMeta>,
735}
736
737/// Result of roots/list request
738#[derive(Debug, Clone, Serialize, Deserialize)]
739pub struct ListRootsResult {
740    /// The list of roots available to the server
741    pub roots: Vec<Root>,
742    /// Optional protocol-level metadata
743    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
744    pub meta: Option<Value>,
745}
746
747#[derive(Debug, Clone, Default, Serialize, Deserialize)]
748pub struct SamplingCapability {
749    /// Support for tool use within sampling
750    #[serde(default, skip_serializing_if = "Option::is_none")]
751    pub tools: Option<SamplingToolsCapability>,
752    /// Support for context inclusion within sampling
753    #[serde(default, skip_serializing_if = "Option::is_none")]
754    pub context: Option<SamplingContextCapability>,
755}
756
757/// Marker capability for tool use within sampling
758#[derive(Debug, Clone, Default, Serialize, Deserialize)]
759pub struct SamplingToolsCapability {}
760
761/// Marker capability for context inclusion within sampling
762#[derive(Debug, Clone, Default, Serialize, Deserialize)]
763pub struct SamplingContextCapability {}
764
765/// Server capability for providing completions
766#[derive(Debug, Clone, Default, Serialize, Deserialize)]
767pub struct CompletionsCapability {}
768
769// =============================================================================
770// Completion Types
771// =============================================================================
772
773/// Reference to a prompt for completion
774#[derive(Debug, Clone, Serialize, Deserialize)]
775pub struct PromptReference {
776    /// Type discriminator, always "ref/prompt"
777    #[serde(rename = "type")]
778    pub ref_type: String,
779    /// The name of the prompt or prompt template
780    pub name: String,
781}
782
783impl PromptReference {
784    /// Create a new prompt reference
785    pub fn new(name: impl Into<String>) -> Self {
786        Self {
787            ref_type: "ref/prompt".to_string(),
788            name: name.into(),
789        }
790    }
791}
792
793/// Reference to a resource for completion
794#[derive(Debug, Clone, Serialize, Deserialize)]
795pub struct ResourceReference {
796    /// Type discriminator, always "ref/resource"
797    #[serde(rename = "type")]
798    pub ref_type: String,
799    /// The URI or URI template of the resource
800    pub uri: String,
801}
802
803impl ResourceReference {
804    /// Create a new resource reference
805    pub fn new(uri: impl Into<String>) -> Self {
806        Self {
807            ref_type: "ref/resource".to_string(),
808            uri: uri.into(),
809        }
810    }
811}
812
813/// Reference for completion - either a prompt or resource reference
814#[derive(Debug, Clone, Serialize, Deserialize)]
815#[serde(tag = "type")]
816#[non_exhaustive]
817pub enum CompletionReference {
818    /// Reference to a prompt
819    #[serde(rename = "ref/prompt")]
820    Prompt {
821        /// The name of the prompt
822        name: String,
823    },
824    /// Reference to a resource
825    #[serde(rename = "ref/resource")]
826    Resource {
827        /// The URI of the resource
828        uri: String,
829    },
830}
831
832impl CompletionReference {
833    /// Create a prompt reference
834    pub fn prompt(name: impl Into<String>) -> Self {
835        Self::Prompt { name: name.into() }
836    }
837
838    /// Create a resource reference
839    pub fn resource(uri: impl Into<String>) -> Self {
840        Self::Resource { uri: uri.into() }
841    }
842}
843
844/// Argument being completed
845#[derive(Debug, Clone, Serialize, Deserialize)]
846pub struct CompletionArgument {
847    /// The name of the argument
848    pub name: String,
849    /// The current value of the argument (partial input)
850    pub value: String,
851}
852
853impl CompletionArgument {
854    /// Create a new completion argument
855    pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
856        Self {
857            name: name.into(),
858            value: value.into(),
859        }
860    }
861}
862
863/// Parameters for completion/complete request
864#[derive(Debug, Clone, Serialize, Deserialize)]
865#[serde(rename_all = "camelCase")]
866pub struct CompleteParams {
867    /// The reference (prompt or resource) being completed
868    #[serde(rename = "ref")]
869    pub reference: CompletionReference,
870    /// The argument being completed
871    pub argument: CompletionArgument,
872    /// Additional context for completion, such as previously resolved argument values
873    #[serde(default, skip_serializing_if = "Option::is_none")]
874    pub context: Option<CompletionContext>,
875    /// Optional protocol-level metadata
876    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
877    pub meta: Option<Value>,
878}
879
880/// Context provided alongside a completion request
881#[derive(Debug, Clone, Serialize, Deserialize)]
882#[serde(rename_all = "camelCase")]
883pub struct CompletionContext {
884    /// Previously resolved argument name-value pairs
885    #[serde(default, skip_serializing_if = "Option::is_none")]
886    pub arguments: Option<std::collections::HashMap<String, String>>,
887}
888
889/// Completion suggestions
890#[derive(Debug, Clone, Serialize, Deserialize)]
891#[serde(rename_all = "camelCase")]
892pub struct Completion {
893    /// Suggested completion values
894    pub values: Vec<String>,
895    /// Total number of available completions (if known)
896    #[serde(default, skip_serializing_if = "Option::is_none")]
897    pub total: Option<u32>,
898    /// Whether there are more completions available
899    #[serde(default, skip_serializing_if = "Option::is_none")]
900    pub has_more: Option<bool>,
901}
902
903impl Completion {
904    /// Create a new completion result
905    pub fn new(values: Vec<String>) -> Self {
906        Self {
907            values,
908            total: None,
909            has_more: None,
910        }
911    }
912
913    /// Create a completion result with pagination info
914    pub fn with_pagination(values: Vec<String>, total: u32, has_more: bool) -> Self {
915        Self {
916            values,
917            total: Some(total),
918            has_more: Some(has_more),
919        }
920    }
921}
922
923/// Result of completion/complete request
924#[derive(Debug, Clone, Serialize, Deserialize)]
925pub struct CompleteResult {
926    /// The completion suggestions
927    pub completion: Completion,
928    /// Optional protocol-level metadata
929    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
930    pub meta: Option<Value>,
931}
932
933impl CompleteResult {
934    /// Create a new completion result
935    pub fn new(values: Vec<String>) -> Self {
936        Self {
937            completion: Completion::new(values),
938            meta: None,
939        }
940    }
941
942    /// Create a completion result with pagination info
943    pub fn with_pagination(values: Vec<String>, total: u32, has_more: bool) -> Self {
944        Self {
945            completion: Completion::with_pagination(values, total, has_more),
946            meta: None,
947        }
948    }
949}
950
951// =============================================================================
952// Sampling Types
953// =============================================================================
954
955/// Hint for model selection
956#[derive(Debug, Clone, Serialize, Deserialize)]
957pub struct ModelHint {
958    /// Suggested model name (partial match allowed)
959    #[serde(default, skip_serializing_if = "Option::is_none")]
960    pub name: Option<String>,
961}
962
963impl ModelHint {
964    /// Create a new model hint
965    pub fn new(name: impl Into<String>) -> Self {
966        Self {
967            name: Some(name.into()),
968        }
969    }
970}
971
972/// Preferences for model selection during sampling
973#[derive(Debug, Clone, Default, Serialize, Deserialize)]
974#[serde(rename_all = "camelCase")]
975pub struct ModelPreferences {
976    /// Priority for response speed (0.0 to 1.0)
977    #[serde(default, skip_serializing_if = "Option::is_none")]
978    pub speed_priority: Option<f64>,
979    /// Priority for model intelligence/capability (0.0 to 1.0)
980    #[serde(default, skip_serializing_if = "Option::is_none")]
981    pub intelligence_priority: Option<f64>,
982    /// Priority for cost efficiency (0.0 to 1.0)
983    #[serde(default, skip_serializing_if = "Option::is_none")]
984    pub cost_priority: Option<f64>,
985    /// Hints for model selection
986    #[serde(default, skip_serializing_if = "Vec::is_empty")]
987    pub hints: Vec<ModelHint>,
988}
989
990impl ModelPreferences {
991    /// Create new model preferences
992    pub fn new() -> Self {
993        Self::default()
994    }
995
996    /// Set speed priority (0.0 to 1.0)
997    pub fn speed(mut self, priority: f64) -> Self {
998        self.speed_priority = Some(priority.clamp(0.0, 1.0));
999        self
1000    }
1001
1002    /// Set intelligence priority (0.0 to 1.0)
1003    pub fn intelligence(mut self, priority: f64) -> Self {
1004        self.intelligence_priority = Some(priority.clamp(0.0, 1.0));
1005        self
1006    }
1007
1008    /// Set cost priority (0.0 to 1.0)
1009    pub fn cost(mut self, priority: f64) -> Self {
1010        self.cost_priority = Some(priority.clamp(0.0, 1.0));
1011        self
1012    }
1013
1014    /// Add a model hint
1015    pub fn hint(mut self, name: impl Into<String>) -> Self {
1016        self.hints.push(ModelHint::new(name));
1017        self
1018    }
1019}
1020
1021/// Context inclusion mode for sampling
1022#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
1023#[serde(rename_all = "camelCase")]
1024#[non_exhaustive]
1025pub enum IncludeContext {
1026    /// Include context from all connected MCP servers
1027    AllServers,
1028    /// Include context from this server only
1029    ThisServer,
1030    /// Don't include any additional context
1031    #[default]
1032    None,
1033}
1034
1035/// Message for sampling request
1036#[derive(Debug, Clone, Serialize, Deserialize)]
1037pub struct SamplingMessage {
1038    /// The role of the message sender
1039    pub role: ContentRole,
1040    /// The content of the message (single item or array)
1041    pub content: SamplingContentOrArray,
1042    /// Optional protocol-level metadata
1043    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1044    pub meta: Option<Value>,
1045}
1046
1047impl SamplingMessage {
1048    /// Create a user message with text content
1049    pub fn user(text: impl Into<String>) -> Self {
1050        Self {
1051            role: ContentRole::User,
1052            content: SamplingContentOrArray::Single(SamplingContent::Text {
1053                text: text.into(),
1054                annotations: None,
1055                meta: None,
1056            }),
1057            meta: None,
1058        }
1059    }
1060
1061    /// Create an assistant message with text content
1062    pub fn assistant(text: impl Into<String>) -> Self {
1063        Self {
1064            role: ContentRole::Assistant,
1065            content: SamplingContentOrArray::Single(SamplingContent::Text {
1066                text: text.into(),
1067                annotations: None,
1068                meta: None,
1069            }),
1070            meta: None,
1071        }
1072    }
1073}
1074
1075/// Tool definition for use in sampling requests (SEP-1577)
1076///
1077/// The MCP spec uses the full `Tool` type for sampling tools.
1078/// This struct mirrors `ToolDefinition` with all optional fields.
1079#[derive(Debug, Clone, Serialize, Deserialize)]
1080#[serde(rename_all = "camelCase")]
1081pub struct SamplingTool {
1082    /// The name of the tool
1083    pub name: String,
1084    /// Human-readable title for display purposes
1085    #[serde(default, skip_serializing_if = "Option::is_none")]
1086    pub title: Option<String>,
1087    /// Description of what the tool does
1088    #[serde(skip_serializing_if = "Option::is_none")]
1089    pub description: Option<String>,
1090    /// JSON Schema describing the tool's input parameters
1091    pub input_schema: Value,
1092    /// Optional JSON Schema defining expected output structure
1093    #[serde(default, skip_serializing_if = "Option::is_none")]
1094    pub output_schema: Option<Value>,
1095    /// Optional icons for display in user interfaces
1096    #[serde(default, skip_serializing_if = "Option::is_none")]
1097    pub icons: Option<Vec<ToolIcon>>,
1098    /// Optional annotations describing tool behavior
1099    #[serde(default, skip_serializing_if = "Option::is_none")]
1100    pub annotations: Option<ToolAnnotations>,
1101    /// Optional execution configuration for task support
1102    #[serde(default, skip_serializing_if = "Option::is_none")]
1103    pub execution: Option<ToolExecution>,
1104}
1105
1106/// Tool choice mode for sampling requests (SEP-1577)
1107///
1108/// Controls how the LLM should use the available tools.
1109#[derive(Debug, Clone, Serialize, Deserialize)]
1110pub struct ToolChoice {
1111    /// The tool choice mode: "auto", "none", or "tool"
1112    pub mode: String,
1113    /// Name of the specific tool to use (required when mode is "tool")
1114    #[serde(skip_serializing_if = "Option::is_none")]
1115    pub name: Option<String>,
1116}
1117
1118impl ToolChoice {
1119    /// Model decides whether to use tools
1120    pub fn auto() -> Self {
1121        Self {
1122            mode: "auto".to_string(),
1123            name: None,
1124        }
1125    }
1126
1127    /// Model must use a tool
1128    pub fn required() -> Self {
1129        Self {
1130            mode: "required".to_string(),
1131            name: None,
1132        }
1133    }
1134
1135    /// Model should not use tools
1136    pub fn none() -> Self {
1137        Self {
1138            mode: "none".to_string(),
1139            name: None,
1140        }
1141    }
1142
1143    /// Force the model to use a specific tool by name
1144    pub fn tool(name: impl Into<String>) -> Self {
1145        Self {
1146            mode: "tool".to_string(),
1147            name: Some(name.into()),
1148        }
1149    }
1150}
1151
1152/// Content types for sampling messages
1153#[derive(Debug, Clone, Serialize, Deserialize)]
1154#[serde(tag = "type", rename_all = "lowercase")]
1155#[non_exhaustive]
1156pub enum SamplingContent {
1157    /// Text content
1158    Text {
1159        /// The text content
1160        text: String,
1161        /// Optional annotations for this content
1162        #[serde(default, skip_serializing_if = "Option::is_none")]
1163        annotations: Option<ContentAnnotations>,
1164        /// Optional protocol-level metadata
1165        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1166        meta: Option<Value>,
1167    },
1168    /// Image content
1169    Image {
1170        /// Base64-encoded image data
1171        data: String,
1172        /// MIME type of the image
1173        #[serde(rename = "mimeType")]
1174        mime_type: String,
1175        /// Optional annotations for this content
1176        #[serde(default, skip_serializing_if = "Option::is_none")]
1177        annotations: Option<ContentAnnotations>,
1178        /// Optional protocol-level metadata
1179        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1180        meta: Option<Value>,
1181    },
1182    /// Audio content (if supported)
1183    Audio {
1184        /// Base64-encoded audio data
1185        data: String,
1186        /// MIME type of the audio
1187        #[serde(rename = "mimeType")]
1188        mime_type: String,
1189        /// Optional annotations for this content
1190        #[serde(default, skip_serializing_if = "Option::is_none")]
1191        annotations: Option<ContentAnnotations>,
1192        /// Optional protocol-level metadata
1193        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1194        meta: Option<Value>,
1195    },
1196    /// Tool use request from the model (SEP-1577)
1197    #[serde(rename = "tool_use")]
1198    ToolUse {
1199        /// Unique identifier for this tool use
1200        id: String,
1201        /// Name of the tool being called
1202        name: String,
1203        /// Input arguments for the tool
1204        input: Value,
1205        /// Optional protocol-level metadata
1206        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1207        meta: Option<Value>,
1208    },
1209    /// Result of a tool invocation (SEP-1577)
1210    #[serde(rename = "tool_result")]
1211    ToolResult {
1212        /// ID of the tool use this result corresponds to
1213        #[serde(rename = "toolUseId")]
1214        tool_use_id: String,
1215        /// The tool result content
1216        content: Vec<SamplingContent>,
1217        /// Structured content from the tool result
1218        #[serde(
1219            default,
1220            rename = "structuredContent",
1221            skip_serializing_if = "Option::is_none"
1222        )]
1223        structured_content: Option<Value>,
1224        /// Whether the tool execution resulted in an error
1225        #[serde(default, rename = "isError", skip_serializing_if = "Option::is_none")]
1226        is_error: Option<bool>,
1227        /// Optional protocol-level metadata
1228        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1229        meta: Option<Value>,
1230    },
1231}
1232
1233impl SamplingContent {
1234    /// Get the text content if this is a text variant.
1235    ///
1236    /// Returns `None` if this is an image, audio, tool_use, or tool_result variant.
1237    ///
1238    /// # Example
1239    ///
1240    /// ```rust
1241    /// use tower_mcp_types::protocol::SamplingContent;
1242    ///
1243    /// let text_content = SamplingContent::Text { text: "Hello".into(), annotations: None, meta: None };
1244    /// assert_eq!(text_content.as_text(), Some("Hello"));
1245    ///
1246    /// let image_content = SamplingContent::Image {
1247    ///     data: "base64...".into(),
1248    ///     mime_type: "image/png".into(),
1249    ///     annotations: None,
1250    ///     meta: None,
1251    /// };
1252    /// assert_eq!(image_content.as_text(), None);
1253    /// ```
1254    pub fn as_text(&self) -> Option<&str> {
1255        match self {
1256            SamplingContent::Text { text, .. } => Some(text),
1257            _ => None,
1258        }
1259    }
1260}
1261
1262/// Content that can be either a single item or an array
1263///
1264/// The MCP spec allows content fields to be either a single
1265/// SamplingContent or an array of SamplingContent items.
1266#[derive(Debug, Clone, Serialize, Deserialize)]
1267#[serde(untagged)]
1268#[non_exhaustive]
1269pub enum SamplingContentOrArray {
1270    /// Single content item
1271    Single(SamplingContent),
1272    /// Array of content items
1273    Array(Vec<SamplingContent>),
1274}
1275
1276impl SamplingContentOrArray {
1277    /// Get content items as a slice
1278    pub fn items(&self) -> Vec<&SamplingContent> {
1279        match self {
1280            Self::Single(c) => vec![c],
1281            Self::Array(arr) => arr.iter().collect(),
1282        }
1283    }
1284
1285    /// Get owned content items
1286    pub fn into_items(self) -> Vec<SamplingContent> {
1287        match self {
1288            Self::Single(c) => vec![c],
1289            Self::Array(arr) => arr,
1290        }
1291    }
1292}
1293
1294/// Parameters for sampling/createMessage request
1295#[derive(Debug, Clone, Serialize, Deserialize)]
1296#[serde(rename_all = "camelCase")]
1297pub struct CreateMessageParams {
1298    /// The messages to send to the LLM
1299    pub messages: Vec<SamplingMessage>,
1300    /// Maximum number of tokens to generate
1301    pub max_tokens: u32,
1302    /// Optional system prompt
1303    #[serde(default, skip_serializing_if = "Option::is_none")]
1304    pub system_prompt: Option<String>,
1305    /// Sampling temperature (0.0 to 1.0)
1306    #[serde(default, skip_serializing_if = "Option::is_none")]
1307    pub temperature: Option<f64>,
1308    /// Stop sequences
1309    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1310    pub stop_sequences: Vec<String>,
1311    /// Model preferences
1312    #[serde(default, skip_serializing_if = "Option::is_none")]
1313    pub model_preferences: Option<ModelPreferences>,
1314    /// Context inclusion mode
1315    #[serde(default, skip_serializing_if = "Option::is_none")]
1316    pub include_context: Option<IncludeContext>,
1317    /// Additional metadata
1318    #[serde(default, skip_serializing_if = "Option::is_none")]
1319    pub metadata: Option<serde_json::Map<String, Value>>,
1320    /// Tools available for the model to use (SEP-1577)
1321    #[serde(default, skip_serializing_if = "Option::is_none")]
1322    pub tools: Option<Vec<SamplingTool>>,
1323    /// Tool choice mode (SEP-1577)
1324    #[serde(default, skip_serializing_if = "Option::is_none")]
1325    pub tool_choice: Option<ToolChoice>,
1326    /// Task parameters for async execution
1327    #[serde(default, skip_serializing_if = "Option::is_none")]
1328    pub task: Option<TaskRequestParams>,
1329    /// Optional protocol-level metadata
1330    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1331    pub meta: Option<Value>,
1332}
1333
1334impl CreateMessageParams {
1335    /// Create a new sampling request
1336    pub fn new(messages: Vec<SamplingMessage>, max_tokens: u32) -> Self {
1337        Self {
1338            messages,
1339            max_tokens,
1340            system_prompt: None,
1341            temperature: None,
1342            stop_sequences: Vec::new(),
1343            model_preferences: None,
1344            include_context: None,
1345            metadata: None,
1346            tools: None,
1347            tool_choice: None,
1348            task: None,
1349            meta: None,
1350        }
1351    }
1352
1353    /// Set the system prompt
1354    pub fn system_prompt(mut self, prompt: impl Into<String>) -> Self {
1355        self.system_prompt = Some(prompt.into());
1356        self
1357    }
1358
1359    /// Set the temperature
1360    pub fn temperature(mut self, temp: f64) -> Self {
1361        self.temperature = Some(temp.clamp(0.0, 1.0));
1362        self
1363    }
1364
1365    /// Add a stop sequence
1366    pub fn stop_sequence(mut self, seq: impl Into<String>) -> Self {
1367        self.stop_sequences.push(seq.into());
1368        self
1369    }
1370
1371    /// Set model preferences
1372    pub fn model_preferences(mut self, prefs: ModelPreferences) -> Self {
1373        self.model_preferences = Some(prefs);
1374        self
1375    }
1376
1377    /// Set context inclusion mode
1378    pub fn include_context(mut self, mode: IncludeContext) -> Self {
1379        self.include_context = Some(mode);
1380        self
1381    }
1382
1383    /// Set tools available for the model to use (SEP-1577)
1384    pub fn tools(mut self, tools: Vec<SamplingTool>) -> Self {
1385        self.tools = Some(tools);
1386        self
1387    }
1388
1389    /// Set tool choice mode (SEP-1577)
1390    pub fn tool_choice(mut self, choice: ToolChoice) -> Self {
1391        self.tool_choice = Some(choice);
1392        self
1393    }
1394}
1395
1396/// Result of sampling/createMessage request
1397#[derive(Debug, Clone, Serialize, Deserialize)]
1398#[serde(rename_all = "camelCase")]
1399pub struct CreateMessageResult {
1400    /// The generated content (single item or array)
1401    pub content: SamplingContentOrArray,
1402    /// The model that generated the response
1403    pub model: String,
1404    /// The role of the response (always assistant)
1405    pub role: ContentRole,
1406    /// Why the generation stopped
1407    #[serde(default, skip_serializing_if = "Option::is_none")]
1408    pub stop_reason: Option<String>,
1409    /// Optional protocol-level metadata
1410    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1411    pub meta: Option<Value>,
1412}
1413
1414impl CreateMessageResult {
1415    /// Get content items as a vector of references
1416    pub fn content_items(&self) -> Vec<&SamplingContent> {
1417        self.content.items()
1418    }
1419
1420    /// Get the text from the first text content item.
1421    ///
1422    /// Returns `None` if there are no content items or if the first
1423    /// text-containing item is not found.
1424    ///
1425    /// # Example
1426    ///
1427    /// ```rust
1428    /// use tower_mcp_types::protocol::{CreateMessageResult, SamplingContent, SamplingContentOrArray, ContentRole};
1429    ///
1430    /// let result = CreateMessageResult {
1431    ///     content: SamplingContentOrArray::Single(SamplingContent::Text {
1432    ///         text: "Hello, world!".into(),
1433    ///         annotations: None,
1434    ///         meta: None,
1435    ///     }),
1436    ///     model: "claude-3".into(),
1437    ///     role: ContentRole::Assistant,
1438    ///     stop_reason: None,
1439    ///     meta: None,
1440    /// };
1441    /// assert_eq!(result.first_text(), Some("Hello, world!"));
1442    /// ```
1443    pub fn first_text(&self) -> Option<&str> {
1444        self.content.items().iter().find_map(|c| c.as_text())
1445    }
1446}
1447
1448/// Information about a client or server implementation
1449#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1450#[serde(rename_all = "camelCase")]
1451pub struct Implementation {
1452    /// Name of the implementation
1453    pub name: String,
1454    /// Version of the implementation
1455    pub version: String,
1456    /// Human-readable title for display purposes
1457    #[serde(skip_serializing_if = "Option::is_none")]
1458    pub title: Option<String>,
1459    /// Description of the implementation
1460    #[serde(skip_serializing_if = "Option::is_none")]
1461    pub description: Option<String>,
1462    /// Icons for the implementation
1463    #[serde(skip_serializing_if = "Option::is_none")]
1464    pub icons: Option<Vec<ToolIcon>>,
1465    /// URL of the implementation's website
1466    #[serde(skip_serializing_if = "Option::is_none")]
1467    pub website_url: Option<String>,
1468    /// Optional protocol-level metadata
1469    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1470    pub meta: Option<Value>,
1471}
1472
1473#[derive(Debug, Clone, Serialize, Deserialize)]
1474#[serde(rename_all = "camelCase")]
1475pub struct InitializeResult {
1476    pub protocol_version: String,
1477    pub capabilities: ServerCapabilities,
1478    pub server_info: Implementation,
1479    /// Optional instructions describing how to use this server.
1480    /// These hints help LLMs understand the server's features.
1481    #[serde(skip_serializing_if = "Option::is_none")]
1482    pub instructions: Option<String>,
1483    /// Optional protocol-level metadata
1484    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1485    pub meta: Option<Value>,
1486}
1487
1488#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1489#[serde(rename_all = "camelCase")]
1490pub struct ServerCapabilities {
1491    #[serde(default, skip_serializing_if = "Option::is_none")]
1492    pub tools: Option<ToolsCapability>,
1493    #[serde(default, skip_serializing_if = "Option::is_none")]
1494    pub resources: Option<ResourcesCapability>,
1495    #[serde(default, skip_serializing_if = "Option::is_none")]
1496    pub prompts: Option<PromptsCapability>,
1497    /// Logging capability - servers that emit log notifications declare this
1498    #[serde(default, skip_serializing_if = "Option::is_none")]
1499    pub logging: Option<LoggingCapability>,
1500    #[serde(default, skip_serializing_if = "Option::is_none")]
1501    pub tasks: Option<TasksCapability>,
1502    /// Completion capability - server provides autocomplete suggestions
1503    #[serde(default, skip_serializing_if = "Option::is_none")]
1504    pub completions: Option<CompletionsCapability>,
1505    /// Experimental, non-standard capabilities
1506    #[serde(default, skip_serializing_if = "Option::is_none")]
1507    pub experimental: Option<HashMap<String, serde_json::Value>>,
1508    /// Declared extension support (SEP-1724/SEP-2133)
1509    #[serde(default, skip_serializing_if = "Option::is_none")]
1510    pub extensions: Option<HashMap<String, serde_json::Value>>,
1511}
1512
1513/// Logging capability declaration
1514#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1515pub struct LoggingCapability {}
1516
1517/// Capability for async task management
1518#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1519#[serde(rename_all = "camelCase")]
1520pub struct TasksCapability {
1521    /// Support for listing tasks
1522    #[serde(default, skip_serializing_if = "Option::is_none")]
1523    pub list: Option<TasksListCapability>,
1524    /// Support for cancelling tasks
1525    #[serde(default, skip_serializing_if = "Option::is_none")]
1526    pub cancel: Option<TasksCancelCapability>,
1527    /// Which request types support task-augmented requests
1528    #[serde(default, skip_serializing_if = "Option::is_none")]
1529    pub requests: Option<TasksRequestsCapability>,
1530}
1531
1532/// Marker capability for tasks/list support
1533#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1534pub struct TasksListCapability {}
1535
1536/// Marker capability for tasks/cancel support
1537#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1538pub struct TasksCancelCapability {}
1539
1540/// Capability declaring which request types support task-augmented requests
1541#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1542#[serde(rename_all = "camelCase")]
1543pub struct TasksRequestsCapability {
1544    /// Task support for tool-related requests
1545    #[serde(default, skip_serializing_if = "Option::is_none")]
1546    pub tools: Option<TasksToolsRequestsCapability>,
1547}
1548
1549/// Nested capability for task-augmented tool requests
1550#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1551#[serde(rename_all = "camelCase")]
1552pub struct TasksToolsRequestsCapability {
1553    /// Whether the server supports task-augmented tools/call requests
1554    #[serde(default, skip_serializing_if = "Option::is_none")]
1555    pub call: Option<TasksToolsCallCapability>,
1556}
1557
1558/// Marker capability for task-augmented tools/call support
1559#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1560pub struct TasksToolsCallCapability {}
1561
1562#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1563#[serde(rename_all = "camelCase")]
1564pub struct ToolsCapability {
1565    #[serde(default)]
1566    pub list_changed: bool,
1567}
1568
1569#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1570#[serde(rename_all = "camelCase")]
1571pub struct ResourcesCapability {
1572    #[serde(default)]
1573    pub subscribe: bool,
1574    #[serde(default)]
1575    pub list_changed: bool,
1576}
1577
1578#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1579#[serde(rename_all = "camelCase")]
1580pub struct PromptsCapability {
1581    #[serde(default)]
1582    pub list_changed: bool,
1583}
1584
1585// =============================================================================
1586// Tools
1587// =============================================================================
1588
1589#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1590pub struct ListToolsParams {
1591    #[serde(default, skip_serializing_if = "Option::is_none")]
1592    pub cursor: Option<String>,
1593    /// Optional protocol-level metadata
1594    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1595    pub meta: Option<RequestMeta>,
1596}
1597
1598#[derive(Debug, Clone, Serialize, Deserialize)]
1599#[serde(rename_all = "camelCase")]
1600pub struct ListToolsResult {
1601    pub tools: Vec<ToolDefinition>,
1602    #[serde(default, skip_serializing_if = "Option::is_none")]
1603    pub next_cursor: Option<String>,
1604    /// Optional protocol-level metadata
1605    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1606    pub meta: Option<Value>,
1607}
1608
1609/// Tool definition as returned by tools/list
1610#[derive(Debug, Clone, Serialize, Deserialize)]
1611#[serde(rename_all = "camelCase")]
1612pub struct ToolDefinition {
1613    pub name: String,
1614    /// Human-readable title for display purposes
1615    #[serde(skip_serializing_if = "Option::is_none")]
1616    pub title: Option<String>,
1617    #[serde(skip_serializing_if = "Option::is_none")]
1618    pub description: Option<String>,
1619    pub input_schema: Value,
1620    /// Optional JSON Schema defining expected output structure
1621    #[serde(skip_serializing_if = "Option::is_none")]
1622    pub output_schema: Option<Value>,
1623    /// Optional icons for display in user interfaces
1624    #[serde(skip_serializing_if = "Option::is_none")]
1625    pub icons: Option<Vec<ToolIcon>>,
1626    /// Optional annotations describing tool behavior.
1627    /// Note: Clients MUST consider these untrusted unless from a trusted server.
1628    #[serde(skip_serializing_if = "Option::is_none")]
1629    pub annotations: Option<ToolAnnotations>,
1630    /// Optional execution configuration for task support
1631    #[serde(skip_serializing_if = "Option::is_none")]
1632    pub execution: Option<ToolExecution>,
1633    /// Optional protocol-level metadata
1634    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1635    pub meta: Option<Value>,
1636}
1637
1638/// Icon theme context
1639#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1640#[serde(rename_all = "lowercase")]
1641#[non_exhaustive]
1642pub enum IconTheme {
1643    /// Icon designed for light backgrounds
1644    Light,
1645    /// Icon designed for dark backgrounds
1646    Dark,
1647}
1648
1649/// Icon for tool display in user interfaces
1650#[derive(Debug, Clone, Serialize, Deserialize)]
1651#[serde(rename_all = "camelCase")]
1652pub struct ToolIcon {
1653    /// URL or data URI of the icon
1654    pub src: String,
1655    /// MIME type of the icon (e.g., "image/png", "image/svg+xml")
1656    #[serde(skip_serializing_if = "Option::is_none")]
1657    pub mime_type: Option<String>,
1658    /// Available sizes (e.g., ["48x48", "96x96"])
1659    #[serde(skip_serializing_if = "Option::is_none")]
1660    pub sizes: Option<Vec<String>>,
1661    /// Icon theme context ("light" or "dark")
1662    #[serde(skip_serializing_if = "Option::is_none")]
1663    pub theme: Option<IconTheme>,
1664}
1665
1666/// Annotations describing tool behavior for trust and safety.
1667/// Clients MUST consider these untrusted unless the server is trusted.
1668#[derive(Debug, Clone, Serialize, Deserialize)]
1669#[serde(rename_all = "camelCase")]
1670pub struct ToolAnnotations {
1671    /// Human-readable title for the tool
1672    #[serde(skip_serializing_if = "Option::is_none")]
1673    pub title: Option<String>,
1674    /// If true, the tool does not modify state. Default: false
1675    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1676    pub read_only_hint: bool,
1677    /// If true, the tool may have destructive effects. Default: true
1678    /// Only meaningful when read_only_hint is false.
1679    #[serde(default = "default_true", skip_serializing_if = "is_true")]
1680    pub destructive_hint: bool,
1681    /// If true, calling repeatedly with same args has same effect. Default: false
1682    /// Only meaningful when read_only_hint is false.
1683    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1684    pub idempotent_hint: bool,
1685    /// If true, tool interacts with external entities. Default: true
1686    #[serde(default = "default_true", skip_serializing_if = "is_true")]
1687    pub open_world_hint: bool,
1688}
1689
1690impl Default for ToolAnnotations {
1691    fn default() -> Self {
1692        Self {
1693            title: None,
1694            read_only_hint: false,
1695            destructive_hint: true,
1696            idempotent_hint: false,
1697            open_world_hint: true,
1698        }
1699    }
1700}
1701
1702impl ToolAnnotations {
1703    /// Returns true if the tool does not modify state.
1704    pub fn is_read_only(&self) -> bool {
1705        self.read_only_hint
1706    }
1707
1708    /// Returns true if the tool may have destructive effects.
1709    pub fn is_destructive(&self) -> bool {
1710        self.destructive_hint
1711    }
1712
1713    /// Returns true if calling repeatedly with same args has the same effect.
1714    pub fn is_idempotent(&self) -> bool {
1715        self.idempotent_hint
1716    }
1717
1718    /// Returns true if the tool interacts with external entities.
1719    pub fn is_open_world(&self) -> bool {
1720        self.open_world_hint
1721    }
1722}
1723
1724impl ToolDefinition {
1725    /// Returns true if the tool does not modify state.
1726    ///
1727    /// Returns `false` (the MCP spec default) when annotations are absent.
1728    pub fn is_read_only(&self) -> bool {
1729        self.annotations.as_ref().is_some_and(|a| a.read_only_hint)
1730    }
1731
1732    /// Returns true if the tool may have destructive effects.
1733    ///
1734    /// Returns `true` (the MCP spec default) when annotations are absent.
1735    pub fn is_destructive(&self) -> bool {
1736        self.annotations.as_ref().is_none_or(|a| a.destructive_hint)
1737    }
1738
1739    /// Returns true if calling repeatedly with same args has the same effect.
1740    ///
1741    /// Returns `false` (the MCP spec default) when annotations are absent.
1742    pub fn is_idempotent(&self) -> bool {
1743        self.annotations.as_ref().is_some_and(|a| a.idempotent_hint)
1744    }
1745
1746    /// Returns true if the tool interacts with external entities.
1747    ///
1748    /// Returns `true` (the MCP spec default) when annotations are absent.
1749    pub fn is_open_world(&self) -> bool {
1750        self.annotations.as_ref().is_none_or(|a| a.open_world_hint)
1751    }
1752}
1753
1754fn default_true() -> bool {
1755    true
1756}
1757
1758fn is_true(v: &bool) -> bool {
1759    *v
1760}
1761
1762#[derive(Debug, Clone, Serialize, Deserialize)]
1763pub struct CallToolParams {
1764    pub name: String,
1765    #[serde(default)]
1766    pub arguments: Value,
1767    /// Request metadata including progress token
1768    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1769    pub meta: Option<RequestMeta>,
1770    /// Task parameters for async execution
1771    #[serde(default, skip_serializing_if = "Option::is_none")]
1772    pub task: Option<TaskRequestParams>,
1773}
1774
1775/// Result of a tool invocation.
1776///
1777/// This is the return type for tool handlers. Use the convenience constructors
1778/// like [`CallToolResult::text`], [`CallToolResult::json`], or [`CallToolResult::error`]
1779/// to create results easily.
1780///
1781/// # Example
1782///
1783/// ```rust
1784/// use tower_mcp_types::CallToolResult;
1785///
1786/// // Simple text result
1787/// let result = CallToolResult::text("Hello, world!");
1788///
1789/// // JSON result with structured content
1790/// let result = CallToolResult::json(serde_json::json!({"key": "value"}));
1791///
1792/// // Error result
1793/// let result = CallToolResult::error("Something went wrong");
1794/// ```
1795#[derive(Debug, Clone, Serialize, Deserialize)]
1796#[serde(rename_all = "camelCase")]
1797pub struct CallToolResult {
1798    /// The content items returned by the tool.
1799    pub content: Vec<Content>,
1800    /// Whether this result represents an error.
1801    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1802    pub is_error: bool,
1803    /// Optional structured content for programmatic access.
1804    #[serde(default, skip_serializing_if = "Option::is_none")]
1805    pub structured_content: Option<Value>,
1806    /// Optional metadata (e.g., for io.modelcontextprotocol/related-task)
1807    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1808    pub meta: Option<Value>,
1809}
1810
1811impl CallToolResult {
1812    /// Create a text result.
1813    ///
1814    /// This is the most common result type for tools that return plain text.
1815    pub fn text(text: impl Into<String>) -> Self {
1816        Self {
1817            content: vec![Content::Text {
1818                text: text.into(),
1819                annotations: None,
1820                meta: None,
1821            }],
1822            is_error: false,
1823            structured_content: None,
1824            meta: None,
1825        }
1826    }
1827
1828    /// Create an error result.
1829    ///
1830    /// Use this when the tool encounters an error during execution.
1831    /// The `is_error` flag will be set to `true`.
1832    pub fn error(message: impl Into<String>) -> Self {
1833        Self {
1834            content: vec![Content::Text {
1835                text: message.into(),
1836                annotations: None,
1837                meta: None,
1838            }],
1839            is_error: true,
1840            structured_content: None,
1841            meta: None,
1842        }
1843    }
1844
1845    /// Create a JSON result with structured content from a [`serde_json::Value`].
1846    ///
1847    /// The JSON value is serialized to pretty-printed text for display,
1848    /// and also stored in `structured_content` for programmatic access.
1849    ///
1850    /// If you have a type that implements [`serde::Serialize`], use
1851    /// [`from_serialize`](Self::from_serialize) instead to avoid manual `to_value()` calls.
1852    pub fn json(value: Value) -> Self {
1853        let text = serde_json::to_string_pretty(&value).unwrap_or_default();
1854        Self {
1855            content: vec![Content::Text {
1856                text,
1857                annotations: None,
1858                meta: None,
1859            }],
1860            is_error: false,
1861            structured_content: Some(value),
1862            meta: None,
1863        }
1864    }
1865
1866    /// Create a JSON result from any serializable value.
1867    ///
1868    /// This is a fallible alternative to [`json`](Self::json) that accepts any
1869    /// `serde::Serialize` type and handles serialization errors gracefully.
1870    /// The value is serialized to a `serde_json::Value`, then delegated to `json()`,
1871    /// so `structured_content` is populated correctly.
1872    ///
1873    /// # Errors
1874    ///
1875    /// Returns an error if the value cannot be serialized to JSON.
1876    ///
1877    /// # Example
1878    ///
1879    /// ```rust
1880    /// use tower_mcp_types::CallToolResult;
1881    /// use serde::Serialize;
1882    ///
1883    /// #[derive(Serialize)]
1884    /// struct SearchResult {
1885    ///     title: String,
1886    ///     score: f64,
1887    /// }
1888    ///
1889    /// let result = SearchResult {
1890    ///     title: "Example".to_string(),
1891    ///     score: 0.95,
1892    /// };
1893    /// let tool_result = CallToolResult::from_serialize(&result).unwrap();
1894    /// assert!(!tool_result.is_error);
1895    /// assert!(tool_result.structured_content.is_some());
1896    /// ```
1897    pub fn from_serialize(
1898        value: &impl serde::Serialize,
1899    ) -> std::result::Result<Self, crate::error::Error> {
1900        let json_value = serde_json::to_value(value)
1901            .map_err(|e| crate::error::Error::tool(format!("Serialization failed: {}", e)))?;
1902        Ok(Self::json(json_value))
1903    }
1904
1905    /// Create a result from a list of serializable items.
1906    ///
1907    /// Wraps the list in a JSON object with the given key and a `count` field,
1908    /// since MCP `structuredContent` requires objects, not bare arrays.
1909    ///
1910    /// # Examples
1911    ///
1912    /// ```
1913    /// use tower_mcp_types::CallToolResult;
1914    /// use serde::Serialize;
1915    ///
1916    /// #[derive(Serialize)]
1917    /// struct Database {
1918    ///     name: String,
1919    ///     size_mb: u64,
1920    /// }
1921    ///
1922    /// let databases = vec![
1923    ///     Database { name: "users".to_string(), size_mb: 100 },
1924    ///     Database { name: "logs".to_string(), size_mb: 500 },
1925    /// ];
1926    /// let result = CallToolResult::from_list("databases", &databases).unwrap();
1927    /// // Produces: {"databases": [...], "count": 2}
1928    /// assert!(!result.is_error);
1929    /// assert!(result.structured_content.is_some());
1930    /// ```
1931    pub fn from_list<T: serde::Serialize>(
1932        key: &str,
1933        items: &[T],
1934    ) -> std::result::Result<Self, crate::error::Error> {
1935        Self::from_serialize(&serde_json::json!({ key: items, "count": items.len() }))
1936    }
1937
1938    /// Create a result with a base64-encoded image.
1939    ///
1940    /// # Example
1941    ///
1942    /// ```rust
1943    /// use tower_mcp_types::CallToolResult;
1944    /// use base64::Engine;
1945    ///
1946    /// let png_bytes = vec![0x89, 0x50, 0x4E, 0x47]; // PNG header
1947    /// let encoded = base64::engine::general_purpose::STANDARD.encode(&png_bytes);
1948    ///
1949    /// let result = CallToolResult::image(encoded, "image/png");
1950    /// assert!(!result.is_error);
1951    /// ```
1952    pub fn image(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1953        Self {
1954            content: vec![Content::Image {
1955                data: data.into(),
1956                mime_type: mime_type.into(),
1957                annotations: None,
1958                meta: None,
1959            }],
1960            is_error: false,
1961            structured_content: None,
1962            meta: None,
1963        }
1964    }
1965
1966    /// Create a result with base64-encoded audio.
1967    ///
1968    /// # Example
1969    ///
1970    /// ```rust
1971    /// use tower_mcp_types::CallToolResult;
1972    /// use base64::Engine;
1973    ///
1974    /// let wav_bytes = vec![0x52, 0x49, 0x46, 0x46]; // RIFF header
1975    /// let encoded = base64::engine::general_purpose::STANDARD.encode(&wav_bytes);
1976    ///
1977    /// let result = CallToolResult::audio(encoded, "audio/wav");
1978    /// assert!(!result.is_error);
1979    /// ```
1980    pub fn audio(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1981        Self {
1982            content: vec![Content::Audio {
1983                data: data.into(),
1984                mime_type: mime_type.into(),
1985                annotations: None,
1986                meta: None,
1987            }],
1988            is_error: false,
1989            structured_content: None,
1990            meta: None,
1991        }
1992    }
1993
1994    /// Create a result with a resource link (without embedding the content).
1995    ///
1996    /// Use this to reference a resource by URI without including its full content
1997    /// in the tool result.
1998    ///
1999    /// # Example
2000    ///
2001    /// ```rust
2002    /// use tower_mcp_types::CallToolResult;
2003    ///
2004    /// let result = CallToolResult::resource_link(
2005    ///     "file:///var/log/app.log",
2006    ///     "app-log",
2007    /// );
2008    /// assert!(!result.is_error);
2009    /// ```
2010    pub fn resource_link(uri: impl Into<String>, name: impl Into<String>) -> Self {
2011        Self {
2012            content: vec![Content::ResourceLink {
2013                uri: uri.into(),
2014                name: name.into(),
2015                title: None,
2016                description: None,
2017                mime_type: None,
2018                size: None,
2019                icons: None,
2020                annotations: None,
2021                meta: None,
2022            }],
2023            is_error: false,
2024            structured_content: None,
2025            meta: None,
2026        }
2027    }
2028
2029    /// Create a result with a resource link including metadata
2030    pub fn resource_link_with_meta(
2031        uri: impl Into<String>,
2032        name: impl Into<String>,
2033        description: Option<String>,
2034        mime_type: Option<String>,
2035    ) -> Self {
2036        Self {
2037            content: vec![Content::ResourceLink {
2038                uri: uri.into(),
2039                name: name.into(),
2040                title: None,
2041                description,
2042                mime_type,
2043                size: None,
2044                icons: None,
2045                annotations: None,
2046                meta: None,
2047            }],
2048            is_error: false,
2049            structured_content: None,
2050            meta: None,
2051        }
2052    }
2053
2054    /// Create a result with an embedded resource
2055    pub fn resource(resource: ResourceContent) -> Self {
2056        Self {
2057            content: vec![Content::Resource {
2058                resource,
2059                annotations: None,
2060                meta: None,
2061            }],
2062            is_error: false,
2063            structured_content: None,
2064            meta: None,
2065        }
2066    }
2067
2068    /// Concatenate all text content items into a single string.
2069    ///
2070    /// Non-text content items are skipped. Multiple text items are
2071    /// joined without a separator.
2072    ///
2073    /// # Example
2074    ///
2075    /// ```rust
2076    /// use tower_mcp_types::CallToolResult;
2077    ///
2078    /// let result = CallToolResult::text("hello world");
2079    /// assert_eq!(result.all_text(), "hello world");
2080    /// ```
2081    pub fn all_text(&self) -> String {
2082        self.content.iter().filter_map(|c| c.as_text()).collect()
2083    }
2084
2085    /// Get the text from the first [`Content::Text`] item.
2086    ///
2087    /// Returns `None` if there are no text content items.
2088    ///
2089    /// # Example
2090    ///
2091    /// ```rust
2092    /// use tower_mcp_types::CallToolResult;
2093    ///
2094    /// let result = CallToolResult::text("hello");
2095    /// assert_eq!(result.first_text(), Some("hello"));
2096    /// ```
2097    pub fn first_text(&self) -> Option<&str> {
2098        self.content.iter().find_map(|c| c.as_text())
2099    }
2100
2101    /// Parse the result as a JSON [`Value`].
2102    ///
2103    /// Returns `structured_content` if set (from [`json()`](Self::json) /
2104    /// [`from_serialize()`](Self::from_serialize)), otherwise parses
2105    /// [`first_text()`](Self::first_text). Returns `None` if no content is available.
2106    ///
2107    /// # Example
2108    ///
2109    /// ```rust
2110    /// use tower_mcp_types::CallToolResult;
2111    /// use serde_json::json;
2112    ///
2113    /// let result = CallToolResult::json(json!({"key": "value"}));
2114    /// let value = result.as_json().unwrap().unwrap();
2115    /// assert_eq!(value["key"], "value");
2116    /// ```
2117    pub fn as_json(&self) -> Option<Result<Value, serde_json::Error>> {
2118        if let Some(ref sc) = self.structured_content {
2119            return Some(Ok(sc.clone()));
2120        }
2121        self.first_text().map(serde_json::from_str)
2122    }
2123
2124    /// Deserialize the result into a typed value.
2125    ///
2126    /// Uses `structured_content` if set, otherwise parses
2127    /// [`first_text()`](Self::first_text). Returns `None` if no content is available.
2128    ///
2129    /// # Example
2130    ///
2131    /// ```rust
2132    /// use tower_mcp_types::CallToolResult;
2133    /// use serde::Deserialize;
2134    /// use serde_json::json;
2135    ///
2136    /// #[derive(Debug, Deserialize, PartialEq)]
2137    /// struct Output { key: String }
2138    ///
2139    /// let result = CallToolResult::json(json!({"key": "value"}));
2140    /// let output: Output = result.deserialize().unwrap().unwrap();
2141    /// assert_eq!(output.key, "value");
2142    /// ```
2143    pub fn deserialize<T: DeserializeOwned>(&self) -> Option<Result<T, serde_json::Error>> {
2144        if let Some(ref sc) = self.structured_content {
2145            return Some(serde_json::from_value(sc.clone()));
2146        }
2147        self.first_text().map(serde_json::from_str)
2148    }
2149}
2150
2151/// Content types for tool results, resources, and prompts.
2152///
2153/// Content can be text, images, audio, or embedded resources. Each variant
2154/// supports optional annotations for audience targeting and priority hints.
2155#[derive(Debug, Clone, Serialize, Deserialize)]
2156#[serde(tag = "type", rename_all = "snake_case")]
2157#[non_exhaustive]
2158pub enum Content {
2159    /// Plain text content.
2160    Text {
2161        /// The text content.
2162        text: String,
2163        /// Optional annotations for this content.
2164        #[serde(skip_serializing_if = "Option::is_none")]
2165        annotations: Option<ContentAnnotations>,
2166        /// Optional protocol-level metadata
2167        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2168        meta: Option<Value>,
2169    },
2170    /// Base64-encoded image content.
2171    Image {
2172        /// Base64-encoded image data.
2173        data: String,
2174        /// MIME type (e.g., "image/png", "image/jpeg").
2175        #[serde(rename = "mimeType")]
2176        mime_type: String,
2177        /// Optional annotations for this content.
2178        #[serde(skip_serializing_if = "Option::is_none")]
2179        annotations: Option<ContentAnnotations>,
2180        /// Optional protocol-level metadata
2181        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2182        meta: Option<Value>,
2183    },
2184    /// Base64-encoded audio content.
2185    Audio {
2186        /// Base64-encoded audio data.
2187        data: String,
2188        /// MIME type (e.g., "audio/wav", "audio/mp3").
2189        #[serde(rename = "mimeType")]
2190        mime_type: String,
2191        /// Optional annotations for this content.
2192        #[serde(skip_serializing_if = "Option::is_none")]
2193        annotations: Option<ContentAnnotations>,
2194        /// Optional protocol-level metadata
2195        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2196        meta: Option<Value>,
2197    },
2198    /// Embedded resource content.
2199    Resource {
2200        /// The embedded resource.
2201        resource: ResourceContent,
2202        /// Optional annotations for this content.
2203        #[serde(skip_serializing_if = "Option::is_none")]
2204        annotations: Option<ContentAnnotations>,
2205        /// Optional protocol-level metadata
2206        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2207        meta: Option<Value>,
2208    },
2209    /// Link to a resource (without embedding the content)
2210    ResourceLink {
2211        /// URI of the resource
2212        uri: String,
2213        /// Programmatic name of the resource (required per BaseMetadata)
2214        name: String,
2215        /// Human-readable title for display purposes
2216        #[serde(default, skip_serializing_if = "Option::is_none")]
2217        title: Option<String>,
2218        /// Description of the resource
2219        #[serde(skip_serializing_if = "Option::is_none")]
2220        description: Option<String>,
2221        /// MIME type of the resource
2222        #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
2223        mime_type: Option<String>,
2224        /// Raw content size in bytes
2225        #[serde(default, skip_serializing_if = "Option::is_none")]
2226        size: Option<u64>,
2227        /// Optional icons for display in user interfaces
2228        #[serde(default, skip_serializing_if = "Option::is_none")]
2229        icons: Option<Vec<ToolIcon>>,
2230        #[serde(skip_serializing_if = "Option::is_none")]
2231        annotations: Option<ContentAnnotations>,
2232        /// Optional protocol-level metadata
2233        #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2234        meta: Option<Value>,
2235    },
2236}
2237
2238/// Annotations for content items
2239#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2240pub struct ContentAnnotations {
2241    /// Intended audience for this content
2242    #[serde(skip_serializing_if = "Option::is_none")]
2243    pub audience: Option<Vec<ContentRole>>,
2244    /// Priority hint from 0 (optional) to 1 (required)
2245    #[serde(skip_serializing_if = "Option::is_none")]
2246    pub priority: Option<f64>,
2247    /// ISO 8601 timestamp of when this content was last modified
2248    #[serde(rename = "lastModified", skip_serializing_if = "Option::is_none")]
2249    pub last_modified: Option<String>,
2250}
2251
2252impl Content {
2253    /// Extract the text from a [`Content::Text`] variant.
2254    ///
2255    /// Returns `None` for non-text content variants.
2256    ///
2257    /// # Example
2258    ///
2259    /// ```rust
2260    /// use tower_mcp_types::Content;
2261    ///
2262    /// let content = Content::Text { text: "hello".into(), annotations: None, meta: None };
2263    /// assert_eq!(content.as_text(), Some("hello"));
2264    /// ```
2265    /// Create a [`Content::Text`] variant with no annotations.
2266    ///
2267    /// This is a shorthand for the common case of creating text content
2268    /// without annotations.
2269    ///
2270    /// # Example
2271    ///
2272    /// ```rust
2273    /// use tower_mcp_types::Content;
2274    ///
2275    /// let content = Content::text("hello world");
2276    /// assert_eq!(content.as_text(), Some("hello world"));
2277    /// ```
2278    pub fn text(text: impl Into<String>) -> Self {
2279        Content::Text {
2280            text: text.into(),
2281            annotations: None,
2282            meta: None,
2283        }
2284    }
2285
2286    /// Extract the text from a [`Content::Text`] variant.
2287    ///
2288    /// Returns `None` for non-text content variants.
2289    ///
2290    /// # Example
2291    ///
2292    /// ```rust
2293    /// use tower_mcp_types::Content;
2294    ///
2295    /// let content = Content::Text { text: "hello".into(), annotations: None, meta: None };
2296    /// assert_eq!(content.as_text(), Some("hello"));
2297    /// ```
2298    pub fn as_text(&self) -> Option<&str> {
2299        match self {
2300            Content::Text { text, .. } => Some(text),
2301            _ => None,
2302        }
2303    }
2304}
2305
2306/// Role indicating who content is intended for.
2307///
2308/// Used in content annotations to specify the target audience.
2309#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2310#[serde(rename_all = "lowercase")]
2311#[non_exhaustive]
2312pub enum ContentRole {
2313    /// Content intended for the human user.
2314    User,
2315    /// Content intended for the AI assistant.
2316    Assistant,
2317}
2318
2319/// Content of an embedded resource.
2320///
2321/// Contains either text or binary (blob) content along with metadata.
2322#[derive(Debug, Clone, Serialize, Deserialize)]
2323#[serde(rename_all = "camelCase")]
2324pub struct ResourceContent {
2325    /// The URI identifying this resource.
2326    pub uri: String,
2327    /// MIME type of the content.
2328    #[serde(skip_serializing_if = "Option::is_none")]
2329    pub mime_type: Option<String>,
2330    /// Text content (for text-based resources).
2331    #[serde(skip_serializing_if = "Option::is_none")]
2332    pub text: Option<String>,
2333    /// Base64-encoded binary content (for binary resources).
2334    #[serde(skip_serializing_if = "Option::is_none")]
2335    pub blob: Option<String>,
2336    /// Optional protocol-level metadata
2337    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2338    pub meta: Option<Value>,
2339}
2340
2341// =============================================================================
2342// Resources
2343// =============================================================================
2344
2345#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2346pub struct ListResourcesParams {
2347    #[serde(default, skip_serializing_if = "Option::is_none")]
2348    pub cursor: Option<String>,
2349    /// Optional protocol-level metadata
2350    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2351    pub meta: Option<RequestMeta>,
2352}
2353
2354#[derive(Debug, Clone, Serialize, Deserialize)]
2355#[serde(rename_all = "camelCase")]
2356pub struct ListResourcesResult {
2357    pub resources: Vec<ResourceDefinition>,
2358    #[serde(default, skip_serializing_if = "Option::is_none")]
2359    pub next_cursor: Option<String>,
2360    /// Optional protocol-level metadata
2361    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2362    pub meta: Option<Value>,
2363}
2364
2365#[derive(Debug, Clone, Serialize, Deserialize)]
2366#[serde(rename_all = "camelCase")]
2367pub struct ResourceDefinition {
2368    pub uri: String,
2369    pub name: String,
2370    /// Human-readable title for display purposes
2371    #[serde(skip_serializing_if = "Option::is_none")]
2372    pub title: Option<String>,
2373    #[serde(skip_serializing_if = "Option::is_none")]
2374    pub description: Option<String>,
2375    #[serde(skip_serializing_if = "Option::is_none")]
2376    pub mime_type: Option<String>,
2377    /// Optional icons for display in user interfaces
2378    #[serde(skip_serializing_if = "Option::is_none")]
2379    pub icons: Option<Vec<ToolIcon>>,
2380    /// Size of the resource in bytes (if known)
2381    #[serde(skip_serializing_if = "Option::is_none")]
2382    pub size: Option<u64>,
2383    /// Annotations for this resource (audience, priority hints)
2384    #[serde(skip_serializing_if = "Option::is_none")]
2385    pub annotations: Option<ContentAnnotations>,
2386    /// Optional protocol-level metadata
2387    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2388    pub meta: Option<Value>,
2389}
2390
2391#[derive(Debug, Clone, Serialize, Deserialize)]
2392pub struct ReadResourceParams {
2393    pub uri: String,
2394    /// Optional protocol-level metadata
2395    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2396    pub meta: Option<RequestMeta>,
2397}
2398
2399#[derive(Debug, Clone, Serialize, Deserialize)]
2400pub struct ReadResourceResult {
2401    pub contents: Vec<ResourceContent>,
2402    /// Optional protocol-level metadata
2403    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2404    pub meta: Option<Value>,
2405}
2406
2407impl ReadResourceResult {
2408    /// Create a result with text content.
2409    ///
2410    /// # Example
2411    ///
2412    /// ```rust
2413    /// use tower_mcp_types::ReadResourceResult;
2414    ///
2415    /// let result = ReadResourceResult::text("file://readme.md", "# Hello World");
2416    /// ```
2417    pub fn text(uri: impl Into<String>, content: impl Into<String>) -> Self {
2418        Self {
2419            contents: vec![ResourceContent {
2420                uri: uri.into(),
2421                mime_type: Some("text/plain".to_string()),
2422                text: Some(content.into()),
2423                blob: None,
2424                meta: None,
2425            }],
2426            meta: None,
2427        }
2428    }
2429
2430    /// Create a result with text content and a specific MIME type.
2431    ///
2432    /// # Example
2433    ///
2434    /// ```rust
2435    /// use tower_mcp_types::ReadResourceResult;
2436    ///
2437    /// let result = ReadResourceResult::text_with_mime(
2438    ///     "file://readme.md",
2439    ///     "# Hello World",
2440    ///     "text/markdown"
2441    /// );
2442    /// ```
2443    pub fn text_with_mime(
2444        uri: impl Into<String>,
2445        content: impl Into<String>,
2446        mime_type: impl Into<String>,
2447    ) -> Self {
2448        Self {
2449            contents: vec![ResourceContent {
2450                uri: uri.into(),
2451                mime_type: Some(mime_type.into()),
2452                text: Some(content.into()),
2453                blob: None,
2454                meta: None,
2455            }],
2456            meta: None,
2457        }
2458    }
2459
2460    /// Create a result with JSON content.
2461    ///
2462    /// The value is serialized to a JSON string automatically.
2463    ///
2464    /// # Example
2465    ///
2466    /// ```rust
2467    /// use tower_mcp_types::ReadResourceResult;
2468    /// use serde_json::json;
2469    ///
2470    /// let data = json!({"name": "example", "count": 42});
2471    /// let result = ReadResourceResult::json("data://config", &data);
2472    /// ```
2473    pub fn json<T: serde::Serialize>(uri: impl Into<String>, value: &T) -> Self {
2474        let json_string =
2475            serde_json::to_string_pretty(value).unwrap_or_else(|_| "null".to_string());
2476        Self {
2477            contents: vec![ResourceContent {
2478                uri: uri.into(),
2479                mime_type: Some("application/json".to_string()),
2480                text: Some(json_string),
2481                blob: None,
2482                meta: None,
2483            }],
2484            meta: None,
2485        }
2486    }
2487
2488    /// Create a result with binary content (base64 encoded).
2489    ///
2490    /// # Example
2491    ///
2492    /// ```rust
2493    /// use tower_mcp_types::ReadResourceResult;
2494    ///
2495    /// let bytes = vec![0x89, 0x50, 0x4E, 0x47]; // PNG magic bytes
2496    /// let result = ReadResourceResult::blob("file://image.png", &bytes);
2497    /// ```
2498    pub fn blob(uri: impl Into<String>, bytes: &[u8]) -> Self {
2499        use base64::Engine;
2500        let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
2501        Self {
2502            contents: vec![ResourceContent {
2503                uri: uri.into(),
2504                mime_type: Some("application/octet-stream".to_string()),
2505                text: None,
2506                blob: Some(encoded),
2507                meta: None,
2508            }],
2509            meta: None,
2510        }
2511    }
2512
2513    /// Create a result with binary content and a specific MIME type.
2514    ///
2515    /// # Example
2516    ///
2517    /// ```rust
2518    /// use tower_mcp_types::ReadResourceResult;
2519    ///
2520    /// let bytes = vec![0x89, 0x50, 0x4E, 0x47];
2521    /// let result = ReadResourceResult::blob_with_mime("file://image.png", &bytes, "image/png");
2522    /// ```
2523    pub fn blob_with_mime(
2524        uri: impl Into<String>,
2525        bytes: &[u8],
2526        mime_type: impl Into<String>,
2527    ) -> Self {
2528        use base64::Engine;
2529        let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
2530        Self {
2531            contents: vec![ResourceContent {
2532                uri: uri.into(),
2533                mime_type: Some(mime_type.into()),
2534                text: None,
2535                blob: Some(encoded),
2536                meta: None,
2537            }],
2538            meta: None,
2539        }
2540    }
2541
2542    /// Get the text from the first content item.
2543    ///
2544    /// Returns `None` if there are no contents or the first item has no text.
2545    ///
2546    /// # Example
2547    ///
2548    /// ```rust
2549    /// use tower_mcp_types::ReadResourceResult;
2550    ///
2551    /// let result = ReadResourceResult::text("file://readme.md", "# Hello");
2552    /// assert_eq!(result.first_text(), Some("# Hello"));
2553    /// ```
2554    pub fn first_text(&self) -> Option<&str> {
2555        self.contents.first().and_then(|c| c.text.as_deref())
2556    }
2557
2558    /// Get the URI from the first content item.
2559    ///
2560    /// Returns `None` if there are no contents.
2561    ///
2562    /// # Example
2563    ///
2564    /// ```rust
2565    /// use tower_mcp_types::ReadResourceResult;
2566    ///
2567    /// let result = ReadResourceResult::text("file://readme.md", "# Hello");
2568    /// assert_eq!(result.first_uri(), Some("file://readme.md"));
2569    /// ```
2570    pub fn first_uri(&self) -> Option<&str> {
2571        self.contents.first().map(|c| c.uri.as_str())
2572    }
2573
2574    /// Parse the first text content as a JSON [`Value`].
2575    ///
2576    /// Returns `None` if there are no contents or the first item has no text.
2577    ///
2578    /// # Example
2579    ///
2580    /// ```rust
2581    /// use tower_mcp_types::ReadResourceResult;
2582    /// use serde_json::json;
2583    ///
2584    /// let result = ReadResourceResult::json("data://config", &json!({"key": "value"}));
2585    /// let value = result.as_json().unwrap().unwrap();
2586    /// assert_eq!(value["key"], "value");
2587    /// ```
2588    pub fn as_json(&self) -> Option<Result<Value, serde_json::Error>> {
2589        self.first_text().map(serde_json::from_str)
2590    }
2591
2592    /// Deserialize the first text content into a typed value.
2593    ///
2594    /// Returns `None` if there are no contents or the first item has no text.
2595    ///
2596    /// # Example
2597    ///
2598    /// ```rust
2599    /// use tower_mcp_types::ReadResourceResult;
2600    /// use serde::Deserialize;
2601    /// use serde_json::json;
2602    ///
2603    /// #[derive(Debug, Deserialize, PartialEq)]
2604    /// struct Config { key: String }
2605    ///
2606    /// let result = ReadResourceResult::json("data://config", &json!({"key": "value"}));
2607    /// let config: Config = result.deserialize().unwrap().unwrap();
2608    /// assert_eq!(config.key, "value");
2609    /// ```
2610    pub fn deserialize<T: DeserializeOwned>(&self) -> Option<Result<T, serde_json::Error>> {
2611        self.first_text().map(serde_json::from_str)
2612    }
2613}
2614
2615#[derive(Debug, Clone, Deserialize)]
2616pub struct SubscribeResourceParams {
2617    pub uri: String,
2618    /// Optional protocol-level metadata
2619    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2620    pub meta: Option<RequestMeta>,
2621}
2622
2623#[derive(Debug, Clone, Deserialize)]
2624pub struct UnsubscribeResourceParams {
2625    pub uri: String,
2626    /// Optional protocol-level metadata
2627    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2628    pub meta: Option<RequestMeta>,
2629}
2630
2631/// Parameters for listing resource templates
2632#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2633pub struct ListResourceTemplatesParams {
2634    /// Pagination cursor from previous response
2635    #[serde(default)]
2636    pub cursor: Option<String>,
2637    /// Optional protocol-level metadata
2638    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2639    pub meta: Option<RequestMeta>,
2640}
2641
2642/// Result of listing resource templates
2643#[derive(Debug, Clone, Serialize, Deserialize)]
2644#[serde(rename_all = "camelCase")]
2645pub struct ListResourceTemplatesResult {
2646    /// Available resource templates
2647    pub resource_templates: Vec<ResourceTemplateDefinition>,
2648    /// Cursor for next page (if more templates available)
2649    #[serde(skip_serializing_if = "Option::is_none")]
2650    pub next_cursor: Option<String>,
2651    /// Optional protocol-level metadata
2652    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2653    pub meta: Option<Value>,
2654}
2655
2656/// Definition of a resource template as returned by resources/templates/list
2657///
2658/// Resource templates allow servers to expose parameterized resources using
2659/// [URI templates (RFC 6570)](https://datatracker.ietf.org/doc/html/rfc6570).
2660///
2661/// # Example
2662///
2663/// ```json
2664/// {
2665///     "uriTemplate": "file:///{path}",
2666///     "name": "Project Files",
2667///     "description": "Access files in the project directory",
2668///     "mimeType": "application/octet-stream"
2669/// }
2670/// ```
2671#[derive(Debug, Clone, Serialize, Deserialize)]
2672#[serde(rename_all = "camelCase")]
2673pub struct ResourceTemplateDefinition {
2674    /// URI template following RFC 6570 (e.g., `file:///{path}`)
2675    pub uri_template: String,
2676    /// Human-readable name for this template
2677    pub name: String,
2678    /// Human-readable title for display purposes
2679    #[serde(skip_serializing_if = "Option::is_none")]
2680    pub title: Option<String>,
2681    /// Description of what resources this template provides
2682    #[serde(skip_serializing_if = "Option::is_none")]
2683    pub description: Option<String>,
2684    /// MIME type hint for resources from this template
2685    #[serde(skip_serializing_if = "Option::is_none")]
2686    pub mime_type: Option<String>,
2687    /// Optional icons for display in user interfaces
2688    #[serde(skip_serializing_if = "Option::is_none")]
2689    pub icons: Option<Vec<ToolIcon>>,
2690    /// Annotations for this resource template (audience, priority hints)
2691    #[serde(skip_serializing_if = "Option::is_none")]
2692    pub annotations: Option<ContentAnnotations>,
2693    /// Arguments accepted by this template for URI expansion
2694    #[serde(default, skip_serializing_if = "Vec::is_empty")]
2695    pub arguments: Vec<PromptArgument>,
2696    /// Optional protocol-level metadata
2697    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2698    pub meta: Option<Value>,
2699}
2700
2701// =============================================================================
2702// Prompts
2703// =============================================================================
2704
2705#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2706pub struct ListPromptsParams {
2707    #[serde(default, skip_serializing_if = "Option::is_none")]
2708    pub cursor: Option<String>,
2709    /// Optional protocol-level metadata
2710    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2711    pub meta: Option<RequestMeta>,
2712}
2713
2714#[derive(Debug, Clone, Serialize, Deserialize)]
2715#[serde(rename_all = "camelCase")]
2716pub struct ListPromptsResult {
2717    pub prompts: Vec<PromptDefinition>,
2718    #[serde(default, skip_serializing_if = "Option::is_none")]
2719    pub next_cursor: Option<String>,
2720    /// Optional protocol-level metadata
2721    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2722    pub meta: Option<Value>,
2723}
2724
2725#[derive(Debug, Clone, Serialize, Deserialize)]
2726pub struct PromptDefinition {
2727    pub name: String,
2728    /// Human-readable title for display purposes
2729    #[serde(skip_serializing_if = "Option::is_none")]
2730    pub title: Option<String>,
2731    #[serde(skip_serializing_if = "Option::is_none")]
2732    pub description: Option<String>,
2733    /// Optional icons for display in user interfaces
2734    #[serde(skip_serializing_if = "Option::is_none")]
2735    pub icons: Option<Vec<ToolIcon>>,
2736    #[serde(default, skip_serializing_if = "Vec::is_empty")]
2737    pub arguments: Vec<PromptArgument>,
2738    /// Optional protocol-level metadata
2739    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2740    pub meta: Option<Value>,
2741}
2742
2743#[derive(Debug, Clone, Serialize, Deserialize)]
2744pub struct PromptArgument {
2745    pub name: String,
2746    #[serde(skip_serializing_if = "Option::is_none")]
2747    pub description: Option<String>,
2748    #[serde(default)]
2749    pub required: bool,
2750}
2751
2752#[derive(Debug, Clone, Serialize, Deserialize)]
2753pub struct GetPromptParams {
2754    pub name: String,
2755    #[serde(default)]
2756    pub arguments: std::collections::HashMap<String, String>,
2757    /// Optional protocol-level metadata
2758    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2759    pub meta: Option<RequestMeta>,
2760}
2761
2762#[derive(Debug, Clone, Serialize, Deserialize)]
2763/// The result of a prompts/get request.
2764///
2765/// Contains a list of messages that form the prompt, along with an optional
2766/// description. Messages can include text, images, and embedded resources.
2767///
2768/// # Example: prompt with image content
2769///
2770/// ```rust
2771/// use tower_mcp_types::protocol::{
2772///     GetPromptResult, PromptMessage, PromptRole, Content,
2773/// };
2774/// use base64::Engine;
2775///
2776/// let image_data = base64::engine::general_purpose::STANDARD.encode(b"fake-png");
2777///
2778/// let result = GetPromptResult {
2779///     description: Some("Analyze this image".to_string()),
2780///     messages: vec![
2781///         PromptMessage {
2782///             role: PromptRole::User,
2783///             content: Content::Image {
2784///                 data: image_data,
2785///                 mime_type: "image/png".to_string(),
2786///                 annotations: None,
2787///                 meta: None,
2788///             },
2789///             meta: None,
2790///         },
2791///     ],
2792///     meta: None,
2793/// };
2794/// assert_eq!(result.messages.len(), 1);
2795/// ```
2796///
2797/// # Example: prompt with embedded resource
2798///
2799/// ```rust
2800/// use tower_mcp_types::protocol::{
2801///     GetPromptResult, PromptMessage, PromptRole, Content, ResourceContent,
2802/// };
2803///
2804/// let result = GetPromptResult {
2805///     description: Some("Review this file".to_string()),
2806///     messages: vec![
2807///         PromptMessage {
2808///             role: PromptRole::User,
2809///             content: Content::Resource {
2810///                 resource: ResourceContent {
2811///                     uri: "file:///src/main.rs".to_string(),
2812///                     mime_type: Some("text/x-rust".to_string()),
2813///                     text: Some("fn main() {}".to_string()),
2814///                     blob: None,
2815///                     meta: None,
2816///                 },
2817///                 annotations: None,
2818///                 meta: None,
2819///             },
2820///             meta: None,
2821///         },
2822///     ],
2823///     meta: None,
2824/// };
2825/// assert_eq!(result.messages.len(), 1);
2826/// ```
2827pub struct GetPromptResult {
2828    #[serde(default, skip_serializing_if = "Option::is_none")]
2829    pub description: Option<String>,
2830    pub messages: Vec<PromptMessage>,
2831    /// Optional protocol-level metadata
2832    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2833    pub meta: Option<Value>,
2834}
2835
2836impl GetPromptResult {
2837    /// Create a result with a single user message.
2838    ///
2839    /// # Example
2840    ///
2841    /// ```rust
2842    /// use tower_mcp_types::GetPromptResult;
2843    ///
2844    /// let result = GetPromptResult::user_message("Please analyze this code.");
2845    /// ```
2846    pub fn user_message(text: impl Into<String>) -> Self {
2847        Self {
2848            description: None,
2849            messages: vec![PromptMessage {
2850                role: PromptRole::User,
2851                content: Content::Text {
2852                    text: text.into(),
2853                    annotations: None,
2854                    meta: None,
2855                },
2856                meta: None,
2857            }],
2858            meta: None,
2859        }
2860    }
2861
2862    /// Create a result with a single user message and description.
2863    ///
2864    /// # Example
2865    ///
2866    /// ```rust
2867    /// use tower_mcp_types::GetPromptResult;
2868    ///
2869    /// let result = GetPromptResult::user_message_with_description(
2870    ///     "Please analyze this code.",
2871    ///     "Code analysis prompt"
2872    /// );
2873    /// ```
2874    pub fn user_message_with_description(
2875        text: impl Into<String>,
2876        description: impl Into<String>,
2877    ) -> Self {
2878        Self {
2879            description: Some(description.into()),
2880            messages: vec![PromptMessage {
2881                role: PromptRole::User,
2882                content: Content::Text {
2883                    text: text.into(),
2884                    annotations: None,
2885                    meta: None,
2886                },
2887                meta: None,
2888            }],
2889            meta: None,
2890        }
2891    }
2892
2893    /// Create a result with a single assistant message.
2894    ///
2895    /// # Example
2896    ///
2897    /// ```rust
2898    /// use tower_mcp_types::GetPromptResult;
2899    ///
2900    /// let result = GetPromptResult::assistant_message("Here is my analysis...");
2901    /// ```
2902    pub fn assistant_message(text: impl Into<String>) -> Self {
2903        Self {
2904            description: None,
2905            messages: vec![PromptMessage {
2906                role: PromptRole::Assistant,
2907                content: Content::Text {
2908                    text: text.into(),
2909                    annotations: None,
2910                    meta: None,
2911                },
2912                meta: None,
2913            }],
2914            meta: None,
2915        }
2916    }
2917
2918    /// Create a builder for constructing prompts with multiple messages.
2919    ///
2920    /// # Example
2921    ///
2922    /// ```rust
2923    /// use tower_mcp_types::GetPromptResult;
2924    ///
2925    /// let result = GetPromptResult::builder()
2926    ///     .description("Multi-turn conversation prompt")
2927    ///     .user("What is the weather today?")
2928    ///     .assistant("I don't have access to weather data, but I can help you find it.")
2929    ///     .user("Where should I look?")
2930    ///     .build();
2931    /// ```
2932    pub fn builder() -> GetPromptResultBuilder {
2933        GetPromptResultBuilder::new()
2934    }
2935
2936    /// Get the text from the first message's content.
2937    ///
2938    /// Returns `None` if there are no messages or the first message
2939    /// does not contain text content.
2940    ///
2941    /// # Example
2942    ///
2943    /// ```rust
2944    /// use tower_mcp_types::GetPromptResult;
2945    ///
2946    /// let result = GetPromptResult::user_message("Analyze this code.");
2947    /// assert_eq!(result.first_message_text(), Some("Analyze this code."));
2948    /// ```
2949    pub fn first_message_text(&self) -> Option<&str> {
2950        self.messages.first().and_then(|m| m.content.as_text())
2951    }
2952
2953    /// Parse the first message text as a JSON [`Value`].
2954    ///
2955    /// Returns `None` if there are no messages or the first message
2956    /// does not contain text content.
2957    ///
2958    /// # Example
2959    ///
2960    /// ```rust
2961    /// use tower_mcp_types::GetPromptResult;
2962    ///
2963    /// let result = GetPromptResult::user_message(r#"{"key": "value"}"#);
2964    /// let value = result.as_json().unwrap().unwrap();
2965    /// assert_eq!(value["key"], "value");
2966    /// ```
2967    pub fn as_json(&self) -> Option<Result<Value, serde_json::Error>> {
2968        self.first_message_text().map(serde_json::from_str)
2969    }
2970
2971    /// Deserialize the first message text into a typed value.
2972    ///
2973    /// Returns `None` if there are no messages or the first message
2974    /// does not contain text content.
2975    ///
2976    /// # Example
2977    ///
2978    /// ```rust
2979    /// use tower_mcp_types::GetPromptResult;
2980    /// use serde::Deserialize;
2981    ///
2982    /// #[derive(Debug, Deserialize, PartialEq)]
2983    /// struct Params { key: String }
2984    ///
2985    /// let result = GetPromptResult::user_message(r#"{"key": "value"}"#);
2986    /// let params: Params = result.deserialize().unwrap().unwrap();
2987    /// assert_eq!(params.key, "value");
2988    /// ```
2989    pub fn deserialize<T: DeserializeOwned>(&self) -> Option<Result<T, serde_json::Error>> {
2990        self.first_message_text().map(serde_json::from_str)
2991    }
2992}
2993
2994/// Builder for constructing [`GetPromptResult`] with multiple messages.
2995#[derive(Debug, Clone, Default)]
2996pub struct GetPromptResultBuilder {
2997    description: Option<String>,
2998    messages: Vec<PromptMessage>,
2999}
3000
3001impl GetPromptResultBuilder {
3002    /// Create a new builder.
3003    pub fn new() -> Self {
3004        Self::default()
3005    }
3006
3007    /// Set the prompt description.
3008    pub fn description(mut self, description: impl Into<String>) -> Self {
3009        self.description = Some(description.into());
3010        self
3011    }
3012
3013    /// Add a user message.
3014    pub fn user(mut self, text: impl Into<String>) -> Self {
3015        self.messages.push(PromptMessage {
3016            role: PromptRole::User,
3017            content: Content::Text {
3018                text: text.into(),
3019                annotations: None,
3020                meta: None,
3021            },
3022            meta: None,
3023        });
3024        self
3025    }
3026
3027    /// Add an assistant message.
3028    pub fn assistant(mut self, text: impl Into<String>) -> Self {
3029        self.messages.push(PromptMessage {
3030            role: PromptRole::Assistant,
3031            content: Content::Text {
3032                text: text.into(),
3033                annotations: None,
3034                meta: None,
3035            },
3036            meta: None,
3037        });
3038        self
3039    }
3040
3041    /// Build the final result.
3042    pub fn build(self) -> GetPromptResult {
3043        GetPromptResult {
3044            description: self.description,
3045            messages: self.messages,
3046            meta: None,
3047        }
3048    }
3049}
3050
3051#[derive(Debug, Clone, Serialize, Deserialize)]
3052pub struct PromptMessage {
3053    pub role: PromptRole,
3054    pub content: Content,
3055    /// Optional protocol-level metadata
3056    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3057    pub meta: Option<Value>,
3058}
3059
3060#[derive(Debug, Clone, Serialize, Deserialize)]
3061#[serde(rename_all = "lowercase")]
3062#[non_exhaustive]
3063pub enum PromptRole {
3064    User,
3065    Assistant,
3066}
3067
3068// =============================================================================
3069// Tasks (async operations)
3070// =============================================================================
3071
3072/// Task support mode for tool execution
3073#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
3074#[serde(rename_all = "camelCase")]
3075#[non_exhaustive]
3076pub enum TaskSupportMode {
3077    /// Task execution is required (tool MUST be called with task params)
3078    Required,
3079    /// Task execution is optional (tool MAY be called with or without task params)
3080    Optional,
3081    /// Task execution is forbidden (tool MUST NOT be called with task params)
3082    #[default]
3083    Forbidden,
3084}
3085
3086/// Execution metadata for a tool definition
3087#[derive(Debug, Clone, Serialize, Deserialize)]
3088#[serde(rename_all = "camelCase")]
3089pub struct ToolExecution {
3090    /// Whether the tool supports task-augmented requests (defaults to "forbidden")
3091    #[serde(default, skip_serializing_if = "Option::is_none")]
3092    pub task_support: Option<TaskSupportMode>,
3093}
3094
3095/// Parameters for task-augmented requests (the `task` field in CallToolParams)
3096#[derive(Debug, Clone, Serialize, Deserialize)]
3097#[serde(rename_all = "camelCase")]
3098pub struct TaskRequestParams {
3099    /// Time-to-live for the task in milliseconds
3100    #[serde(default, skip_serializing_if = "Option::is_none")]
3101    pub ttl: Option<u64>,
3102}
3103
3104/// Status of an async task
3105#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
3106#[serde(rename_all = "snake_case")]
3107#[non_exhaustive]
3108pub enum TaskStatus {
3109    /// Task is actively being processed
3110    Working,
3111    /// Task requires user input to continue
3112    InputRequired,
3113    /// Task completed successfully
3114    Completed,
3115    /// Task failed with an error
3116    Failed,
3117    /// Task was cancelled by user request
3118    Cancelled,
3119}
3120
3121impl std::fmt::Display for TaskStatus {
3122    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3123        match self {
3124            TaskStatus::Working => write!(f, "working"),
3125            TaskStatus::InputRequired => write!(f, "input_required"),
3126            TaskStatus::Completed => write!(f, "completed"),
3127            TaskStatus::Failed => write!(f, "failed"),
3128            TaskStatus::Cancelled => write!(f, "cancelled"),
3129        }
3130    }
3131}
3132
3133impl TaskStatus {
3134    /// Check if this status represents a terminal state
3135    pub fn is_terminal(&self) -> bool {
3136        matches!(
3137            self,
3138            TaskStatus::Completed | TaskStatus::Failed | TaskStatus::Cancelled
3139        )
3140    }
3141}
3142
3143/// Task object matching the MCP 2025-11-25 spec
3144#[derive(Debug, Clone, Serialize, Deserialize)]
3145#[serde(rename_all = "camelCase")]
3146pub struct TaskObject {
3147    /// Unique task identifier
3148    pub task_id: String,
3149    /// Current task status
3150    pub status: TaskStatus,
3151    /// Human-readable status message
3152    #[serde(skip_serializing_if = "Option::is_none")]
3153    pub status_message: Option<String>,
3154    /// ISO 8601 timestamp when the task was created
3155    pub created_at: String,
3156    /// ISO 8601 timestamp when the task was last updated
3157    pub last_updated_at: String,
3158    /// Time-to-live in milliseconds, null for unlimited
3159    pub ttl: Option<u64>,
3160    /// Suggested polling interval in milliseconds
3161    #[serde(skip_serializing_if = "Option::is_none")]
3162    pub poll_interval: Option<u64>,
3163    /// Optional protocol-level metadata
3164    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3165    pub meta: Option<Value>,
3166}
3167
3168/// Backwards-compatible alias for TaskObject
3169#[deprecated(note = "Use TaskObject instead")]
3170pub type TaskInfo = TaskObject;
3171
3172/// Result of creating a task (returned when tools/call includes task params)
3173#[derive(Debug, Clone, Serialize, Deserialize)]
3174#[serde(rename_all = "camelCase")]
3175pub struct CreateTaskResult {
3176    /// The created task object
3177    pub task: TaskObject,
3178    /// Optional protocol-level metadata
3179    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3180    pub meta: Option<Value>,
3181}
3182
3183/// Parameters for listing tasks
3184#[derive(Debug, Clone, Default, Deserialize)]
3185#[serde(rename_all = "camelCase")]
3186pub struct ListTasksParams {
3187    /// Filter by status (optional)
3188    #[serde(default)]
3189    pub status: Option<TaskStatus>,
3190    /// Pagination cursor
3191    #[serde(default)]
3192    pub cursor: Option<String>,
3193    /// Optional protocol-level metadata
3194    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3195    pub meta: Option<RequestMeta>,
3196}
3197
3198/// Result of listing tasks
3199#[derive(Debug, Clone, Serialize, Deserialize)]
3200#[serde(rename_all = "camelCase")]
3201pub struct ListTasksResult {
3202    /// List of tasks
3203    pub tasks: Vec<TaskObject>,
3204    /// Next cursor for pagination
3205    #[serde(skip_serializing_if = "Option::is_none")]
3206    pub next_cursor: Option<String>,
3207}
3208
3209/// Parameters for getting task info
3210#[derive(Debug, Clone, Deserialize)]
3211#[serde(rename_all = "camelCase")]
3212pub struct GetTaskInfoParams {
3213    /// Task ID to query
3214    pub task_id: String,
3215    /// Optional protocol-level metadata
3216    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3217    pub meta: Option<RequestMeta>,
3218}
3219
3220/// Parameters for getting task result
3221#[derive(Debug, Clone, Deserialize)]
3222#[serde(rename_all = "camelCase")]
3223pub struct GetTaskResultParams {
3224    /// Task ID to get result for
3225    pub task_id: String,
3226    /// Optional protocol-level metadata
3227    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3228    pub meta: Option<RequestMeta>,
3229}
3230
3231/// Parameters for cancelling a task
3232#[derive(Debug, Clone, Deserialize)]
3233#[serde(rename_all = "camelCase")]
3234pub struct CancelTaskParams {
3235    /// Task ID to cancel
3236    pub task_id: String,
3237    /// Optional reason for cancellation
3238    #[serde(default)]
3239    pub reason: Option<String>,
3240    /// Optional protocol-level metadata
3241    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3242    pub meta: Option<RequestMeta>,
3243}
3244
3245/// Notification params when task status changes
3246///
3247/// Per the spec, `TaskStatusNotificationParams = NotificationParams & Task`,
3248/// so this includes all fields from the Task object.
3249#[derive(Debug, Clone, Serialize, Deserialize)]
3250#[serde(rename_all = "camelCase")]
3251pub struct TaskStatusParams {
3252    /// Task ID
3253    pub task_id: String,
3254    /// New status
3255    pub status: TaskStatus,
3256    /// Human-readable status message
3257    #[serde(skip_serializing_if = "Option::is_none")]
3258    pub status_message: Option<String>,
3259    /// ISO 8601 timestamp when the task was created
3260    pub created_at: String,
3261    /// ISO 8601 timestamp when the task was last updated
3262    pub last_updated_at: String,
3263    /// Time-to-live in milliseconds, null for unlimited
3264    pub ttl: Option<u64>,
3265    /// Suggested polling interval in milliseconds
3266    #[serde(skip_serializing_if = "Option::is_none")]
3267    pub poll_interval: Option<u64>,
3268    /// Optional protocol-level metadata
3269    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3270    pub meta: Option<Value>,
3271}
3272
3273/// Backwards-compatible alias
3274pub type TaskStatusChangedParams = TaskStatusParams;
3275
3276// =============================================================================
3277// Elicitation (server-to-client user input requests)
3278// =============================================================================
3279
3280/// Parameters for form-based elicitation request
3281#[derive(Debug, Clone, Serialize, Deserialize)]
3282#[serde(rename_all = "camelCase")]
3283pub struct ElicitFormParams {
3284    /// The elicitation mode (defaults to form if not specified)
3285    #[serde(default, skip_serializing_if = "Option::is_none")]
3286    pub mode: Option<ElicitMode>,
3287    /// Message to present to the user explaining what information is needed
3288    pub message: String,
3289    /// Schema for the form fields (restricted subset of JSON Schema)
3290    pub requested_schema: ElicitFormSchema,
3291    /// Request metadata including progress token
3292    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3293    pub meta: Option<RequestMeta>,
3294}
3295
3296/// Parameters for URL-based elicitation request.
3297///
3298/// URL-based elicitation allows servers to direct users to an external URL
3299/// (e.g., an OAuth flow or payment page) and receive completion notification.
3300///
3301/// # Example
3302///
3303/// ```rust
3304/// use tower_mcp_types::protocol::{ElicitUrlParams, ElicitMode};
3305///
3306/// let params = ElicitUrlParams {
3307///     mode: Some(ElicitMode::Url),
3308///     elicitation_id: "auth-flow-123".to_string(),
3309///     message: "Please sign in to continue".to_string(),
3310///     url: "https://example.com/auth?session=abc".to_string(),
3311///     meta: None,
3312/// };
3313///
3314/// assert_eq!(params.url, "https://example.com/auth?session=abc");
3315/// ```
3316#[derive(Debug, Clone, Serialize, Deserialize)]
3317#[serde(rename_all = "camelCase")]
3318pub struct ElicitUrlParams {
3319    /// The elicitation mode (defaults to url if not specified)
3320    #[serde(default, skip_serializing_if = "Option::is_none")]
3321    pub mode: Option<ElicitMode>,
3322    /// Unique ID for this elicitation (opaque to client)
3323    pub elicitation_id: String,
3324    /// Message explaining why the user needs to navigate to the URL
3325    pub message: String,
3326    /// The URL the user should navigate to
3327    pub url: String,
3328    /// Request metadata including progress token
3329    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3330    pub meta: Option<RequestMeta>,
3331}
3332
3333/// Elicitation request parameters (union of form and URL modes)
3334#[derive(Debug, Clone, Serialize, Deserialize)]
3335#[serde(untagged)]
3336#[non_exhaustive]
3337pub enum ElicitRequestParams {
3338    Form(ElicitFormParams),
3339    Url(ElicitUrlParams),
3340}
3341
3342/// Elicitation mode
3343#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
3344#[serde(rename_all = "lowercase")]
3345#[non_exhaustive]
3346pub enum ElicitMode {
3347    /// Form-based elicitation with structured input
3348    Form,
3349    /// URL-based elicitation (out-of-band)
3350    Url,
3351}
3352
3353/// Restricted JSON Schema for elicitation forms.
3354///
3355/// Based on [JSON Schema 2020-12](https://json-schema.org/specification), but restricted
3356/// to a flat object with primitive-typed properties. Complex types (arrays, nested objects)
3357/// are not supported -- only `string`, `integer`, `number`, `boolean`, and `enum` fields.
3358///
3359/// The schema is validated by the client before submitting the form response.
3360/// Required fields must be present, and each value must match its declared type.
3361///
3362/// Use the builder methods to construct a schema with string, integer,
3363/// number, boolean, and enum fields, optionally with default values.
3364///
3365/// # Example
3366///
3367/// ```rust
3368/// use tower_mcp_types::protocol::ElicitFormSchema;
3369///
3370/// let schema = ElicitFormSchema::new()
3371///     .string_field("name", Some("Your full name"), true)
3372///     .string_field_with_default("greeting", Some("How to greet"), false, "Hello")
3373///     .integer_field("age", Some("Your age"), false)
3374///     .enum_field(
3375///         "role",
3376///         Some("Select your role"),
3377///         vec!["admin".into(), "user".into(), "guest".into()],
3378///         true,
3379///     )
3380///     .enum_field_with_default(
3381///         "theme",
3382///         Some("Color theme"),
3383///         false,
3384///         &["light", "dark", "auto"],
3385///         "auto",
3386///     )
3387///     .boolean_field("subscribe", Some("Subscribe to updates"), false);
3388///
3389/// assert_eq!(schema.required, vec!["name", "role"]);
3390/// assert_eq!(schema.properties.len(), 6);
3391/// ```
3392#[derive(Debug, Clone, Serialize, Deserialize)]
3393pub struct ElicitFormSchema {
3394    /// Must be "object"
3395    #[serde(rename = "type")]
3396    pub schema_type: String,
3397    /// Map of property names to their schema definitions
3398    pub properties: std::collections::HashMap<String, PrimitiveSchemaDefinition>,
3399    /// List of required property names
3400    #[serde(default, skip_serializing_if = "Vec::is_empty")]
3401    pub required: Vec<String>,
3402}
3403
3404impl ElicitFormSchema {
3405    /// Create a new form schema
3406    pub fn new() -> Self {
3407        Self {
3408            schema_type: "object".to_string(),
3409            properties: std::collections::HashMap::new(),
3410            required: Vec::new(),
3411        }
3412    }
3413
3414    /// Add a string field
3415    pub fn string_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
3416        self.properties.insert(
3417            name.to_string(),
3418            PrimitiveSchemaDefinition::String(StringSchema {
3419                schema_type: "string".to_string(),
3420                title: None,
3421                description: description.map(|s| s.to_string()),
3422                format: None,
3423                pattern: None,
3424                min_length: None,
3425                max_length: None,
3426                default: None,
3427            }),
3428        );
3429        if required {
3430            self.required.push(name.to_string());
3431        }
3432        self
3433    }
3434
3435    /// Add a string field with a default value
3436    pub fn string_field_with_default(
3437        mut self,
3438        name: &str,
3439        description: Option<&str>,
3440        required: bool,
3441        default: &str,
3442    ) -> Self {
3443        self.properties.insert(
3444            name.to_string(),
3445            PrimitiveSchemaDefinition::String(StringSchema {
3446                schema_type: "string".to_string(),
3447                title: None,
3448                description: description.map(|s| s.to_string()),
3449                format: None,
3450                pattern: None,
3451                min_length: None,
3452                max_length: None,
3453                default: Some(default.to_string()),
3454            }),
3455        );
3456        if required {
3457            self.required.push(name.to_string());
3458        }
3459        self
3460    }
3461
3462    /// Add an integer field
3463    pub fn integer_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
3464        self.properties.insert(
3465            name.to_string(),
3466            PrimitiveSchemaDefinition::Integer(IntegerSchema {
3467                schema_type: "integer".to_string(),
3468                title: None,
3469                description: description.map(|s| s.to_string()),
3470                minimum: None,
3471                maximum: None,
3472                default: None,
3473            }),
3474        );
3475        if required {
3476            self.required.push(name.to_string());
3477        }
3478        self
3479    }
3480
3481    /// Add an integer field with a default value
3482    pub fn integer_field_with_default(
3483        mut self,
3484        name: &str,
3485        description: Option<&str>,
3486        required: bool,
3487        default: i64,
3488    ) -> Self {
3489        self.properties.insert(
3490            name.to_string(),
3491            PrimitiveSchemaDefinition::Integer(IntegerSchema {
3492                schema_type: "integer".to_string(),
3493                title: None,
3494                description: description.map(|s| s.to_string()),
3495                minimum: None,
3496                maximum: None,
3497                default: Some(default),
3498            }),
3499        );
3500        if required {
3501            self.required.push(name.to_string());
3502        }
3503        self
3504    }
3505
3506    /// Add a number field
3507    pub fn number_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
3508        self.properties.insert(
3509            name.to_string(),
3510            PrimitiveSchemaDefinition::Number(NumberSchema {
3511                schema_type: "number".to_string(),
3512                title: None,
3513                description: description.map(|s| s.to_string()),
3514                minimum: None,
3515                maximum: None,
3516                default: None,
3517            }),
3518        );
3519        if required {
3520            self.required.push(name.to_string());
3521        }
3522        self
3523    }
3524
3525    /// Add a number field with a default value
3526    pub fn number_field_with_default(
3527        mut self,
3528        name: &str,
3529        description: Option<&str>,
3530        required: bool,
3531        default: f64,
3532    ) -> Self {
3533        self.properties.insert(
3534            name.to_string(),
3535            PrimitiveSchemaDefinition::Number(NumberSchema {
3536                schema_type: "number".to_string(),
3537                title: None,
3538                description: description.map(|s| s.to_string()),
3539                minimum: None,
3540                maximum: None,
3541                default: Some(default),
3542            }),
3543        );
3544        if required {
3545            self.required.push(name.to_string());
3546        }
3547        self
3548    }
3549
3550    /// Add a boolean field
3551    pub fn boolean_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
3552        self.properties.insert(
3553            name.to_string(),
3554            PrimitiveSchemaDefinition::Boolean(BooleanSchema {
3555                schema_type: "boolean".to_string(),
3556                title: None,
3557                description: description.map(|s| s.to_string()),
3558                default: None,
3559            }),
3560        );
3561        if required {
3562            self.required.push(name.to_string());
3563        }
3564        self
3565    }
3566
3567    /// Add a boolean field with a default value
3568    pub fn boolean_field_with_default(
3569        mut self,
3570        name: &str,
3571        description: Option<&str>,
3572        required: bool,
3573        default: bool,
3574    ) -> Self {
3575        self.properties.insert(
3576            name.to_string(),
3577            PrimitiveSchemaDefinition::Boolean(BooleanSchema {
3578                schema_type: "boolean".to_string(),
3579                title: None,
3580                description: description.map(|s| s.to_string()),
3581                default: Some(default),
3582            }),
3583        );
3584        if required {
3585            self.required.push(name.to_string());
3586        }
3587        self
3588    }
3589
3590    /// Add a single-select enum field
3591    pub fn enum_field(
3592        mut self,
3593        name: &str,
3594        description: Option<&str>,
3595        options: Vec<String>,
3596        required: bool,
3597    ) -> Self {
3598        self.properties.insert(
3599            name.to_string(),
3600            PrimitiveSchemaDefinition::SingleSelectEnum(SingleSelectEnumSchema {
3601                schema_type: "string".to_string(),
3602                title: None,
3603                description: description.map(|s| s.to_string()),
3604                enum_values: options,
3605                default: None,
3606            }),
3607        );
3608        if required {
3609            self.required.push(name.to_string());
3610        }
3611        self
3612    }
3613
3614    /// Add a single-select enum field with a default value
3615    pub fn enum_field_with_default(
3616        mut self,
3617        name: &str,
3618        description: Option<&str>,
3619        required: bool,
3620        options: &[&str],
3621        default: &str,
3622    ) -> Self {
3623        self.properties.insert(
3624            name.to_string(),
3625            PrimitiveSchemaDefinition::SingleSelectEnum(SingleSelectEnumSchema {
3626                schema_type: "string".to_string(),
3627                title: None,
3628                description: description.map(|s| s.to_string()),
3629                enum_values: options.iter().map(|s| s.to_string()).collect(),
3630                default: Some(default.to_string()),
3631            }),
3632        );
3633        if required {
3634            self.required.push(name.to_string());
3635        }
3636        self
3637    }
3638
3639    /// Add a raw JSON schema field
3640    ///
3641    /// Use this for advanced schema features not covered by the typed builders.
3642    pub fn raw_field(mut self, name: &str, schema: serde_json::Value, required: bool) -> Self {
3643        self.properties
3644            .insert(name.to_string(), PrimitiveSchemaDefinition::Raw(schema));
3645        if required {
3646            self.required.push(name.to_string());
3647        }
3648        self
3649    }
3650}
3651
3652impl Default for ElicitFormSchema {
3653    fn default() -> Self {
3654        Self::new()
3655    }
3656}
3657
3658/// Primitive schema definition for form fields
3659#[derive(Debug, Clone, Serialize, Deserialize)]
3660#[serde(untagged)]
3661#[non_exhaustive]
3662pub enum PrimitiveSchemaDefinition {
3663    /// String field
3664    String(StringSchema),
3665    /// Integer field
3666    Integer(IntegerSchema),
3667    /// Number (floating-point) field
3668    Number(NumberSchema),
3669    /// Boolean field
3670    Boolean(BooleanSchema),
3671    /// Single-select enum field
3672    SingleSelectEnum(SingleSelectEnumSchema),
3673    /// Multi-select enum field
3674    MultiSelectEnum(MultiSelectEnumSchema),
3675    /// Raw JSON schema (for advanced/custom schemas)
3676    Raw(serde_json::Value),
3677}
3678
3679/// String field schema
3680#[derive(Debug, Clone, Serialize, Deserialize)]
3681#[serde(rename_all = "camelCase")]
3682pub struct StringSchema {
3683    #[serde(rename = "type")]
3684    pub schema_type: String,
3685    /// Human-readable title for this field
3686    #[serde(skip_serializing_if = "Option::is_none")]
3687    pub title: Option<String>,
3688    #[serde(skip_serializing_if = "Option::is_none")]
3689    pub description: Option<String>,
3690    #[serde(skip_serializing_if = "Option::is_none")]
3691    pub format: Option<String>,
3692    /// Regex pattern for validation
3693    #[serde(skip_serializing_if = "Option::is_none")]
3694    pub pattern: Option<String>,
3695    #[serde(skip_serializing_if = "Option::is_none")]
3696    pub min_length: Option<u64>,
3697    #[serde(skip_serializing_if = "Option::is_none")]
3698    pub max_length: Option<u64>,
3699    /// Default value for this field
3700    #[serde(skip_serializing_if = "Option::is_none")]
3701    pub default: Option<String>,
3702}
3703
3704/// Integer field schema
3705#[derive(Debug, Clone, Serialize, Deserialize)]
3706#[serde(rename_all = "camelCase")]
3707pub struct IntegerSchema {
3708    #[serde(rename = "type")]
3709    pub schema_type: String,
3710    /// Human-readable title for this field
3711    #[serde(skip_serializing_if = "Option::is_none")]
3712    pub title: Option<String>,
3713    #[serde(skip_serializing_if = "Option::is_none")]
3714    pub description: Option<String>,
3715    #[serde(skip_serializing_if = "Option::is_none")]
3716    pub minimum: Option<i64>,
3717    #[serde(skip_serializing_if = "Option::is_none")]
3718    pub maximum: Option<i64>,
3719    /// Default value for this field
3720    #[serde(skip_serializing_if = "Option::is_none")]
3721    pub default: Option<i64>,
3722}
3723
3724/// Number field schema
3725#[derive(Debug, Clone, Serialize, Deserialize)]
3726#[serde(rename_all = "camelCase")]
3727pub struct NumberSchema {
3728    #[serde(rename = "type")]
3729    pub schema_type: String,
3730    /// Human-readable title for this field
3731    #[serde(skip_serializing_if = "Option::is_none")]
3732    pub title: Option<String>,
3733    #[serde(skip_serializing_if = "Option::is_none")]
3734    pub description: Option<String>,
3735    #[serde(skip_serializing_if = "Option::is_none")]
3736    pub minimum: Option<f64>,
3737    #[serde(skip_serializing_if = "Option::is_none")]
3738    pub maximum: Option<f64>,
3739    /// Default value for this field
3740    #[serde(skip_serializing_if = "Option::is_none")]
3741    pub default: Option<f64>,
3742}
3743
3744/// Boolean field schema
3745#[derive(Debug, Clone, Serialize, Deserialize)]
3746#[serde(rename_all = "camelCase")]
3747pub struct BooleanSchema {
3748    #[serde(rename = "type")]
3749    pub schema_type: String,
3750    /// Human-readable title for this field
3751    #[serde(skip_serializing_if = "Option::is_none")]
3752    pub title: Option<String>,
3753    #[serde(skip_serializing_if = "Option::is_none")]
3754    pub description: Option<String>,
3755    /// Default value for this field
3756    #[serde(skip_serializing_if = "Option::is_none")]
3757    pub default: Option<bool>,
3758}
3759
3760/// Single-select enum schema
3761#[derive(Debug, Clone, Serialize, Deserialize)]
3762#[serde(rename_all = "camelCase")]
3763pub struct SingleSelectEnumSchema {
3764    #[serde(rename = "type")]
3765    pub schema_type: String,
3766    /// Human-readable title for this field
3767    #[serde(skip_serializing_if = "Option::is_none")]
3768    pub title: Option<String>,
3769    #[serde(skip_serializing_if = "Option::is_none")]
3770    pub description: Option<String>,
3771    #[serde(rename = "enum")]
3772    pub enum_values: Vec<String>,
3773    /// Default value for this field
3774    #[serde(skip_serializing_if = "Option::is_none")]
3775    pub default: Option<String>,
3776}
3777
3778/// Multi-select enum schema
3779#[derive(Debug, Clone, Serialize, Deserialize)]
3780#[serde(rename_all = "camelCase")]
3781pub struct MultiSelectEnumSchema {
3782    #[serde(rename = "type")]
3783    pub schema_type: String,
3784    /// Human-readable title for this field
3785    #[serde(skip_serializing_if = "Option::is_none")]
3786    pub title: Option<String>,
3787    #[serde(skip_serializing_if = "Option::is_none")]
3788    pub description: Option<String>,
3789    pub items: MultiSelectEnumItems,
3790    #[serde(skip_serializing_if = "Option::is_none")]
3791    pub unique_items: Option<bool>,
3792    /// Default value for this field
3793    #[serde(skip_serializing_if = "Option::is_none")]
3794    pub default: Option<Vec<String>>,
3795}
3796
3797/// Items definition for multi-select enum
3798#[derive(Debug, Clone, Serialize, Deserialize)]
3799pub struct MultiSelectEnumItems {
3800    #[serde(rename = "type")]
3801    pub schema_type: String,
3802    #[serde(rename = "enum")]
3803    pub enum_values: Vec<String>,
3804}
3805
3806/// User action in response to elicitation
3807#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
3808#[serde(rename_all = "lowercase")]
3809#[non_exhaustive]
3810pub enum ElicitAction {
3811    /// User submitted the form/confirmed the action
3812    Accept,
3813    /// User explicitly declined the action
3814    Decline,
3815    /// User dismissed without making an explicit choice
3816    Cancel,
3817}
3818
3819/// Result of an elicitation request
3820#[derive(Debug, Clone, Serialize, Deserialize)]
3821pub struct ElicitResult {
3822    /// The user's action
3823    pub action: ElicitAction,
3824    /// Submitted form data (only present when action is Accept and mode was Form)
3825    #[serde(default, skip_serializing_if = "Option::is_none")]
3826    pub content: Option<std::collections::HashMap<String, ElicitFieldValue>>,
3827    /// Optional protocol-level metadata
3828    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3829    pub meta: Option<Value>,
3830}
3831
3832impl ElicitResult {
3833    /// Create an accept result with content
3834    pub fn accept(content: std::collections::HashMap<String, ElicitFieldValue>) -> Self {
3835        Self {
3836            action: ElicitAction::Accept,
3837            content: Some(content),
3838            meta: None,
3839        }
3840    }
3841
3842    /// Create a decline result
3843    pub fn decline() -> Self {
3844        Self {
3845            action: ElicitAction::Decline,
3846            content: None,
3847            meta: None,
3848        }
3849    }
3850
3851    /// Create a cancel result
3852    pub fn cancel() -> Self {
3853        Self {
3854            action: ElicitAction::Cancel,
3855            content: None,
3856            meta: None,
3857        }
3858    }
3859}
3860
3861/// Value from an elicitation form field
3862#[derive(Debug, Clone, Serialize, Deserialize)]
3863#[serde(untagged)]
3864#[non_exhaustive]
3865pub enum ElicitFieldValue {
3866    String(String),
3867    Number(f64),
3868    Integer(i64),
3869    Boolean(bool),
3870    StringArray(Vec<String>),
3871}
3872
3873/// Parameters for elicitation complete notification
3874#[derive(Debug, Clone, Serialize, Deserialize)]
3875#[serde(rename_all = "camelCase")]
3876pub struct ElicitationCompleteParams {
3877    /// The ID of the elicitation that completed
3878    pub elicitation_id: String,
3879    /// Optional protocol-level metadata
3880    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3881    pub meta: Option<Value>,
3882}
3883
3884// =============================================================================
3885// Common
3886// =============================================================================
3887
3888#[derive(Debug, Clone, Default, Serialize, Deserialize)]
3889pub struct EmptyResult {}
3890
3891// =============================================================================
3892// Parsing
3893// =============================================================================
3894
3895impl McpRequest {
3896    /// Parse from JSON-RPC request
3897    pub fn from_jsonrpc(req: &JsonRpcRequest) -> Result<Self, crate::error::Error> {
3898        let params = req
3899            .params
3900            .clone()
3901            .unwrap_or(Value::Object(Default::default()));
3902
3903        match req.method.as_str() {
3904            "initialize" => {
3905                let p: InitializeParams = serde_json::from_value(params)?;
3906                Ok(McpRequest::Initialize(p))
3907            }
3908            "tools/list" => {
3909                let p: ListToolsParams = serde_json::from_value(params).unwrap_or_default();
3910                Ok(McpRequest::ListTools(p))
3911            }
3912            "tools/call" => {
3913                let p: CallToolParams = serde_json::from_value(params)?;
3914                Ok(McpRequest::CallTool(p))
3915            }
3916            "resources/list" => {
3917                let p: ListResourcesParams = serde_json::from_value(params).unwrap_or_default();
3918                Ok(McpRequest::ListResources(p))
3919            }
3920            "resources/templates/list" => {
3921                let p: ListResourceTemplatesParams =
3922                    serde_json::from_value(params).unwrap_or_default();
3923                Ok(McpRequest::ListResourceTemplates(p))
3924            }
3925            "resources/read" => {
3926                let p: ReadResourceParams = serde_json::from_value(params)?;
3927                Ok(McpRequest::ReadResource(p))
3928            }
3929            "resources/subscribe" => {
3930                let p: SubscribeResourceParams = serde_json::from_value(params)?;
3931                Ok(McpRequest::SubscribeResource(p))
3932            }
3933            "resources/unsubscribe" => {
3934                let p: UnsubscribeResourceParams = serde_json::from_value(params)?;
3935                Ok(McpRequest::UnsubscribeResource(p))
3936            }
3937            "prompts/list" => {
3938                let p: ListPromptsParams = serde_json::from_value(params).unwrap_or_default();
3939                Ok(McpRequest::ListPrompts(p))
3940            }
3941            "prompts/get" => {
3942                let p: GetPromptParams = serde_json::from_value(params)?;
3943                Ok(McpRequest::GetPrompt(p))
3944            }
3945            "tasks/list" => {
3946                let p: ListTasksParams = serde_json::from_value(params).unwrap_or_default();
3947                Ok(McpRequest::ListTasks(p))
3948            }
3949            "tasks/get" => {
3950                let p: GetTaskInfoParams = serde_json::from_value(params)?;
3951                Ok(McpRequest::GetTaskInfo(p))
3952            }
3953            "tasks/result" => {
3954                let p: GetTaskResultParams = serde_json::from_value(params)?;
3955                Ok(McpRequest::GetTaskResult(p))
3956            }
3957            "tasks/cancel" => {
3958                let p: CancelTaskParams = serde_json::from_value(params)?;
3959                Ok(McpRequest::CancelTask(p))
3960            }
3961            "ping" => Ok(McpRequest::Ping),
3962            "logging/setLevel" => {
3963                let p: SetLogLevelParams = serde_json::from_value(params)?;
3964                Ok(McpRequest::SetLoggingLevel(p))
3965            }
3966            "completion/complete" => {
3967                let p: CompleteParams = serde_json::from_value(params)?;
3968                Ok(McpRequest::Complete(p))
3969            }
3970            method => Ok(McpRequest::Unknown {
3971                method: method.to_string(),
3972                params: req.params.clone(),
3973            }),
3974        }
3975    }
3976}
3977
3978impl McpNotification {
3979    /// Parse from JSON-RPC notification
3980    pub fn from_jsonrpc(notif: &JsonRpcNotification) -> Result<Self, crate::error::Error> {
3981        let params = notif
3982            .params
3983            .clone()
3984            .unwrap_or(Value::Object(Default::default()));
3985
3986        match notif.method.as_str() {
3987            notifications::INITIALIZED => Ok(McpNotification::Initialized),
3988            notifications::CANCELLED => {
3989                let p: CancelledParams = serde_json::from_value(params)?;
3990                Ok(McpNotification::Cancelled(p))
3991            }
3992            notifications::PROGRESS => {
3993                let p: ProgressParams = serde_json::from_value(params)?;
3994                Ok(McpNotification::Progress(p))
3995            }
3996            notifications::ROOTS_LIST_CHANGED => Ok(McpNotification::RootsListChanged),
3997            method => Ok(McpNotification::Unknown {
3998                method: method.to_string(),
3999                params: notif.params.clone(),
4000            }),
4001        }
4002    }
4003}
4004
4005#[cfg(test)]
4006mod tests {
4007    use super::*;
4008
4009    #[test]
4010    fn test_content_text_constructor() {
4011        let content = Content::text("hello world");
4012        assert_eq!(content.as_text(), Some("hello world"));
4013
4014        // Verify it creates a Text variant with no annotations
4015        match &content {
4016            Content::Text {
4017                text, annotations, ..
4018            } => {
4019                assert_eq!(text, "hello world");
4020                assert!(annotations.is_none());
4021            }
4022            _ => panic!("expected Content::Text"),
4023        }
4024
4025        // Works with String too
4026        let content = Content::text(String::from("owned"));
4027        assert_eq!(content.as_text(), Some("owned"));
4028    }
4029
4030    #[test]
4031    fn test_elicit_form_schema_builder() {
4032        let schema = ElicitFormSchema::new()
4033            .string_field("name", Some("Your name"), true)
4034            .number_field("age", Some("Your age"), false)
4035            .boolean_field("agree", Some("Do you agree?"), true)
4036            .enum_field(
4037                "color",
4038                Some("Favorite color"),
4039                vec!["red".to_string(), "green".to_string(), "blue".to_string()],
4040                false,
4041            );
4042
4043        assert_eq!(schema.schema_type, "object");
4044        assert_eq!(schema.properties.len(), 4);
4045        assert_eq!(schema.required.len(), 2);
4046        assert!(schema.required.contains(&"name".to_string()));
4047        assert!(schema.required.contains(&"agree".to_string()));
4048    }
4049
4050    #[test]
4051    fn test_elicit_form_schema_serialization() {
4052        let schema = ElicitFormSchema::new().string_field("username", Some("Enter username"), true);
4053
4054        let json = serde_json::to_value(&schema).unwrap();
4055        assert_eq!(json["type"], "object");
4056        assert!(json["properties"]["username"]["type"] == "string");
4057        assert!(
4058            json["required"]
4059                .as_array()
4060                .unwrap()
4061                .contains(&serde_json::json!("username"))
4062        );
4063    }
4064
4065    #[test]
4066    fn test_elicit_result_accept() {
4067        let mut content = std::collections::HashMap::new();
4068        content.insert(
4069            "name".to_string(),
4070            ElicitFieldValue::String("Alice".to_string()),
4071        );
4072        content.insert("age".to_string(), ElicitFieldValue::Integer(30));
4073
4074        let result = ElicitResult::accept(content);
4075        assert_eq!(result.action, ElicitAction::Accept);
4076        assert!(result.content.is_some());
4077    }
4078
4079    #[test]
4080    fn test_elicit_result_decline() {
4081        let result = ElicitResult::decline();
4082        assert_eq!(result.action, ElicitAction::Decline);
4083        assert!(result.content.is_none());
4084    }
4085
4086    #[test]
4087    fn test_elicit_result_cancel() {
4088        let result = ElicitResult::cancel();
4089        assert_eq!(result.action, ElicitAction::Cancel);
4090        assert!(result.content.is_none());
4091    }
4092
4093    #[test]
4094    fn test_elicit_mode_serialization() {
4095        assert_eq!(
4096            serde_json::to_string(&ElicitMode::Form).unwrap(),
4097            "\"form\""
4098        );
4099        assert_eq!(serde_json::to_string(&ElicitMode::Url).unwrap(), "\"url\"");
4100    }
4101
4102    #[test]
4103    fn test_elicit_action_serialization() {
4104        assert_eq!(
4105            serde_json::to_string(&ElicitAction::Accept).unwrap(),
4106            "\"accept\""
4107        );
4108        assert_eq!(
4109            serde_json::to_string(&ElicitAction::Decline).unwrap(),
4110            "\"decline\""
4111        );
4112        assert_eq!(
4113            serde_json::to_string(&ElicitAction::Cancel).unwrap(),
4114            "\"cancel\""
4115        );
4116    }
4117
4118    #[test]
4119    fn test_elicitation_capability() {
4120        let cap = ElicitationCapability {
4121            form: Some(ElicitationFormCapability {}),
4122            url: None,
4123        };
4124
4125        let json = serde_json::to_value(&cap).unwrap();
4126        assert!(json["form"].is_object());
4127        assert!(json.get("url").is_none());
4128    }
4129
4130    #[test]
4131    fn test_client_capabilities_with_elicitation() {
4132        let caps = ClientCapabilities {
4133            roots: None,
4134            sampling: None,
4135            elicitation: Some(ElicitationCapability {
4136                form: Some(ElicitationFormCapability {}),
4137                url: Some(ElicitationUrlCapability {}),
4138            }),
4139            tasks: None,
4140            experimental: None,
4141            extensions: None,
4142        };
4143
4144        let json = serde_json::to_value(&caps).unwrap();
4145        assert!(json["elicitation"]["form"].is_object());
4146        assert!(json["elicitation"]["url"].is_object());
4147    }
4148
4149    #[test]
4150    fn test_elicit_url_params() {
4151        let params = ElicitUrlParams {
4152            mode: Some(ElicitMode::Url),
4153            elicitation_id: "abc123".to_string(),
4154            message: "Please authorize".to_string(),
4155            url: "https://example.com/auth".to_string(),
4156            meta: None,
4157        };
4158
4159        let json = serde_json::to_value(&params).unwrap();
4160        assert_eq!(json["mode"], "url");
4161        assert_eq!(json["elicitationId"], "abc123");
4162        assert_eq!(json["message"], "Please authorize");
4163        assert_eq!(json["url"], "https://example.com/auth");
4164    }
4165
4166    #[test]
4167    fn test_elicitation_complete_params() {
4168        let params = ElicitationCompleteParams {
4169            elicitation_id: "xyz789".to_string(),
4170            meta: None,
4171        };
4172
4173        let json = serde_json::to_value(&params).unwrap();
4174        assert_eq!(json["elicitationId"], "xyz789");
4175    }
4176
4177    #[test]
4178    fn test_root_new() {
4179        let root = Root::new("file:///home/user/project");
4180        assert_eq!(root.uri, "file:///home/user/project");
4181        assert!(root.name.is_none());
4182    }
4183
4184    #[test]
4185    fn test_root_with_name() {
4186        let root = Root::with_name("file:///home/user/project", "My Project");
4187        assert_eq!(root.uri, "file:///home/user/project");
4188        assert_eq!(root.name.as_deref(), Some("My Project"));
4189    }
4190
4191    #[test]
4192    fn test_root_serialization() {
4193        let root = Root::with_name("file:///workspace", "Workspace");
4194        let json = serde_json::to_value(&root).unwrap();
4195        assert_eq!(json["uri"], "file:///workspace");
4196        assert_eq!(json["name"], "Workspace");
4197    }
4198
4199    #[test]
4200    fn test_root_serialization_without_name() {
4201        let root = Root::new("file:///workspace");
4202        let json = serde_json::to_value(&root).unwrap();
4203        assert_eq!(json["uri"], "file:///workspace");
4204        assert!(json.get("name").is_none());
4205    }
4206
4207    #[test]
4208    fn test_root_deserialization() {
4209        let json = serde_json::json!({
4210            "uri": "file:///home/user",
4211            "name": "Home"
4212        });
4213        let root: Root = serde_json::from_value(json).unwrap();
4214        assert_eq!(root.uri, "file:///home/user");
4215        assert_eq!(root.name.as_deref(), Some("Home"));
4216    }
4217
4218    #[test]
4219    fn test_list_roots_result() {
4220        let result = ListRootsResult {
4221            roots: vec![
4222                Root::new("file:///project1"),
4223                Root::with_name("file:///project2", "Project 2"),
4224            ],
4225            meta: None,
4226        };
4227
4228        let json = serde_json::to_value(&result).unwrap();
4229        let roots = json["roots"].as_array().unwrap();
4230        assert_eq!(roots.len(), 2);
4231        assert_eq!(roots[0]["uri"], "file:///project1");
4232        assert_eq!(roots[1]["name"], "Project 2");
4233    }
4234
4235    #[test]
4236    fn test_roots_capability_serialization() {
4237        let cap = RootsCapability { list_changed: true };
4238        let json = serde_json::to_value(&cap).unwrap();
4239        assert_eq!(json["listChanged"], true);
4240    }
4241
4242    #[test]
4243    fn test_client_capabilities_with_roots() {
4244        let caps = ClientCapabilities {
4245            roots: Some(RootsCapability { list_changed: true }),
4246            sampling: None,
4247            elicitation: None,
4248            tasks: None,
4249            experimental: None,
4250            extensions: None,
4251        };
4252
4253        let json = serde_json::to_value(&caps).unwrap();
4254        assert_eq!(json["roots"]["listChanged"], true);
4255    }
4256
4257    #[test]
4258    fn test_roots_list_changed_notification_parsing() {
4259        let notif = JsonRpcNotification {
4260            jsonrpc: "2.0".to_string(),
4261            method: notifications::ROOTS_LIST_CHANGED.to_string(),
4262            params: None,
4263        };
4264
4265        let mcp_notif = McpNotification::from_jsonrpc(&notif).unwrap();
4266        assert!(matches!(mcp_notif, McpNotification::RootsListChanged));
4267    }
4268
4269    // =========================================================================
4270    // Completion Tests
4271    // =========================================================================
4272
4273    #[test]
4274    fn test_prompt_reference() {
4275        let ref_ = PromptReference::new("my-prompt");
4276        assert_eq!(ref_.ref_type, "ref/prompt");
4277        assert_eq!(ref_.name, "my-prompt");
4278
4279        let json = serde_json::to_value(&ref_).unwrap();
4280        assert_eq!(json["type"], "ref/prompt");
4281        assert_eq!(json["name"], "my-prompt");
4282    }
4283
4284    #[test]
4285    fn test_resource_reference() {
4286        let ref_ = ResourceReference::new("file:///path/to/file");
4287        assert_eq!(ref_.ref_type, "ref/resource");
4288        assert_eq!(ref_.uri, "file:///path/to/file");
4289
4290        let json = serde_json::to_value(&ref_).unwrap();
4291        assert_eq!(json["type"], "ref/resource");
4292        assert_eq!(json["uri"], "file:///path/to/file");
4293    }
4294
4295    #[test]
4296    fn test_completion_reference_prompt() {
4297        let ref_ = CompletionReference::prompt("test-prompt");
4298        let json = serde_json::to_value(&ref_).unwrap();
4299        assert_eq!(json["type"], "ref/prompt");
4300        assert_eq!(json["name"], "test-prompt");
4301    }
4302
4303    #[test]
4304    fn test_completion_reference_resource() {
4305        let ref_ = CompletionReference::resource("file:///test");
4306        let json = serde_json::to_value(&ref_).unwrap();
4307        assert_eq!(json["type"], "ref/resource");
4308        assert_eq!(json["uri"], "file:///test");
4309    }
4310
4311    #[test]
4312    fn test_completion_argument() {
4313        let arg = CompletionArgument::new("query", "SELECT * FROM");
4314        assert_eq!(arg.name, "query");
4315        assert_eq!(arg.value, "SELECT * FROM");
4316    }
4317
4318    #[test]
4319    fn test_complete_params_serialization() {
4320        let params = CompleteParams {
4321            reference: CompletionReference::prompt("sql-prompt"),
4322            argument: CompletionArgument::new("query", "SEL"),
4323            context: None,
4324            meta: None,
4325        };
4326
4327        let json = serde_json::to_value(&params).unwrap();
4328        assert_eq!(json["ref"]["type"], "ref/prompt");
4329        assert_eq!(json["ref"]["name"], "sql-prompt");
4330        assert_eq!(json["argument"]["name"], "query");
4331        assert_eq!(json["argument"]["value"], "SEL");
4332        assert!(json.get("context").is_none()); // omitted when None
4333    }
4334
4335    #[test]
4336    fn test_completion_new() {
4337        let completion = Completion::new(vec!["SELECT".to_string(), "SET".to_string()]);
4338        assert_eq!(completion.values.len(), 2);
4339        assert!(completion.total.is_none());
4340        assert!(completion.has_more.is_none());
4341    }
4342
4343    #[test]
4344    fn test_completion_with_pagination() {
4345        let completion =
4346            Completion::with_pagination(vec!["a".to_string(), "b".to_string()], 100, true);
4347        assert_eq!(completion.values.len(), 2);
4348        assert_eq!(completion.total, Some(100));
4349        assert_eq!(completion.has_more, Some(true));
4350    }
4351
4352    #[test]
4353    fn test_complete_result() {
4354        let result = CompleteResult::new(vec!["option1".to_string(), "option2".to_string()]);
4355        let json = serde_json::to_value(&result).unwrap();
4356        assert!(json["completion"]["values"].is_array());
4357        assert_eq!(json["completion"]["values"][0], "option1");
4358    }
4359
4360    // =========================================================================
4361    // Sampling Tests
4362    // =========================================================================
4363
4364    #[test]
4365    fn test_model_hint() {
4366        let hint = ModelHint::new("claude-3-opus");
4367        assert_eq!(hint.name, Some("claude-3-opus".to_string()));
4368    }
4369
4370    #[test]
4371    fn test_model_preferences_builder() {
4372        let prefs = ModelPreferences::new()
4373            .speed(0.8)
4374            .intelligence(0.9)
4375            .cost(0.5)
4376            .hint("gpt-4")
4377            .hint("claude-3");
4378
4379        assert_eq!(prefs.speed_priority, Some(0.8));
4380        assert_eq!(prefs.intelligence_priority, Some(0.9));
4381        assert_eq!(prefs.cost_priority, Some(0.5));
4382        assert_eq!(prefs.hints.len(), 2);
4383    }
4384
4385    #[test]
4386    fn test_model_preferences_clamping() {
4387        let prefs = ModelPreferences::new().speed(1.5).cost(-0.5);
4388
4389        assert_eq!(prefs.speed_priority, Some(1.0)); // Clamped to max
4390        assert_eq!(prefs.cost_priority, Some(0.0)); // Clamped to min
4391    }
4392
4393    #[test]
4394    fn test_include_context_serialization() {
4395        assert_eq!(
4396            serde_json::to_string(&IncludeContext::AllServers).unwrap(),
4397            "\"allServers\""
4398        );
4399        assert_eq!(
4400            serde_json::to_string(&IncludeContext::ThisServer).unwrap(),
4401            "\"thisServer\""
4402        );
4403        assert_eq!(
4404            serde_json::to_string(&IncludeContext::None).unwrap(),
4405            "\"none\""
4406        );
4407    }
4408
4409    #[test]
4410    fn test_sampling_message_user() {
4411        let msg = SamplingMessage::user("Hello, how are you?");
4412        assert_eq!(msg.role, ContentRole::User);
4413        assert!(
4414            matches!(msg.content, SamplingContentOrArray::Single(SamplingContent::Text { ref text, .. }) if text == "Hello, how are you?")
4415        );
4416    }
4417
4418    #[test]
4419    fn test_sampling_message_assistant() {
4420        let msg = SamplingMessage::assistant("I'm doing well!");
4421        assert_eq!(msg.role, ContentRole::Assistant);
4422    }
4423
4424    #[test]
4425    fn test_sampling_content_text_serialization() {
4426        let content = SamplingContent::Text {
4427            text: "Hello".to_string(),
4428            annotations: None,
4429            meta: None,
4430        };
4431        let json = serde_json::to_value(&content).unwrap();
4432        assert_eq!(json["type"], "text");
4433        assert_eq!(json["text"], "Hello");
4434    }
4435
4436    #[test]
4437    fn test_sampling_content_image_serialization() {
4438        let content = SamplingContent::Image {
4439            data: "base64data".to_string(),
4440            mime_type: "image/png".to_string(),
4441            annotations: None,
4442            meta: None,
4443        };
4444        let json = serde_json::to_value(&content).unwrap();
4445        assert_eq!(json["type"], "image");
4446        assert_eq!(json["data"], "base64data");
4447        assert_eq!(json["mimeType"], "image/png");
4448    }
4449
4450    #[test]
4451    fn test_create_message_params() {
4452        let params = CreateMessageParams::new(
4453            vec![
4454                SamplingMessage::user("What is 2+2?"),
4455                SamplingMessage::assistant("4"),
4456                SamplingMessage::user("And 3+3?"),
4457            ],
4458            100,
4459        )
4460        .system_prompt("You are a math tutor")
4461        .temperature(0.7)
4462        .stop_sequence("END")
4463        .include_context(IncludeContext::ThisServer);
4464
4465        assert_eq!(params.messages.len(), 3);
4466        assert_eq!(params.max_tokens, 100);
4467        assert_eq!(
4468            params.system_prompt.as_deref(),
4469            Some("You are a math tutor")
4470        );
4471        assert_eq!(params.temperature, Some(0.7));
4472        assert_eq!(params.stop_sequences.len(), 1);
4473        assert_eq!(params.include_context, Some(IncludeContext::ThisServer));
4474    }
4475
4476    #[test]
4477    fn test_create_message_params_serialization() {
4478        let params = CreateMessageParams::new(vec![SamplingMessage::user("Hello")], 50);
4479
4480        let json = serde_json::to_value(&params).unwrap();
4481        assert!(json["messages"].is_array());
4482        assert_eq!(json["maxTokens"], 50);
4483    }
4484
4485    #[test]
4486    fn test_create_message_result_deserialization() {
4487        let json = serde_json::json!({
4488            "content": {
4489                "type": "text",
4490                "text": "The answer is 42"
4491            },
4492            "model": "claude-3-opus",
4493            "role": "assistant",
4494            "stopReason": "end_turn"
4495        });
4496
4497        let result: CreateMessageResult = serde_json::from_value(json).unwrap();
4498        assert_eq!(result.model, "claude-3-opus");
4499        assert_eq!(result.role, ContentRole::Assistant);
4500        assert_eq!(result.stop_reason.as_deref(), Some("end_turn"));
4501    }
4502
4503    #[test]
4504    fn test_completions_capability_serialization() {
4505        let cap = CompletionsCapability {};
4506        let json = serde_json::to_value(&cap).unwrap();
4507        assert!(json.is_object());
4508    }
4509
4510    #[test]
4511    fn test_server_capabilities_with_completions() {
4512        let caps = ServerCapabilities {
4513            completions: Some(CompletionsCapability {}),
4514            ..Default::default()
4515        };
4516
4517        let json = serde_json::to_value(&caps).unwrap();
4518        assert!(json["completions"].is_object());
4519    }
4520
4521    #[test]
4522    fn test_content_resource_link_serialization() {
4523        let content = Content::ResourceLink {
4524            uri: "file:///test.txt".to_string(),
4525            name: "test.txt".to_string(),
4526            title: None,
4527            description: Some("A test file".to_string()),
4528            mime_type: Some("text/plain".to_string()),
4529            size: None,
4530            icons: None,
4531            annotations: None,
4532            meta: None,
4533        };
4534        let json = serde_json::to_value(&content).unwrap();
4535        assert_eq!(json["type"], "resource_link");
4536        assert_eq!(json["uri"], "file:///test.txt");
4537        assert_eq!(json["name"], "test.txt");
4538        assert_eq!(json["description"], "A test file");
4539        assert_eq!(json["mimeType"], "text/plain");
4540    }
4541
4542    #[test]
4543    fn test_call_tool_result_resource_link() {
4544        let result = CallToolResult::resource_link("file:///output.json", "output.json");
4545        assert_eq!(result.content.len(), 1);
4546        assert!(!result.is_error);
4547        match &result.content[0] {
4548            Content::ResourceLink { uri, .. } => assert_eq!(uri, "file:///output.json"),
4549            _ => panic!("Expected ResourceLink content"),
4550        }
4551    }
4552
4553    #[test]
4554    fn test_call_tool_result_image() {
4555        let result = CallToolResult::image("base64data", "image/png");
4556        assert_eq!(result.content.len(), 1);
4557        match &result.content[0] {
4558            Content::Image {
4559                data, mime_type, ..
4560            } => {
4561                assert_eq!(data, "base64data");
4562                assert_eq!(mime_type, "image/png");
4563            }
4564            _ => panic!("Expected Image content"),
4565        }
4566    }
4567
4568    #[test]
4569    fn test_call_tool_result_audio() {
4570        let result = CallToolResult::audio("audiodata", "audio/wav");
4571        assert_eq!(result.content.len(), 1);
4572        match &result.content[0] {
4573            Content::Audio {
4574                data, mime_type, ..
4575            } => {
4576                assert_eq!(data, "audiodata");
4577                assert_eq!(mime_type, "audio/wav");
4578            }
4579            _ => panic!("Expected Audio content"),
4580        }
4581    }
4582
4583    #[test]
4584    fn test_sampling_tool_serialization() {
4585        let tool = SamplingTool {
4586            name: "get_weather".to_string(),
4587            title: None,
4588            description: Some("Get current weather".to_string()),
4589            input_schema: serde_json::json!({
4590                "type": "object",
4591                "properties": {
4592                    "location": { "type": "string" }
4593                }
4594            }),
4595            output_schema: None,
4596            icons: None,
4597            annotations: None,
4598            execution: None,
4599        };
4600        let json = serde_json::to_value(&tool).unwrap();
4601        assert_eq!(json["name"], "get_weather");
4602        assert_eq!(json["description"], "Get current weather");
4603        assert!(json["inputSchema"]["properties"]["location"].is_object());
4604    }
4605
4606    #[test]
4607    fn test_tool_choice_modes() {
4608        let auto = ToolChoice::auto();
4609        assert_eq!(auto.mode, "auto");
4610        assert!(auto.name.is_none());
4611
4612        let required = ToolChoice::required();
4613        assert_eq!(required.mode, "required");
4614
4615        let none = ToolChoice::none();
4616        assert_eq!(none.mode, "none");
4617
4618        let tool = ToolChoice::tool("get_weather");
4619        assert_eq!(tool.mode, "tool");
4620        assert_eq!(tool.name.as_deref(), Some("get_weather"));
4621
4622        // Test serialization — mode field should serialize as "mode", not "type"
4623        let json = serde_json::to_value(&auto).unwrap();
4624        assert_eq!(json["mode"], "auto");
4625        assert!(json.get("name").is_none());
4626
4627        let json = serde_json::to_value(&tool).unwrap();
4628        assert_eq!(json["mode"], "tool");
4629        assert_eq!(json["name"], "get_weather");
4630    }
4631
4632    #[test]
4633    fn test_sampling_content_tool_use() {
4634        let content = SamplingContent::ToolUse {
4635            id: "tool_123".to_string(),
4636            name: "get_weather".to_string(),
4637            input: serde_json::json!({"location": "San Francisco"}),
4638            meta: None,
4639        };
4640        let json = serde_json::to_value(&content).unwrap();
4641        assert_eq!(json["type"], "tool_use");
4642        assert_eq!(json["id"], "tool_123");
4643        assert_eq!(json["name"], "get_weather");
4644        assert_eq!(json["input"]["location"], "San Francisco");
4645    }
4646
4647    #[test]
4648    fn test_sampling_content_tool_result() {
4649        let content = SamplingContent::ToolResult {
4650            tool_use_id: "tool_123".to_string(),
4651            content: vec![SamplingContent::Text {
4652                text: "72F, sunny".to_string(),
4653                annotations: None,
4654                meta: None,
4655            }],
4656            structured_content: None,
4657            is_error: None,
4658            meta: None,
4659        };
4660        let json = serde_json::to_value(&content).unwrap();
4661        assert_eq!(json["type"], "tool_result");
4662        assert_eq!(json["toolUseId"], "tool_123");
4663        assert_eq!(json["content"][0]["type"], "text");
4664    }
4665
4666    #[test]
4667    fn test_sampling_content_or_array_single() {
4668        let json = serde_json::json!({
4669            "type": "text",
4670            "text": "Hello"
4671        });
4672        let content: SamplingContentOrArray = serde_json::from_value(json).unwrap();
4673        let items = content.items();
4674        assert_eq!(items.len(), 1);
4675        match items[0] {
4676            SamplingContent::Text { text, .. } => assert_eq!(text, "Hello"),
4677            _ => panic!("Expected text content"),
4678        }
4679    }
4680
4681    #[test]
4682    fn test_sampling_content_or_array_multiple() {
4683        let json = serde_json::json!([
4684            { "type": "text", "text": "Hello" },
4685            { "type": "text", "text": "World" }
4686        ]);
4687        let content: SamplingContentOrArray = serde_json::from_value(json).unwrap();
4688        let items = content.items();
4689        assert_eq!(items.len(), 2);
4690    }
4691
4692    #[test]
4693    fn test_create_message_params_with_tools() {
4694        let tool = SamplingTool {
4695            name: "calculator".to_string(),
4696            title: None,
4697            description: Some("Do math".to_string()),
4698            input_schema: serde_json::json!({"type": "object"}),
4699            output_schema: None,
4700            icons: None,
4701            annotations: None,
4702            execution: None,
4703        };
4704        let params = CreateMessageParams::new(vec![], 100)
4705            .tools(vec![tool])
4706            .tool_choice(ToolChoice::auto());
4707
4708        let json = serde_json::to_value(&params).unwrap();
4709        assert!(json["tools"].is_array());
4710        assert_eq!(json["tools"][0]["name"], "calculator");
4711        assert_eq!(json["toolChoice"]["mode"], "auto");
4712    }
4713
4714    #[test]
4715    fn test_create_message_result_content_items() {
4716        let result = CreateMessageResult {
4717            content: SamplingContentOrArray::Array(vec![
4718                SamplingContent::Text {
4719                    text: "First".to_string(),
4720                    annotations: None,
4721                    meta: None,
4722                },
4723                SamplingContent::Text {
4724                    text: "Second".to_string(),
4725                    annotations: None,
4726                    meta: None,
4727                },
4728            ]),
4729            model: "test".to_string(),
4730            role: ContentRole::Assistant,
4731            stop_reason: None,
4732            meta: None,
4733        };
4734        let items = result.content_items();
4735        assert_eq!(items.len(), 2);
4736    }
4737
4738    #[test]
4739    fn test_sampling_content_as_text() {
4740        let text_content = SamplingContent::Text {
4741            text: "Hello".to_string(),
4742            annotations: None,
4743            meta: None,
4744        };
4745        assert_eq!(text_content.as_text(), Some("Hello"));
4746
4747        let image_content = SamplingContent::Image {
4748            data: "base64data".to_string(),
4749            mime_type: "image/png".to_string(),
4750            annotations: None,
4751            meta: None,
4752        };
4753        assert_eq!(image_content.as_text(), None);
4754
4755        let audio_content = SamplingContent::Audio {
4756            data: "base64audio".to_string(),
4757            mime_type: "audio/wav".to_string(),
4758            annotations: None,
4759            meta: None,
4760        };
4761        assert_eq!(audio_content.as_text(), None);
4762    }
4763
4764    #[test]
4765    fn test_create_message_result_first_text_single() {
4766        let result = CreateMessageResult {
4767            content: SamplingContentOrArray::Single(SamplingContent::Text {
4768                text: "Hello, world!".to_string(),
4769                annotations: None,
4770                meta: None,
4771            }),
4772            model: "test".to_string(),
4773            role: ContentRole::Assistant,
4774            stop_reason: None,
4775            meta: None,
4776        };
4777        assert_eq!(result.first_text(), Some("Hello, world!"));
4778    }
4779
4780    #[test]
4781    fn test_create_message_result_first_text_array() {
4782        let result = CreateMessageResult {
4783            content: SamplingContentOrArray::Array(vec![
4784                SamplingContent::Text {
4785                    text: "First".to_string(),
4786                    annotations: None,
4787                    meta: None,
4788                },
4789                SamplingContent::Text {
4790                    text: "Second".to_string(),
4791                    annotations: None,
4792                    meta: None,
4793                },
4794            ]),
4795            model: "test".to_string(),
4796            role: ContentRole::Assistant,
4797            stop_reason: None,
4798            meta: None,
4799        };
4800        assert_eq!(result.first_text(), Some("First"));
4801    }
4802
4803    #[test]
4804    fn test_create_message_result_first_text_skips_non_text() {
4805        let result = CreateMessageResult {
4806            content: SamplingContentOrArray::Array(vec![
4807                SamplingContent::Image {
4808                    data: "base64data".to_string(),
4809                    mime_type: "image/png".to_string(),
4810                    annotations: None,
4811                    meta: None,
4812                },
4813                SamplingContent::Text {
4814                    text: "After image".to_string(),
4815                    annotations: None,
4816                    meta: None,
4817                },
4818            ]),
4819            model: "test".to_string(),
4820            role: ContentRole::Assistant,
4821            stop_reason: None,
4822            meta: None,
4823        };
4824        assert_eq!(result.first_text(), Some("After image"));
4825    }
4826
4827    #[test]
4828    fn test_create_message_result_first_text_none() {
4829        let result = CreateMessageResult {
4830            content: SamplingContentOrArray::Single(SamplingContent::Image {
4831                data: "base64data".to_string(),
4832                mime_type: "image/png".to_string(),
4833                annotations: None,
4834                meta: None,
4835            }),
4836            model: "test".to_string(),
4837            role: ContentRole::Assistant,
4838            stop_reason: None,
4839            meta: None,
4840        };
4841        assert_eq!(result.first_text(), None);
4842    }
4843
4844    #[test]
4845    fn test_tool_annotations_accessors() {
4846        let annotations = ToolAnnotations {
4847            read_only_hint: true,
4848            destructive_hint: false,
4849            idempotent_hint: true,
4850            open_world_hint: false,
4851            ..Default::default()
4852        };
4853
4854        assert!(annotations.is_read_only());
4855        assert!(!annotations.is_destructive());
4856        assert!(annotations.is_idempotent());
4857        assert!(!annotations.is_open_world());
4858    }
4859
4860    #[test]
4861    fn test_tool_annotations_defaults() {
4862        // Default matches MCP spec defaults: destructive=true, open_world=true
4863        let annotations = ToolAnnotations::default();
4864
4865        assert!(!annotations.is_read_only());
4866        assert!(annotations.is_destructive());
4867        assert!(!annotations.is_idempotent());
4868        assert!(annotations.is_open_world());
4869    }
4870
4871    #[test]
4872    fn test_tool_annotations_serde_defaults() {
4873        // When deserialized from an empty object, serde applies
4874        // the spec defaults: destructive_hint=true, open_world_hint=true
4875        let annotations: ToolAnnotations = serde_json::from_str("{}").unwrap();
4876
4877        assert!(!annotations.is_read_only());
4878        assert!(annotations.is_destructive());
4879        assert!(!annotations.is_idempotent());
4880        assert!(annotations.is_open_world());
4881    }
4882
4883    #[test]
4884    fn test_tool_definition_accessors_with_annotations() {
4885        let def = ToolDefinition {
4886            name: "test".to_string(),
4887            title: None,
4888            description: None,
4889            input_schema: serde_json::json!({"type": "object"}),
4890            output_schema: None,
4891            icons: None,
4892            annotations: Some(ToolAnnotations {
4893                read_only_hint: true,
4894                idempotent_hint: true,
4895                destructive_hint: false,
4896                open_world_hint: false,
4897                ..Default::default()
4898            }),
4899            execution: None,
4900            meta: None,
4901        };
4902
4903        assert!(def.is_read_only());
4904        assert!(!def.is_destructive());
4905        assert!(def.is_idempotent());
4906        assert!(!def.is_open_world());
4907    }
4908
4909    #[test]
4910    fn test_tool_definition_accessors_without_annotations() {
4911        let def = ToolDefinition {
4912            name: "test".to_string(),
4913            title: None,
4914            description: None,
4915            input_schema: serde_json::json!({"type": "object"}),
4916            output_schema: None,
4917            icons: None,
4918            annotations: None,
4919            execution: None,
4920            meta: None,
4921        };
4922
4923        // MCP spec defaults when no annotations present
4924        assert!(!def.is_read_only());
4925        assert!(def.is_destructive());
4926        assert!(!def.is_idempotent());
4927        assert!(def.is_open_world());
4928    }
4929
4930    #[test]
4931    fn test_call_tool_result_from_list() {
4932        #[derive(serde::Serialize)]
4933        struct Item {
4934            name: String,
4935        }
4936
4937        let items = vec![
4938            Item {
4939                name: "a".to_string(),
4940            },
4941            Item {
4942                name: "b".to_string(),
4943            },
4944            Item {
4945                name: "c".to_string(),
4946            },
4947        ];
4948
4949        let result = CallToolResult::from_list("items", &items).unwrap();
4950        assert!(!result.is_error);
4951
4952        let structured = result.structured_content.unwrap();
4953        assert_eq!(structured["count"], 3);
4954        assert_eq!(structured["items"].as_array().unwrap().len(), 3);
4955        assert_eq!(structured["items"][0]["name"], "a");
4956    }
4957
4958    #[test]
4959    fn test_call_tool_result_from_list_empty() {
4960        let items: Vec<String> = vec![];
4961        let result = CallToolResult::from_list("results", &items).unwrap();
4962        assert!(!result.is_error);
4963
4964        let structured = result.structured_content.unwrap();
4965        assert_eq!(structured["count"], 0);
4966        assert_eq!(structured["results"].as_array().unwrap().len(), 0);
4967    }
4968
4969    // =========================================================================
4970    // JSON Helper Tests
4971    // =========================================================================
4972
4973    #[test]
4974    fn test_call_tool_result_as_json() {
4975        let result = CallToolResult::json(serde_json::json!({"key": "value"}));
4976        let value = result.as_json().unwrap().unwrap();
4977        assert_eq!(value["key"], "value");
4978    }
4979
4980    #[test]
4981    fn test_call_tool_result_as_json_from_text() {
4982        let result = CallToolResult::text(r#"{"key": "value"}"#);
4983        let value = result.as_json().unwrap().unwrap();
4984        assert_eq!(value["key"], "value");
4985    }
4986
4987    #[test]
4988    fn test_call_tool_result_as_json_none() {
4989        let result = CallToolResult::text("not json");
4990        let parsed = result.as_json().unwrap();
4991        assert!(parsed.is_err());
4992    }
4993
4994    #[test]
4995    fn test_call_tool_result_deserialize() {
4996        #[derive(Debug, serde::Deserialize, PartialEq)]
4997        struct Output {
4998            key: String,
4999        }
5000
5001        let result = CallToolResult::json(serde_json::json!({"key": "value"}));
5002        let output: Output = result.deserialize().unwrap().unwrap();
5003        assert_eq!(output.key, "value");
5004    }
5005
5006    #[test]
5007    fn test_call_tool_result_as_json_empty() {
5008        let result = CallToolResult {
5009            content: vec![],
5010            is_error: false,
5011            structured_content: None,
5012            meta: None,
5013        };
5014        assert!(result.as_json().is_none());
5015    }
5016
5017    #[test]
5018    fn test_call_tool_result_deserialize_from_text() {
5019        #[derive(Debug, serde::Deserialize, PartialEq)]
5020        struct Output {
5021            key: String,
5022        }
5023
5024        let result = CallToolResult::text(r#"{"key": "from_text"}"#);
5025        let output: Output = result.deserialize().unwrap().unwrap();
5026        assert_eq!(output.key, "from_text");
5027    }
5028
5029    #[test]
5030    fn test_read_resource_result_as_json() {
5031        let result = ReadResourceResult::json("data://config", &serde_json::json!({"port": 8080}));
5032        let value = result.as_json().unwrap().unwrap();
5033        assert_eq!(value["port"], 8080);
5034    }
5035
5036    #[test]
5037    fn test_read_resource_result_deserialize() {
5038        #[derive(Debug, serde::Deserialize, PartialEq)]
5039        struct Config {
5040            port: u16,
5041        }
5042
5043        let result = ReadResourceResult::json("data://config", &serde_json::json!({"port": 8080}));
5044        let config: Config = result.deserialize().unwrap().unwrap();
5045        assert_eq!(config.port, 8080);
5046    }
5047
5048    #[test]
5049    fn test_get_prompt_result_as_json() {
5050        let result = GetPromptResult::user_message(r#"{"action": "analyze"}"#);
5051        let value = result.as_json().unwrap().unwrap();
5052        assert_eq!(value["action"], "analyze");
5053    }
5054
5055    #[test]
5056    fn test_get_prompt_result_deserialize() {
5057        #[derive(Debug, serde::Deserialize, PartialEq)]
5058        struct Params {
5059            action: String,
5060        }
5061
5062        let result = GetPromptResult::user_message(r#"{"action": "analyze"}"#);
5063        let params: Params = result.deserialize().unwrap().unwrap();
5064        assert_eq!(params.action, "analyze");
5065    }
5066
5067    #[test]
5068    fn test_get_prompt_result_as_json_empty() {
5069        let result = GetPromptResult {
5070            description: None,
5071            messages: vec![],
5072            meta: None,
5073        };
5074        assert!(result.as_json().is_none());
5075    }
5076
5077    #[test]
5078    fn test_mcp_response_serde_roundtrip() {
5079        // CallToolResult variant - has distinctive fields
5080        let response = McpResponse::CallTool(CallToolResult {
5081            content: vec![Content::text("hello")],
5082            structured_content: None,
5083            is_error: false,
5084            meta: None,
5085        });
5086        let json = serde_json::to_string(&response).unwrap();
5087        let deserialized: McpResponse = serde_json::from_str(&json).unwrap();
5088        match deserialized {
5089            McpResponse::CallTool(result) => {
5090                assert_eq!(result.content[0].as_text(), Some("hello"));
5091            }
5092            _ => panic!("expected CallTool variant"),
5093        }
5094
5095        // ListToolsResult variant
5096        let response = McpResponse::ListTools(ListToolsResult {
5097            tools: vec![],
5098            next_cursor: Some("cursor123".to_string()),
5099            meta: None,
5100        });
5101        let json = serde_json::to_string(&response).unwrap();
5102        let deserialized: McpResponse = serde_json::from_str(&json).unwrap();
5103        match deserialized {
5104            McpResponse::ListTools(result) => {
5105                assert_eq!(result.next_cursor.as_deref(), Some("cursor123"));
5106            }
5107            _ => panic!("expected ListTools variant"),
5108        }
5109    }
5110}