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