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