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