Skip to main content

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