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
966impl SamplingContent {
967    /// Get the text content if this is a text variant.
968    ///
969    /// Returns `None` if this is an image, audio, tool_use, or tool_result variant.
970    ///
971    /// # Example
972    ///
973    /// ```rust
974    /// use tower_mcp::protocol::SamplingContent;
975    ///
976    /// let text_content = SamplingContent::Text { text: "Hello".into() };
977    /// assert_eq!(text_content.as_text(), Some("Hello"));
978    ///
979    /// let image_content = SamplingContent::Image {
980    ///     data: "base64...".into(),
981    ///     mime_type: "image/png".into(),
982    /// };
983    /// assert_eq!(image_content.as_text(), None);
984    /// ```
985    pub fn as_text(&self) -> Option<&str> {
986        match self {
987            SamplingContent::Text { text } => Some(text),
988            _ => None,
989        }
990    }
991}
992
993/// Content that can be either a single item or an array (for CreateMessageResult)
994///
995/// The MCP spec allows CreateMessageResult.content to be either a single
996/// SamplingContent or an array of SamplingContent items.
997#[derive(Debug, Clone, Serialize, Deserialize)]
998#[serde(untagged)]
999pub enum SamplingContentOrArray {
1000    /// Single content item
1001    Single(SamplingContent),
1002    /// Array of content items
1003    Array(Vec<SamplingContent>),
1004}
1005
1006impl SamplingContentOrArray {
1007    /// Get content items as a slice
1008    pub fn items(&self) -> Vec<&SamplingContent> {
1009        match self {
1010            Self::Single(c) => vec![c],
1011            Self::Array(arr) => arr.iter().collect(),
1012        }
1013    }
1014
1015    /// Get owned content items
1016    pub fn into_items(self) -> Vec<SamplingContent> {
1017        match self {
1018            Self::Single(c) => vec![c],
1019            Self::Array(arr) => arr,
1020        }
1021    }
1022}
1023
1024/// Parameters for sampling/createMessage request
1025#[derive(Debug, Clone, Serialize, Deserialize)]
1026#[serde(rename_all = "camelCase")]
1027pub struct CreateMessageParams {
1028    /// The messages to send to the LLM
1029    pub messages: Vec<SamplingMessage>,
1030    /// Maximum number of tokens to generate
1031    pub max_tokens: u32,
1032    /// Optional system prompt
1033    #[serde(default, skip_serializing_if = "Option::is_none")]
1034    pub system_prompt: Option<String>,
1035    /// Sampling temperature (0.0 to 1.0)
1036    #[serde(default, skip_serializing_if = "Option::is_none")]
1037    pub temperature: Option<f64>,
1038    /// Stop sequences
1039    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1040    pub stop_sequences: Vec<String>,
1041    /// Model preferences
1042    #[serde(default, skip_serializing_if = "Option::is_none")]
1043    pub model_preferences: Option<ModelPreferences>,
1044    /// Context inclusion mode
1045    #[serde(default, skip_serializing_if = "Option::is_none")]
1046    pub include_context: Option<IncludeContext>,
1047    /// Additional metadata
1048    #[serde(default, skip_serializing_if = "Option::is_none")]
1049    pub metadata: Option<serde_json::Map<String, Value>>,
1050    /// Tools available for the model to use (SEP-1577)
1051    #[serde(default, skip_serializing_if = "Option::is_none")]
1052    pub tools: Option<Vec<SamplingTool>>,
1053    /// Tool choice mode (SEP-1577)
1054    #[serde(default, skip_serializing_if = "Option::is_none")]
1055    pub tool_choice: Option<ToolChoice>,
1056}
1057
1058impl CreateMessageParams {
1059    /// Create a new sampling request
1060    pub fn new(messages: Vec<SamplingMessage>, max_tokens: u32) -> Self {
1061        Self {
1062            messages,
1063            max_tokens,
1064            system_prompt: None,
1065            temperature: None,
1066            stop_sequences: Vec::new(),
1067            model_preferences: None,
1068            include_context: None,
1069            metadata: None,
1070            tools: None,
1071            tool_choice: None,
1072        }
1073    }
1074
1075    /// Set the system prompt
1076    pub fn system_prompt(mut self, prompt: impl Into<String>) -> Self {
1077        self.system_prompt = Some(prompt.into());
1078        self
1079    }
1080
1081    /// Set the temperature
1082    pub fn temperature(mut self, temp: f64) -> Self {
1083        self.temperature = Some(temp.clamp(0.0, 1.0));
1084        self
1085    }
1086
1087    /// Add a stop sequence
1088    pub fn stop_sequence(mut self, seq: impl Into<String>) -> Self {
1089        self.stop_sequences.push(seq.into());
1090        self
1091    }
1092
1093    /// Set model preferences
1094    pub fn model_preferences(mut self, prefs: ModelPreferences) -> Self {
1095        self.model_preferences = Some(prefs);
1096        self
1097    }
1098
1099    /// Set context inclusion mode
1100    pub fn include_context(mut self, mode: IncludeContext) -> Self {
1101        self.include_context = Some(mode);
1102        self
1103    }
1104
1105    /// Set tools available for the model to use (SEP-1577)
1106    pub fn tools(mut self, tools: Vec<SamplingTool>) -> Self {
1107        self.tools = Some(tools);
1108        self
1109    }
1110
1111    /// Set tool choice mode (SEP-1577)
1112    pub fn tool_choice(mut self, choice: ToolChoice) -> Self {
1113        self.tool_choice = Some(choice);
1114        self
1115    }
1116}
1117
1118/// Result of sampling/createMessage request
1119#[derive(Debug, Clone, Serialize, Deserialize)]
1120#[serde(rename_all = "camelCase")]
1121pub struct CreateMessageResult {
1122    /// The generated content (single item or array)
1123    pub content: SamplingContentOrArray,
1124    /// The model that generated the response
1125    pub model: String,
1126    /// The role of the response (always assistant)
1127    pub role: ContentRole,
1128    /// Why the generation stopped
1129    #[serde(default, skip_serializing_if = "Option::is_none")]
1130    pub stop_reason: Option<String>,
1131}
1132
1133impl CreateMessageResult {
1134    /// Get content items as a vector of references
1135    pub fn content_items(&self) -> Vec<&SamplingContent> {
1136        self.content.items()
1137    }
1138
1139    /// Get the text from the first text content item.
1140    ///
1141    /// Returns `None` if there are no content items or if the first
1142    /// text-containing item is not found.
1143    ///
1144    /// # Example
1145    ///
1146    /// ```rust
1147    /// use tower_mcp::protocol::{CreateMessageResult, SamplingContent, SamplingContentOrArray, ContentRole};
1148    ///
1149    /// let result = CreateMessageResult {
1150    ///     content: SamplingContentOrArray::Single(SamplingContent::Text {
1151    ///         text: "Hello, world!".into(),
1152    ///     }),
1153    ///     model: "claude-3".into(),
1154    ///     role: ContentRole::Assistant,
1155    ///     stop_reason: None,
1156    /// };
1157    /// assert_eq!(result.first_text(), Some("Hello, world!"));
1158    /// ```
1159    pub fn first_text(&self) -> Option<&str> {
1160        self.content.items().iter().find_map(|c| c.as_text())
1161    }
1162}
1163
1164/// Information about a client or server implementation
1165#[derive(Debug, Clone, Default, Deserialize, Serialize)]
1166#[serde(rename_all = "camelCase")]
1167pub struct Implementation {
1168    /// Name of the implementation
1169    pub name: String,
1170    /// Version of the implementation
1171    pub version: String,
1172    /// Human-readable title for display purposes
1173    #[serde(skip_serializing_if = "Option::is_none")]
1174    pub title: Option<String>,
1175    /// Description of the implementation
1176    #[serde(skip_serializing_if = "Option::is_none")]
1177    pub description: Option<String>,
1178    /// Icons for the implementation
1179    #[serde(skip_serializing_if = "Option::is_none")]
1180    pub icons: Option<Vec<ToolIcon>>,
1181    /// URL of the implementation's website
1182    #[serde(skip_serializing_if = "Option::is_none")]
1183    pub website_url: Option<String>,
1184}
1185
1186#[derive(Debug, Clone, Serialize, Deserialize)]
1187#[serde(rename_all = "camelCase")]
1188pub struct InitializeResult {
1189    pub protocol_version: String,
1190    pub capabilities: ServerCapabilities,
1191    pub server_info: Implementation,
1192    /// Optional instructions describing how to use this server.
1193    /// These hints help LLMs understand the server's features.
1194    #[serde(skip_serializing_if = "Option::is_none")]
1195    pub instructions: Option<String>,
1196}
1197
1198#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1199#[serde(rename_all = "camelCase")]
1200pub struct ServerCapabilities {
1201    #[serde(default, skip_serializing_if = "Option::is_none")]
1202    pub tools: Option<ToolsCapability>,
1203    #[serde(default, skip_serializing_if = "Option::is_none")]
1204    pub resources: Option<ResourcesCapability>,
1205    #[serde(default, skip_serializing_if = "Option::is_none")]
1206    pub prompts: Option<PromptsCapability>,
1207    /// Logging capability - servers that emit log notifications declare this
1208    #[serde(default, skip_serializing_if = "Option::is_none")]
1209    pub logging: Option<LoggingCapability>,
1210    #[serde(default, skip_serializing_if = "Option::is_none")]
1211    pub tasks: Option<TasksCapability>,
1212    /// Completion capability - server provides autocomplete suggestions
1213    #[serde(default, skip_serializing_if = "Option::is_none")]
1214    pub completions: Option<CompletionsCapability>,
1215}
1216
1217/// Logging capability declaration
1218#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1219pub struct LoggingCapability {}
1220
1221/// Capability for async task management
1222#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1223#[serde(rename_all = "camelCase")]
1224pub struct TasksCapability {
1225    /// Default poll interval suggestion in seconds
1226    #[serde(default, skip_serializing_if = "Option::is_none")]
1227    pub default_poll_interval: Option<u64>,
1228}
1229
1230#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1231#[serde(rename_all = "camelCase")]
1232pub struct ToolsCapability {
1233    #[serde(default)]
1234    pub list_changed: bool,
1235}
1236
1237#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1238#[serde(rename_all = "camelCase")]
1239pub struct ResourcesCapability {
1240    #[serde(default)]
1241    pub subscribe: bool,
1242    #[serde(default)]
1243    pub list_changed: bool,
1244}
1245
1246#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1247#[serde(rename_all = "camelCase")]
1248pub struct PromptsCapability {
1249    #[serde(default)]
1250    pub list_changed: bool,
1251}
1252
1253// =============================================================================
1254// Tools
1255// =============================================================================
1256
1257#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1258pub struct ListToolsParams {
1259    #[serde(default)]
1260    pub cursor: Option<String>,
1261}
1262
1263#[derive(Debug, Clone, Serialize, Deserialize)]
1264#[serde(rename_all = "camelCase")]
1265pub struct ListToolsResult {
1266    pub tools: Vec<ToolDefinition>,
1267    #[serde(default, skip_serializing_if = "Option::is_none")]
1268    pub next_cursor: Option<String>,
1269}
1270
1271/// Tool definition as returned by tools/list
1272#[derive(Debug, Clone, Serialize, Deserialize)]
1273#[serde(rename_all = "camelCase")]
1274pub struct ToolDefinition {
1275    pub name: String,
1276    /// Human-readable title for display purposes
1277    #[serde(skip_serializing_if = "Option::is_none")]
1278    pub title: Option<String>,
1279    #[serde(skip_serializing_if = "Option::is_none")]
1280    pub description: Option<String>,
1281    pub input_schema: Value,
1282    /// Optional JSON Schema defining expected output structure
1283    #[serde(skip_serializing_if = "Option::is_none")]
1284    pub output_schema: Option<Value>,
1285    /// Optional icons for display in user interfaces
1286    #[serde(skip_serializing_if = "Option::is_none")]
1287    pub icons: Option<Vec<ToolIcon>>,
1288    /// Optional annotations describing tool behavior.
1289    /// Note: Clients MUST consider these untrusted unless from a trusted server.
1290    #[serde(skip_serializing_if = "Option::is_none")]
1291    pub annotations: Option<ToolAnnotations>,
1292}
1293
1294/// Icon for tool display in user interfaces
1295#[derive(Debug, Clone, Serialize, Deserialize)]
1296#[serde(rename_all = "camelCase")]
1297pub struct ToolIcon {
1298    /// URL or data URI of the icon
1299    pub src: String,
1300    /// MIME type of the icon (e.g., "image/png", "image/svg+xml")
1301    #[serde(skip_serializing_if = "Option::is_none")]
1302    pub mime_type: Option<String>,
1303    /// Available sizes (e.g., ["48x48", "96x96"])
1304    #[serde(skip_serializing_if = "Option::is_none")]
1305    pub sizes: Option<Vec<String>>,
1306}
1307
1308/// Annotations describing tool behavior for trust and safety.
1309/// Clients MUST consider these untrusted unless the server is trusted.
1310#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1311#[serde(rename_all = "camelCase")]
1312pub struct ToolAnnotations {
1313    /// Human-readable title for the tool
1314    #[serde(skip_serializing_if = "Option::is_none")]
1315    pub title: Option<String>,
1316    /// If true, the tool does not modify state. Default: false
1317    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1318    pub read_only_hint: bool,
1319    /// If true, the tool may have destructive effects. Default: true
1320    /// Only meaningful when read_only_hint is false.
1321    #[serde(default = "default_true", skip_serializing_if = "is_true")]
1322    pub destructive_hint: bool,
1323    /// If true, calling repeatedly with same args has same effect. Default: false
1324    /// Only meaningful when read_only_hint is false.
1325    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1326    pub idempotent_hint: bool,
1327    /// If true, tool interacts with external entities. Default: true
1328    #[serde(default = "default_true", skip_serializing_if = "is_true")]
1329    pub open_world_hint: bool,
1330}
1331
1332fn default_true() -> bool {
1333    true
1334}
1335
1336fn is_true(v: &bool) -> bool {
1337    *v
1338}
1339
1340#[derive(Debug, Clone, Serialize, Deserialize)]
1341pub struct CallToolParams {
1342    pub name: String,
1343    #[serde(default)]
1344    pub arguments: Value,
1345    /// Request metadata including progress token
1346    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1347    pub meta: Option<RequestMeta>,
1348}
1349
1350/// Result of a tool invocation.
1351///
1352/// This is the return type for tool handlers. Use the convenience constructors
1353/// like [`CallToolResult::text`], [`CallToolResult::json`], or [`CallToolResult::error`]
1354/// to create results easily.
1355///
1356/// # Example
1357///
1358/// ```rust
1359/// use tower_mcp::CallToolResult;
1360///
1361/// // Simple text result
1362/// let result = CallToolResult::text("Hello, world!");
1363///
1364/// // JSON result with structured content
1365/// let result = CallToolResult::json(serde_json::json!({"key": "value"}));
1366///
1367/// // Error result
1368/// let result = CallToolResult::error("Something went wrong");
1369/// ```
1370#[derive(Debug, Clone, Serialize, Deserialize)]
1371#[serde(rename_all = "camelCase")]
1372pub struct CallToolResult {
1373    /// The content items returned by the tool.
1374    pub content: Vec<Content>,
1375    /// Whether this result represents an error.
1376    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1377    pub is_error: bool,
1378    /// Optional structured content for programmatic access.
1379    #[serde(default, skip_serializing_if = "Option::is_none")]
1380    pub structured_content: Option<Value>,
1381}
1382
1383impl CallToolResult {
1384    /// Create a text result.
1385    ///
1386    /// This is the most common result type for tools that return plain text.
1387    pub fn text(text: impl Into<String>) -> Self {
1388        Self {
1389            content: vec![Content::Text {
1390                text: text.into(),
1391                annotations: None,
1392            }],
1393            is_error: false,
1394            structured_content: None,
1395        }
1396    }
1397
1398    /// Create an error result.
1399    ///
1400    /// Use this when the tool encounters an error during execution.
1401    /// The `is_error` flag will be set to `true`.
1402    pub fn error(message: impl Into<String>) -> Self {
1403        Self {
1404            content: vec![Content::Text {
1405                text: message.into(),
1406                annotations: None,
1407            }],
1408            is_error: true,
1409            structured_content: None,
1410        }
1411    }
1412
1413    /// Create a JSON result with structured content from a [`serde_json::Value`].
1414    ///
1415    /// The JSON value is serialized to pretty-printed text for display,
1416    /// and also stored in `structured_content` for programmatic access.
1417    ///
1418    /// If you have a type that implements [`serde::Serialize`], use
1419    /// [`from_serialize`](Self::from_serialize) instead to avoid manual `to_value()` calls.
1420    pub fn json(value: Value) -> Self {
1421        let text = serde_json::to_string_pretty(&value).unwrap_or_default();
1422        Self {
1423            content: vec![Content::Text {
1424                text,
1425                annotations: None,
1426            }],
1427            is_error: false,
1428            structured_content: Some(value),
1429        }
1430    }
1431
1432    /// Create a JSON result from any serializable value.
1433    ///
1434    /// This is a fallible alternative to [`json`](Self::json) that accepts any
1435    /// `serde::Serialize` type and handles serialization errors gracefully.
1436    /// The value is serialized to a `serde_json::Value`, then delegated to `json()`,
1437    /// so `structured_content` is populated correctly.
1438    ///
1439    /// # Errors
1440    ///
1441    /// Returns an error if the value cannot be serialized to JSON.
1442    ///
1443    /// # Example
1444    ///
1445    /// ```rust
1446    /// use tower_mcp::CallToolResult;
1447    /// use serde::Serialize;
1448    ///
1449    /// #[derive(Serialize)]
1450    /// struct SearchResult {
1451    ///     title: String,
1452    ///     score: f64,
1453    /// }
1454    ///
1455    /// let result = SearchResult {
1456    ///     title: "Example".to_string(),
1457    ///     score: 0.95,
1458    /// };
1459    /// let tool_result = CallToolResult::from_serialize(&result).unwrap();
1460    /// assert!(!tool_result.is_error);
1461    /// assert!(tool_result.structured_content.is_some());
1462    /// ```
1463    pub fn from_serialize(
1464        value: &impl serde::Serialize,
1465    ) -> std::result::Result<Self, crate::error::Error> {
1466        let json_value = serde_json::to_value(value)
1467            .map_err(|e| crate::error::Error::tool(format!("Serialization failed: {}", e)))?;
1468        Ok(Self::json(json_value))
1469    }
1470
1471    /// Create a result with an image
1472    pub fn image(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1473        Self {
1474            content: vec![Content::Image {
1475                data: data.into(),
1476                mime_type: mime_type.into(),
1477                annotations: None,
1478            }],
1479            is_error: false,
1480            structured_content: None,
1481        }
1482    }
1483
1484    /// Create a result with audio
1485    pub fn audio(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1486        Self {
1487            content: vec![Content::Audio {
1488                data: data.into(),
1489                mime_type: mime_type.into(),
1490                annotations: None,
1491            }],
1492            is_error: false,
1493            structured_content: None,
1494        }
1495    }
1496
1497    /// Create a result with a resource link
1498    pub fn resource_link(uri: impl Into<String>) -> Self {
1499        Self {
1500            content: vec![Content::ResourceLink {
1501                uri: uri.into(),
1502                name: None,
1503                description: None,
1504                mime_type: None,
1505                annotations: None,
1506            }],
1507            is_error: false,
1508            structured_content: None,
1509        }
1510    }
1511
1512    /// Create a result with a resource link including metadata
1513    pub fn resource_link_with_meta(
1514        uri: impl Into<String>,
1515        name: Option<String>,
1516        description: Option<String>,
1517        mime_type: Option<String>,
1518    ) -> Self {
1519        Self {
1520            content: vec![Content::ResourceLink {
1521                uri: uri.into(),
1522                name,
1523                description,
1524                mime_type,
1525                annotations: None,
1526            }],
1527            is_error: false,
1528            structured_content: None,
1529        }
1530    }
1531
1532    /// Create a result with an embedded resource
1533    pub fn resource(resource: ResourceContent) -> Self {
1534        Self {
1535            content: vec![Content::Resource {
1536                resource,
1537                annotations: None,
1538            }],
1539            is_error: false,
1540            structured_content: None,
1541        }
1542    }
1543
1544    /// Concatenate all text content items into a single string.
1545    ///
1546    /// Non-text content items are skipped. Multiple text items are
1547    /// joined without a separator.
1548    ///
1549    /// # Example
1550    ///
1551    /// ```rust
1552    /// use tower_mcp::CallToolResult;
1553    ///
1554    /// let result = CallToolResult::text("hello world");
1555    /// assert_eq!(result.all_text(), "hello world");
1556    /// ```
1557    pub fn all_text(&self) -> String {
1558        self.content.iter().filter_map(|c| c.as_text()).collect()
1559    }
1560
1561    /// Get the text from the first [`Content::Text`] item.
1562    ///
1563    /// Returns `None` if there are no text content items.
1564    ///
1565    /// # Example
1566    ///
1567    /// ```rust
1568    /// use tower_mcp::CallToolResult;
1569    ///
1570    /// let result = CallToolResult::text("hello");
1571    /// assert_eq!(result.first_text(), Some("hello"));
1572    /// ```
1573    pub fn first_text(&self) -> Option<&str> {
1574        self.content.iter().find_map(|c| c.as_text())
1575    }
1576}
1577
1578/// Content types for tool results, resources, and prompts.
1579///
1580/// Content can be text, images, audio, or embedded resources. Each variant
1581/// supports optional annotations for audience targeting and priority hints.
1582#[derive(Debug, Clone, Serialize, Deserialize)]
1583#[serde(tag = "type", rename_all = "snake_case")]
1584pub enum Content {
1585    /// Plain text content.
1586    Text {
1587        /// The text content.
1588        text: String,
1589        /// Optional annotations for this content.
1590        #[serde(skip_serializing_if = "Option::is_none")]
1591        annotations: Option<ContentAnnotations>,
1592    },
1593    /// Base64-encoded image content.
1594    Image {
1595        /// Base64-encoded image data.
1596        data: String,
1597        /// MIME type (e.g., "image/png", "image/jpeg").
1598        #[serde(rename = "mimeType")]
1599        mime_type: String,
1600        /// Optional annotations for this content.
1601        #[serde(skip_serializing_if = "Option::is_none")]
1602        annotations: Option<ContentAnnotations>,
1603    },
1604    /// Base64-encoded audio content.
1605    Audio {
1606        /// Base64-encoded audio data.
1607        data: String,
1608        /// MIME type (e.g., "audio/wav", "audio/mp3").
1609        #[serde(rename = "mimeType")]
1610        mime_type: String,
1611        /// Optional annotations for this content.
1612        #[serde(skip_serializing_if = "Option::is_none")]
1613        annotations: Option<ContentAnnotations>,
1614    },
1615    /// Embedded resource content.
1616    Resource {
1617        /// The embedded resource.
1618        resource: ResourceContent,
1619        /// Optional annotations for this content.
1620        #[serde(skip_serializing_if = "Option::is_none")]
1621        annotations: Option<ContentAnnotations>,
1622    },
1623    /// Link to a resource (without embedding the content)
1624    ResourceLink {
1625        /// URI of the resource
1626        uri: String,
1627        /// Human-readable name
1628        #[serde(skip_serializing_if = "Option::is_none")]
1629        name: Option<String>,
1630        /// Description of the resource
1631        #[serde(skip_serializing_if = "Option::is_none")]
1632        description: Option<String>,
1633        /// MIME type of the resource
1634        #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
1635        mime_type: Option<String>,
1636        #[serde(skip_serializing_if = "Option::is_none")]
1637        annotations: Option<ContentAnnotations>,
1638    },
1639}
1640
1641/// Annotations for content items
1642#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1643pub struct ContentAnnotations {
1644    /// Intended audience for this content
1645    #[serde(skip_serializing_if = "Option::is_none")]
1646    pub audience: Option<Vec<ContentRole>>,
1647    /// Priority hint from 0 (optional) to 1 (required)
1648    #[serde(skip_serializing_if = "Option::is_none")]
1649    pub priority: Option<f64>,
1650}
1651
1652impl Content {
1653    /// Extract the text from a [`Content::Text`] variant.
1654    ///
1655    /// Returns `None` for non-text content variants.
1656    ///
1657    /// # Example
1658    ///
1659    /// ```rust
1660    /// use tower_mcp::Content;
1661    ///
1662    /// let content = Content::Text { text: "hello".into(), annotations: None };
1663    /// assert_eq!(content.as_text(), Some("hello"));
1664    /// ```
1665    pub fn as_text(&self) -> Option<&str> {
1666        match self {
1667            Content::Text { text, .. } => Some(text),
1668            _ => None,
1669        }
1670    }
1671}
1672
1673/// Role indicating who content is intended for.
1674///
1675/// Used in content annotations to specify the target audience.
1676#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1677#[serde(rename_all = "lowercase")]
1678pub enum ContentRole {
1679    /// Content intended for the human user.
1680    User,
1681    /// Content intended for the AI assistant.
1682    Assistant,
1683}
1684
1685/// Content of an embedded resource.
1686///
1687/// Contains either text or binary (blob) content along with metadata.
1688#[derive(Debug, Clone, Serialize, Deserialize)]
1689#[serde(rename_all = "camelCase")]
1690pub struct ResourceContent {
1691    /// The URI identifying this resource.
1692    pub uri: String,
1693    /// MIME type of the content.
1694    #[serde(skip_serializing_if = "Option::is_none")]
1695    pub mime_type: Option<String>,
1696    /// Text content (for text-based resources).
1697    #[serde(skip_serializing_if = "Option::is_none")]
1698    pub text: Option<String>,
1699    /// Base64-encoded binary content (for binary resources).
1700    #[serde(skip_serializing_if = "Option::is_none")]
1701    pub blob: Option<String>,
1702}
1703
1704// =============================================================================
1705// Resources
1706// =============================================================================
1707
1708#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1709pub struct ListResourcesParams {
1710    #[serde(default)]
1711    pub cursor: Option<String>,
1712}
1713
1714#[derive(Debug, Clone, Serialize, Deserialize)]
1715#[serde(rename_all = "camelCase")]
1716pub struct ListResourcesResult {
1717    pub resources: Vec<ResourceDefinition>,
1718    #[serde(default, skip_serializing_if = "Option::is_none")]
1719    pub next_cursor: Option<String>,
1720}
1721
1722#[derive(Debug, Clone, Serialize, Deserialize)]
1723#[serde(rename_all = "camelCase")]
1724pub struct ResourceDefinition {
1725    pub uri: String,
1726    pub name: String,
1727    /// Human-readable title for display purposes
1728    #[serde(skip_serializing_if = "Option::is_none")]
1729    pub title: Option<String>,
1730    #[serde(skip_serializing_if = "Option::is_none")]
1731    pub description: Option<String>,
1732    #[serde(skip_serializing_if = "Option::is_none")]
1733    pub mime_type: Option<String>,
1734    /// Optional icons for display in user interfaces
1735    #[serde(skip_serializing_if = "Option::is_none")]
1736    pub icons: Option<Vec<ToolIcon>>,
1737    /// Size of the resource in bytes (if known)
1738    #[serde(skip_serializing_if = "Option::is_none")]
1739    pub size: Option<u64>,
1740}
1741
1742#[derive(Debug, Clone, Serialize, Deserialize)]
1743pub struct ReadResourceParams {
1744    pub uri: String,
1745}
1746
1747#[derive(Debug, Clone, Serialize, Deserialize)]
1748pub struct ReadResourceResult {
1749    pub contents: Vec<ResourceContent>,
1750}
1751
1752impl ReadResourceResult {
1753    /// Create a result with text content.
1754    ///
1755    /// # Example
1756    ///
1757    /// ```rust
1758    /// use tower_mcp::ReadResourceResult;
1759    ///
1760    /// let result = ReadResourceResult::text("file://readme.md", "# Hello World");
1761    /// ```
1762    pub fn text(uri: impl Into<String>, content: impl Into<String>) -> Self {
1763        Self {
1764            contents: vec![ResourceContent {
1765                uri: uri.into(),
1766                mime_type: Some("text/plain".to_string()),
1767                text: Some(content.into()),
1768                blob: None,
1769            }],
1770        }
1771    }
1772
1773    /// Create a result with text content and a specific MIME type.
1774    ///
1775    /// # Example
1776    ///
1777    /// ```rust
1778    /// use tower_mcp::ReadResourceResult;
1779    ///
1780    /// let result = ReadResourceResult::text_with_mime(
1781    ///     "file://readme.md",
1782    ///     "# Hello World",
1783    ///     "text/markdown"
1784    /// );
1785    /// ```
1786    pub fn text_with_mime(
1787        uri: impl Into<String>,
1788        content: impl Into<String>,
1789        mime_type: impl Into<String>,
1790    ) -> Self {
1791        Self {
1792            contents: vec![ResourceContent {
1793                uri: uri.into(),
1794                mime_type: Some(mime_type.into()),
1795                text: Some(content.into()),
1796                blob: None,
1797            }],
1798        }
1799    }
1800
1801    /// Create a result with JSON content.
1802    ///
1803    /// The value is serialized to a JSON string automatically.
1804    ///
1805    /// # Example
1806    ///
1807    /// ```rust
1808    /// use tower_mcp::ReadResourceResult;
1809    /// use serde_json::json;
1810    ///
1811    /// let data = json!({"name": "example", "count": 42});
1812    /// let result = ReadResourceResult::json("data://config", &data);
1813    /// ```
1814    pub fn json<T: serde::Serialize>(uri: impl Into<String>, value: &T) -> Self {
1815        let json_string =
1816            serde_json::to_string_pretty(value).unwrap_or_else(|_| "null".to_string());
1817        Self {
1818            contents: vec![ResourceContent {
1819                uri: uri.into(),
1820                mime_type: Some("application/json".to_string()),
1821                text: Some(json_string),
1822                blob: None,
1823            }],
1824        }
1825    }
1826
1827    /// Create a result with binary content (base64 encoded).
1828    ///
1829    /// # Example
1830    ///
1831    /// ```rust
1832    /// use tower_mcp::ReadResourceResult;
1833    ///
1834    /// let bytes = vec![0x89, 0x50, 0x4E, 0x47]; // PNG magic bytes
1835    /// let result = ReadResourceResult::blob("file://image.png", &bytes);
1836    /// ```
1837    pub fn blob(uri: impl Into<String>, bytes: &[u8]) -> Self {
1838        use base64::Engine;
1839        let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
1840        Self {
1841            contents: vec![ResourceContent {
1842                uri: uri.into(),
1843                mime_type: Some("application/octet-stream".to_string()),
1844                text: None,
1845                blob: Some(encoded),
1846            }],
1847        }
1848    }
1849
1850    /// Create a result with binary content and a specific MIME type.
1851    ///
1852    /// # Example
1853    ///
1854    /// ```rust
1855    /// use tower_mcp::ReadResourceResult;
1856    ///
1857    /// let bytes = vec![0x89, 0x50, 0x4E, 0x47];
1858    /// let result = ReadResourceResult::blob_with_mime("file://image.png", &bytes, "image/png");
1859    /// ```
1860    pub fn blob_with_mime(
1861        uri: impl Into<String>,
1862        bytes: &[u8],
1863        mime_type: impl Into<String>,
1864    ) -> Self {
1865        use base64::Engine;
1866        let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
1867        Self {
1868            contents: vec![ResourceContent {
1869                uri: uri.into(),
1870                mime_type: Some(mime_type.into()),
1871                text: None,
1872                blob: Some(encoded),
1873            }],
1874        }
1875    }
1876
1877    /// Get the text from the first content item.
1878    ///
1879    /// Returns `None` if there are no contents or the first item has no text.
1880    ///
1881    /// # Example
1882    ///
1883    /// ```rust
1884    /// use tower_mcp::ReadResourceResult;
1885    ///
1886    /// let result = ReadResourceResult::text("file://readme.md", "# Hello");
1887    /// assert_eq!(result.first_text(), Some("# Hello"));
1888    /// ```
1889    pub fn first_text(&self) -> Option<&str> {
1890        self.contents.first().and_then(|c| c.text.as_deref())
1891    }
1892
1893    /// Get the URI from the first content item.
1894    ///
1895    /// Returns `None` if there are no contents.
1896    ///
1897    /// # Example
1898    ///
1899    /// ```rust
1900    /// use tower_mcp::ReadResourceResult;
1901    ///
1902    /// let result = ReadResourceResult::text("file://readme.md", "# Hello");
1903    /// assert_eq!(result.first_uri(), Some("file://readme.md"));
1904    /// ```
1905    pub fn first_uri(&self) -> Option<&str> {
1906        self.contents.first().map(|c| c.uri.as_str())
1907    }
1908}
1909
1910#[derive(Debug, Clone, Deserialize)]
1911pub struct SubscribeResourceParams {
1912    pub uri: String,
1913}
1914
1915#[derive(Debug, Clone, Deserialize)]
1916pub struct UnsubscribeResourceParams {
1917    pub uri: String,
1918}
1919
1920/// Parameters for listing resource templates
1921#[derive(Debug, Clone, Default, Deserialize)]
1922pub struct ListResourceTemplatesParams {
1923    /// Pagination cursor from previous response
1924    #[serde(default)]
1925    pub cursor: Option<String>,
1926}
1927
1928/// Result of listing resource templates
1929#[derive(Debug, Clone, Serialize)]
1930#[serde(rename_all = "camelCase")]
1931pub struct ListResourceTemplatesResult {
1932    /// Available resource templates
1933    pub resource_templates: Vec<ResourceTemplateDefinition>,
1934    /// Cursor for next page (if more templates available)
1935    #[serde(skip_serializing_if = "Option::is_none")]
1936    pub next_cursor: Option<String>,
1937}
1938
1939/// Definition of a resource template as returned by resources/templates/list
1940///
1941/// Resource templates allow servers to expose parameterized resources using
1942/// [URI templates (RFC 6570)](https://datatracker.ietf.org/doc/html/rfc6570).
1943///
1944/// # Example
1945///
1946/// ```json
1947/// {
1948///     "uriTemplate": "file:///{path}",
1949///     "name": "Project Files",
1950///     "description": "Access files in the project directory",
1951///     "mimeType": "application/octet-stream"
1952/// }
1953/// ```
1954#[derive(Debug, Clone, Serialize, Deserialize)]
1955#[serde(rename_all = "camelCase")]
1956pub struct ResourceTemplateDefinition {
1957    /// URI template following RFC 6570 (e.g., `file:///{path}`)
1958    pub uri_template: String,
1959    /// Human-readable name for this template
1960    pub name: String,
1961    /// Human-readable title for display purposes
1962    #[serde(skip_serializing_if = "Option::is_none")]
1963    pub title: Option<String>,
1964    /// Description of what resources this template provides
1965    #[serde(skip_serializing_if = "Option::is_none")]
1966    pub description: Option<String>,
1967    /// MIME type hint for resources from this template
1968    #[serde(skip_serializing_if = "Option::is_none")]
1969    pub mime_type: Option<String>,
1970    /// Optional icons for display in user interfaces
1971    #[serde(skip_serializing_if = "Option::is_none")]
1972    pub icons: Option<Vec<ToolIcon>>,
1973}
1974
1975// =============================================================================
1976// Prompts
1977// =============================================================================
1978
1979#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1980pub struct ListPromptsParams {
1981    #[serde(default)]
1982    pub cursor: Option<String>,
1983}
1984
1985#[derive(Debug, Clone, Serialize, Deserialize)]
1986#[serde(rename_all = "camelCase")]
1987pub struct ListPromptsResult {
1988    pub prompts: Vec<PromptDefinition>,
1989    #[serde(default, skip_serializing_if = "Option::is_none")]
1990    pub next_cursor: Option<String>,
1991}
1992
1993#[derive(Debug, Clone, Serialize, Deserialize)]
1994pub struct PromptDefinition {
1995    pub name: String,
1996    /// Human-readable title for display purposes
1997    #[serde(skip_serializing_if = "Option::is_none")]
1998    pub title: Option<String>,
1999    #[serde(skip_serializing_if = "Option::is_none")]
2000    pub description: Option<String>,
2001    /// Optional icons for display in user interfaces
2002    #[serde(skip_serializing_if = "Option::is_none")]
2003    pub icons: Option<Vec<ToolIcon>>,
2004    #[serde(default, skip_serializing_if = "Vec::is_empty")]
2005    pub arguments: Vec<PromptArgument>,
2006}
2007
2008#[derive(Debug, Clone, Serialize, Deserialize)]
2009pub struct PromptArgument {
2010    pub name: String,
2011    #[serde(skip_serializing_if = "Option::is_none")]
2012    pub description: Option<String>,
2013    #[serde(default)]
2014    pub required: bool,
2015}
2016
2017#[derive(Debug, Clone, Serialize, Deserialize)]
2018pub struct GetPromptParams {
2019    pub name: String,
2020    #[serde(default)]
2021    pub arguments: std::collections::HashMap<String, String>,
2022}
2023
2024#[derive(Debug, Clone, Serialize, Deserialize)]
2025pub struct GetPromptResult {
2026    #[serde(default, skip_serializing_if = "Option::is_none")]
2027    pub description: Option<String>,
2028    pub messages: Vec<PromptMessage>,
2029}
2030
2031impl GetPromptResult {
2032    /// Create a result with a single user message.
2033    ///
2034    /// # Example
2035    ///
2036    /// ```rust
2037    /// use tower_mcp::GetPromptResult;
2038    ///
2039    /// let result = GetPromptResult::user_message("Please analyze this code.");
2040    /// ```
2041    pub fn user_message(text: impl Into<String>) -> Self {
2042        Self {
2043            description: None,
2044            messages: vec![PromptMessage {
2045                role: PromptRole::User,
2046                content: Content::Text {
2047                    text: text.into(),
2048                    annotations: None,
2049                },
2050            }],
2051        }
2052    }
2053
2054    /// Create a result with a single user message and description.
2055    ///
2056    /// # Example
2057    ///
2058    /// ```rust
2059    /// use tower_mcp::GetPromptResult;
2060    ///
2061    /// let result = GetPromptResult::user_message_with_description(
2062    ///     "Please analyze this code.",
2063    ///     "Code analysis prompt"
2064    /// );
2065    /// ```
2066    pub fn user_message_with_description(
2067        text: impl Into<String>,
2068        description: impl Into<String>,
2069    ) -> Self {
2070        Self {
2071            description: Some(description.into()),
2072            messages: vec![PromptMessage {
2073                role: PromptRole::User,
2074                content: Content::Text {
2075                    text: text.into(),
2076                    annotations: None,
2077                },
2078            }],
2079        }
2080    }
2081
2082    /// Create a result with a single assistant message.
2083    ///
2084    /// # Example
2085    ///
2086    /// ```rust
2087    /// use tower_mcp::GetPromptResult;
2088    ///
2089    /// let result = GetPromptResult::assistant_message("Here is my analysis...");
2090    /// ```
2091    pub fn assistant_message(text: impl Into<String>) -> Self {
2092        Self {
2093            description: None,
2094            messages: vec![PromptMessage {
2095                role: PromptRole::Assistant,
2096                content: Content::Text {
2097                    text: text.into(),
2098                    annotations: None,
2099                },
2100            }],
2101        }
2102    }
2103
2104    /// Create a builder for constructing prompts with multiple messages.
2105    ///
2106    /// # Example
2107    ///
2108    /// ```rust
2109    /// use tower_mcp::GetPromptResult;
2110    ///
2111    /// let result = GetPromptResult::builder()
2112    ///     .description("Multi-turn conversation prompt")
2113    ///     .user("What is the weather today?")
2114    ///     .assistant("I don't have access to weather data, but I can help you find it.")
2115    ///     .user("Where should I look?")
2116    ///     .build();
2117    /// ```
2118    pub fn builder() -> GetPromptResultBuilder {
2119        GetPromptResultBuilder::new()
2120    }
2121
2122    /// Get the text from the first message's content.
2123    ///
2124    /// Returns `None` if there are no messages or the first message
2125    /// does not contain text content.
2126    ///
2127    /// # Example
2128    ///
2129    /// ```rust
2130    /// use tower_mcp::GetPromptResult;
2131    ///
2132    /// let result = GetPromptResult::user_message("Analyze this code.");
2133    /// assert_eq!(result.first_message_text(), Some("Analyze this code."));
2134    /// ```
2135    pub fn first_message_text(&self) -> Option<&str> {
2136        self.messages.first().and_then(|m| m.content.as_text())
2137    }
2138}
2139
2140/// Builder for constructing [`GetPromptResult`] with multiple messages.
2141#[derive(Debug, Clone, Default)]
2142pub struct GetPromptResultBuilder {
2143    description: Option<String>,
2144    messages: Vec<PromptMessage>,
2145}
2146
2147impl GetPromptResultBuilder {
2148    /// Create a new builder.
2149    pub fn new() -> Self {
2150        Self::default()
2151    }
2152
2153    /// Set the prompt description.
2154    pub fn description(mut self, description: impl Into<String>) -> Self {
2155        self.description = Some(description.into());
2156        self
2157    }
2158
2159    /// Add a user message.
2160    pub fn user(mut self, text: impl Into<String>) -> Self {
2161        self.messages.push(PromptMessage {
2162            role: PromptRole::User,
2163            content: Content::Text {
2164                text: text.into(),
2165                annotations: None,
2166            },
2167        });
2168        self
2169    }
2170
2171    /// Add an assistant message.
2172    pub fn assistant(mut self, text: impl Into<String>) -> Self {
2173        self.messages.push(PromptMessage {
2174            role: PromptRole::Assistant,
2175            content: Content::Text {
2176                text: text.into(),
2177                annotations: None,
2178            },
2179        });
2180        self
2181    }
2182
2183    /// Build the final result.
2184    pub fn build(self) -> GetPromptResult {
2185        GetPromptResult {
2186            description: self.description,
2187            messages: self.messages,
2188        }
2189    }
2190}
2191
2192#[derive(Debug, Clone, Serialize, Deserialize)]
2193pub struct PromptMessage {
2194    pub role: PromptRole,
2195    pub content: Content,
2196}
2197
2198#[derive(Debug, Clone, Serialize, Deserialize)]
2199#[serde(rename_all = "lowercase")]
2200pub enum PromptRole {
2201    User,
2202    Assistant,
2203}
2204
2205// =============================================================================
2206// Tasks (async operations)
2207// =============================================================================
2208
2209/// Status of an async task
2210#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2211#[serde(rename_all = "snake_case")]
2212pub enum TaskStatus {
2213    /// Task is actively being processed
2214    Working,
2215    /// Task requires user input to continue
2216    InputRequired,
2217    /// Task completed successfully
2218    Completed,
2219    /// Task failed with an error
2220    Failed,
2221    /// Task was cancelled by user request
2222    Cancelled,
2223}
2224
2225impl std::fmt::Display for TaskStatus {
2226    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2227        match self {
2228            TaskStatus::Working => write!(f, "working"),
2229            TaskStatus::InputRequired => write!(f, "input_required"),
2230            TaskStatus::Completed => write!(f, "completed"),
2231            TaskStatus::Failed => write!(f, "failed"),
2232            TaskStatus::Cancelled => write!(f, "cancelled"),
2233        }
2234    }
2235}
2236
2237impl TaskStatus {
2238    /// Check if this status represents a terminal state
2239    pub fn is_terminal(&self) -> bool {
2240        matches!(
2241            self,
2242            TaskStatus::Completed | TaskStatus::Failed | TaskStatus::Cancelled
2243        )
2244    }
2245}
2246
2247/// Information about a task
2248#[derive(Debug, Clone, Serialize, Deserialize)]
2249#[serde(rename_all = "camelCase")]
2250pub struct TaskInfo {
2251    /// Unique task identifier
2252    pub task_id: String,
2253    /// Current task status
2254    pub status: TaskStatus,
2255    /// ISO 8601 timestamp when the task was created
2256    pub created_at: String,
2257    /// Time-to-live in seconds (how long to keep the result after completion)
2258    #[serde(skip_serializing_if = "Option::is_none")]
2259    pub ttl: Option<u64>,
2260    /// Suggested polling interval in seconds
2261    #[serde(skip_serializing_if = "Option::is_none")]
2262    pub poll_interval: Option<u64>,
2263    /// Progress percentage (0-100) if available
2264    #[serde(skip_serializing_if = "Option::is_none")]
2265    pub progress: Option<f64>,
2266    /// Human-readable status message
2267    #[serde(skip_serializing_if = "Option::is_none")]
2268    pub message: Option<String>,
2269}
2270
2271/// Parameters for enqueuing a task
2272#[derive(Debug, Clone, Deserialize)]
2273#[serde(rename_all = "camelCase")]
2274pub struct EnqueueTaskParams {
2275    /// Tool name to execute
2276    pub tool_name: String,
2277    /// Arguments to pass to the tool
2278    #[serde(default)]
2279    pub arguments: Value,
2280    /// Optional time-to-live for the task result in seconds
2281    #[serde(default)]
2282    pub ttl: Option<u64>,
2283}
2284
2285/// Result of enqueuing a task
2286#[derive(Debug, Clone, Serialize)]
2287#[serde(rename_all = "camelCase")]
2288pub struct EnqueueTaskResult {
2289    /// The task ID for tracking
2290    pub task_id: String,
2291    /// Initial status (should be Working)
2292    pub status: TaskStatus,
2293    /// Suggested polling interval in seconds
2294    #[serde(skip_serializing_if = "Option::is_none")]
2295    pub poll_interval: Option<u64>,
2296}
2297
2298/// Parameters for listing tasks
2299#[derive(Debug, Clone, Default, Deserialize)]
2300#[serde(rename_all = "camelCase")]
2301pub struct ListTasksParams {
2302    /// Filter by status (optional)
2303    #[serde(default)]
2304    pub status: Option<TaskStatus>,
2305    /// Pagination cursor
2306    #[serde(default)]
2307    pub cursor: Option<String>,
2308}
2309
2310/// Result of listing tasks
2311#[derive(Debug, Clone, Serialize)]
2312#[serde(rename_all = "camelCase")]
2313pub struct ListTasksResult {
2314    /// List of tasks
2315    pub tasks: Vec<TaskInfo>,
2316    /// Next cursor for pagination
2317    #[serde(skip_serializing_if = "Option::is_none")]
2318    pub next_cursor: Option<String>,
2319}
2320
2321/// Parameters for getting task info
2322#[derive(Debug, Clone, Deserialize)]
2323#[serde(rename_all = "camelCase")]
2324pub struct GetTaskInfoParams {
2325    /// Task ID to query
2326    pub task_id: String,
2327}
2328
2329/// Result of getting task info
2330pub type GetTaskInfoResult = TaskInfo;
2331
2332/// Parameters for getting task result
2333#[derive(Debug, Clone, Deserialize)]
2334#[serde(rename_all = "camelCase")]
2335pub struct GetTaskResultParams {
2336    /// Task ID to get result for
2337    pub task_id: String,
2338}
2339
2340/// Result of getting task result
2341#[derive(Debug, Clone, Serialize)]
2342#[serde(rename_all = "camelCase")]
2343pub struct GetTaskResultResult {
2344    /// Task ID
2345    pub task_id: String,
2346    /// Task status
2347    pub status: TaskStatus,
2348    /// The tool call result (if completed)
2349    #[serde(skip_serializing_if = "Option::is_none")]
2350    pub result: Option<CallToolResult>,
2351    /// Error message (if failed)
2352    #[serde(skip_serializing_if = "Option::is_none")]
2353    pub error: Option<String>,
2354}
2355
2356/// Parameters for cancelling a task
2357#[derive(Debug, Clone, Deserialize)]
2358#[serde(rename_all = "camelCase")]
2359pub struct CancelTaskParams {
2360    /// Task ID to cancel
2361    pub task_id: String,
2362    /// Optional reason for cancellation
2363    #[serde(default)]
2364    pub reason: Option<String>,
2365}
2366
2367/// Result of cancelling a task
2368#[derive(Debug, Clone, Serialize)]
2369#[serde(rename_all = "camelCase")]
2370pub struct CancelTaskResult {
2371    /// Whether the cancellation was successful
2372    pub cancelled: bool,
2373    /// Updated task status
2374    pub status: TaskStatus,
2375}
2376
2377/// Notification params when task status changes
2378#[derive(Debug, Clone, Serialize, Deserialize)]
2379#[serde(rename_all = "camelCase")]
2380pub struct TaskStatusChangedParams {
2381    /// Task ID
2382    pub task_id: String,
2383    /// New status
2384    pub status: TaskStatus,
2385    /// Human-readable message
2386    #[serde(skip_serializing_if = "Option::is_none")]
2387    pub message: Option<String>,
2388}
2389
2390// =============================================================================
2391// Elicitation (server-to-client user input requests)
2392// =============================================================================
2393
2394/// Parameters for form-based elicitation request
2395#[derive(Debug, Clone, Serialize, Deserialize)]
2396#[serde(rename_all = "camelCase")]
2397pub struct ElicitFormParams {
2398    /// The elicitation mode
2399    pub mode: ElicitMode,
2400    /// Message to present to the user explaining what information is needed
2401    pub message: String,
2402    /// Schema for the form fields (restricted subset of JSON Schema)
2403    pub requested_schema: ElicitFormSchema,
2404    /// Request metadata including progress token
2405    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2406    pub meta: Option<RequestMeta>,
2407}
2408
2409/// Parameters for URL-based elicitation request
2410#[derive(Debug, Clone, Serialize, Deserialize)]
2411#[serde(rename_all = "camelCase")]
2412pub struct ElicitUrlParams {
2413    /// The elicitation mode
2414    pub mode: ElicitMode,
2415    /// Unique ID for this elicitation (opaque to client)
2416    pub elicitation_id: String,
2417    /// Message explaining why the user needs to navigate to the URL
2418    pub message: String,
2419    /// The URL the user should navigate to
2420    pub url: String,
2421    /// Request metadata including progress token
2422    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2423    pub meta: Option<RequestMeta>,
2424}
2425
2426/// Elicitation request parameters (union of form and URL modes)
2427#[derive(Debug, Clone, Serialize, Deserialize)]
2428#[serde(untagged)]
2429pub enum ElicitRequestParams {
2430    Form(ElicitFormParams),
2431    Url(ElicitUrlParams),
2432}
2433
2434/// Elicitation mode
2435#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2436#[serde(rename_all = "lowercase")]
2437pub enum ElicitMode {
2438    /// Form-based elicitation with structured input
2439    Form,
2440    /// URL-based elicitation (out-of-band)
2441    Url,
2442}
2443
2444/// Restricted JSON Schema for elicitation forms
2445///
2446/// Only allows top-level properties with primitive types.
2447#[derive(Debug, Clone, Serialize, Deserialize)]
2448pub struct ElicitFormSchema {
2449    /// Must be "object"
2450    #[serde(rename = "type")]
2451    pub schema_type: String,
2452    /// Map of property names to their schema definitions
2453    pub properties: std::collections::HashMap<String, PrimitiveSchemaDefinition>,
2454    /// List of required property names
2455    #[serde(default, skip_serializing_if = "Vec::is_empty")]
2456    pub required: Vec<String>,
2457}
2458
2459impl ElicitFormSchema {
2460    /// Create a new form schema
2461    pub fn new() -> Self {
2462        Self {
2463            schema_type: "object".to_string(),
2464            properties: std::collections::HashMap::new(),
2465            required: Vec::new(),
2466        }
2467    }
2468
2469    /// Add a string field
2470    pub fn string_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2471        self.properties.insert(
2472            name.to_string(),
2473            PrimitiveSchemaDefinition::String(StringSchema {
2474                schema_type: "string".to_string(),
2475                description: description.map(|s| s.to_string()),
2476                format: None,
2477                min_length: None,
2478                max_length: None,
2479                default: None,
2480            }),
2481        );
2482        if required {
2483            self.required.push(name.to_string());
2484        }
2485        self
2486    }
2487
2488    /// Add a string field with a default value
2489    pub fn string_field_with_default(
2490        mut self,
2491        name: &str,
2492        description: Option<&str>,
2493        required: bool,
2494        default: &str,
2495    ) -> Self {
2496        self.properties.insert(
2497            name.to_string(),
2498            PrimitiveSchemaDefinition::String(StringSchema {
2499                schema_type: "string".to_string(),
2500                description: description.map(|s| s.to_string()),
2501                format: None,
2502                min_length: None,
2503                max_length: None,
2504                default: Some(default.to_string()),
2505            }),
2506        );
2507        if required {
2508            self.required.push(name.to_string());
2509        }
2510        self
2511    }
2512
2513    /// Add an integer field
2514    pub fn integer_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2515        self.properties.insert(
2516            name.to_string(),
2517            PrimitiveSchemaDefinition::Integer(IntegerSchema {
2518                schema_type: "integer".to_string(),
2519                description: description.map(|s| s.to_string()),
2520                minimum: None,
2521                maximum: None,
2522                default: None,
2523            }),
2524        );
2525        if required {
2526            self.required.push(name.to_string());
2527        }
2528        self
2529    }
2530
2531    /// Add an integer field with a default value
2532    pub fn integer_field_with_default(
2533        mut self,
2534        name: &str,
2535        description: Option<&str>,
2536        required: bool,
2537        default: i64,
2538    ) -> Self {
2539        self.properties.insert(
2540            name.to_string(),
2541            PrimitiveSchemaDefinition::Integer(IntegerSchema {
2542                schema_type: "integer".to_string(),
2543                description: description.map(|s| s.to_string()),
2544                minimum: None,
2545                maximum: None,
2546                default: Some(default),
2547            }),
2548        );
2549        if required {
2550            self.required.push(name.to_string());
2551        }
2552        self
2553    }
2554
2555    /// Add a number field
2556    pub fn number_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2557        self.properties.insert(
2558            name.to_string(),
2559            PrimitiveSchemaDefinition::Number(NumberSchema {
2560                schema_type: "number".to_string(),
2561                description: description.map(|s| s.to_string()),
2562                minimum: None,
2563                maximum: None,
2564                default: None,
2565            }),
2566        );
2567        if required {
2568            self.required.push(name.to_string());
2569        }
2570        self
2571    }
2572
2573    /// Add a number field with a default value
2574    pub fn number_field_with_default(
2575        mut self,
2576        name: &str,
2577        description: Option<&str>,
2578        required: bool,
2579        default: f64,
2580    ) -> Self {
2581        self.properties.insert(
2582            name.to_string(),
2583            PrimitiveSchemaDefinition::Number(NumberSchema {
2584                schema_type: "number".to_string(),
2585                description: description.map(|s| s.to_string()),
2586                minimum: None,
2587                maximum: None,
2588                default: Some(default),
2589            }),
2590        );
2591        if required {
2592            self.required.push(name.to_string());
2593        }
2594        self
2595    }
2596
2597    /// Add a boolean field
2598    pub fn boolean_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2599        self.properties.insert(
2600            name.to_string(),
2601            PrimitiveSchemaDefinition::Boolean(BooleanSchema {
2602                schema_type: "boolean".to_string(),
2603                description: description.map(|s| s.to_string()),
2604                default: None,
2605            }),
2606        );
2607        if required {
2608            self.required.push(name.to_string());
2609        }
2610        self
2611    }
2612
2613    /// Add a boolean field with a default value
2614    pub fn boolean_field_with_default(
2615        mut self,
2616        name: &str,
2617        description: Option<&str>,
2618        required: bool,
2619        default: bool,
2620    ) -> Self {
2621        self.properties.insert(
2622            name.to_string(),
2623            PrimitiveSchemaDefinition::Boolean(BooleanSchema {
2624                schema_type: "boolean".to_string(),
2625                description: description.map(|s| s.to_string()),
2626                default: Some(default),
2627            }),
2628        );
2629        if required {
2630            self.required.push(name.to_string());
2631        }
2632        self
2633    }
2634
2635    /// Add a single-select enum field
2636    pub fn enum_field(
2637        mut self,
2638        name: &str,
2639        description: Option<&str>,
2640        options: Vec<String>,
2641        required: bool,
2642    ) -> Self {
2643        self.properties.insert(
2644            name.to_string(),
2645            PrimitiveSchemaDefinition::SingleSelectEnum(SingleSelectEnumSchema {
2646                schema_type: "string".to_string(),
2647                description: description.map(|s| s.to_string()),
2648                enum_values: options,
2649                default: None,
2650            }),
2651        );
2652        if required {
2653            self.required.push(name.to_string());
2654        }
2655        self
2656    }
2657
2658    /// Add a single-select enum field with a default value
2659    pub fn enum_field_with_default(
2660        mut self,
2661        name: &str,
2662        description: Option<&str>,
2663        required: bool,
2664        options: &[&str],
2665        default: &str,
2666    ) -> Self {
2667        self.properties.insert(
2668            name.to_string(),
2669            PrimitiveSchemaDefinition::SingleSelectEnum(SingleSelectEnumSchema {
2670                schema_type: "string".to_string(),
2671                description: description.map(|s| s.to_string()),
2672                enum_values: options.iter().map(|s| s.to_string()).collect(),
2673                default: Some(default.to_string()),
2674            }),
2675        );
2676        if required {
2677            self.required.push(name.to_string());
2678        }
2679        self
2680    }
2681
2682    /// Add a raw JSON schema field
2683    ///
2684    /// Use this for advanced schema features not covered by the typed builders.
2685    pub fn raw_field(mut self, name: &str, schema: serde_json::Value, required: bool) -> Self {
2686        self.properties
2687            .insert(name.to_string(), PrimitiveSchemaDefinition::Raw(schema));
2688        if required {
2689            self.required.push(name.to_string());
2690        }
2691        self
2692    }
2693}
2694
2695impl Default for ElicitFormSchema {
2696    fn default() -> Self {
2697        Self::new()
2698    }
2699}
2700
2701/// Primitive schema definition for form fields
2702#[derive(Debug, Clone, Serialize, Deserialize)]
2703#[serde(untagged)]
2704pub enum PrimitiveSchemaDefinition {
2705    /// String field
2706    String(StringSchema),
2707    /// Integer field
2708    Integer(IntegerSchema),
2709    /// Number (floating-point) field
2710    Number(NumberSchema),
2711    /// Boolean field
2712    Boolean(BooleanSchema),
2713    /// Single-select enum field
2714    SingleSelectEnum(SingleSelectEnumSchema),
2715    /// Multi-select enum field
2716    MultiSelectEnum(MultiSelectEnumSchema),
2717    /// Raw JSON schema (for advanced/custom schemas)
2718    Raw(serde_json::Value),
2719}
2720
2721/// String field schema
2722#[derive(Debug, Clone, Serialize, Deserialize)]
2723#[serde(rename_all = "camelCase")]
2724pub struct StringSchema {
2725    #[serde(rename = "type")]
2726    pub schema_type: String,
2727    #[serde(skip_serializing_if = "Option::is_none")]
2728    pub description: Option<String>,
2729    #[serde(skip_serializing_if = "Option::is_none")]
2730    pub format: Option<String>,
2731    #[serde(skip_serializing_if = "Option::is_none")]
2732    pub min_length: Option<u64>,
2733    #[serde(skip_serializing_if = "Option::is_none")]
2734    pub max_length: Option<u64>,
2735    /// Default value for this field
2736    #[serde(skip_serializing_if = "Option::is_none")]
2737    pub default: Option<String>,
2738}
2739
2740/// Integer field schema
2741#[derive(Debug, Clone, Serialize, Deserialize)]
2742#[serde(rename_all = "camelCase")]
2743pub struct IntegerSchema {
2744    #[serde(rename = "type")]
2745    pub schema_type: String,
2746    #[serde(skip_serializing_if = "Option::is_none")]
2747    pub description: Option<String>,
2748    #[serde(skip_serializing_if = "Option::is_none")]
2749    pub minimum: Option<i64>,
2750    #[serde(skip_serializing_if = "Option::is_none")]
2751    pub maximum: Option<i64>,
2752    /// Default value for this field
2753    #[serde(skip_serializing_if = "Option::is_none")]
2754    pub default: Option<i64>,
2755}
2756
2757/// Number field schema
2758#[derive(Debug, Clone, Serialize, Deserialize)]
2759#[serde(rename_all = "camelCase")]
2760pub struct NumberSchema {
2761    #[serde(rename = "type")]
2762    pub schema_type: String,
2763    #[serde(skip_serializing_if = "Option::is_none")]
2764    pub description: Option<String>,
2765    #[serde(skip_serializing_if = "Option::is_none")]
2766    pub minimum: Option<f64>,
2767    #[serde(skip_serializing_if = "Option::is_none")]
2768    pub maximum: Option<f64>,
2769    /// Default value for this field
2770    #[serde(skip_serializing_if = "Option::is_none")]
2771    pub default: Option<f64>,
2772}
2773
2774/// Boolean field schema
2775#[derive(Debug, Clone, Serialize, Deserialize)]
2776#[serde(rename_all = "camelCase")]
2777pub struct BooleanSchema {
2778    #[serde(rename = "type")]
2779    pub schema_type: String,
2780    #[serde(skip_serializing_if = "Option::is_none")]
2781    pub description: Option<String>,
2782    /// Default value for this field
2783    #[serde(skip_serializing_if = "Option::is_none")]
2784    pub default: Option<bool>,
2785}
2786
2787/// Single-select enum schema
2788#[derive(Debug, Clone, Serialize, Deserialize)]
2789#[serde(rename_all = "camelCase")]
2790pub struct SingleSelectEnumSchema {
2791    #[serde(rename = "type")]
2792    pub schema_type: String,
2793    #[serde(skip_serializing_if = "Option::is_none")]
2794    pub description: Option<String>,
2795    #[serde(rename = "enum")]
2796    pub enum_values: Vec<String>,
2797    /// Default value for this field
2798    #[serde(skip_serializing_if = "Option::is_none")]
2799    pub default: Option<String>,
2800}
2801
2802/// Multi-select enum schema
2803#[derive(Debug, Clone, Serialize, Deserialize)]
2804#[serde(rename_all = "camelCase")]
2805pub struct MultiSelectEnumSchema {
2806    #[serde(rename = "type")]
2807    pub schema_type: String,
2808    #[serde(skip_serializing_if = "Option::is_none")]
2809    pub description: Option<String>,
2810    pub items: MultiSelectEnumItems,
2811    #[serde(skip_serializing_if = "Option::is_none")]
2812    pub unique_items: Option<bool>,
2813}
2814
2815/// Items definition for multi-select enum
2816#[derive(Debug, Clone, Serialize, Deserialize)]
2817pub struct MultiSelectEnumItems {
2818    #[serde(rename = "type")]
2819    pub schema_type: String,
2820    #[serde(rename = "enum")]
2821    pub enum_values: Vec<String>,
2822}
2823
2824/// User action in response to elicitation
2825#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2826#[serde(rename_all = "lowercase")]
2827pub enum ElicitAction {
2828    /// User submitted the form/confirmed the action
2829    Accept,
2830    /// User explicitly declined the action
2831    Decline,
2832    /// User dismissed without making an explicit choice
2833    Cancel,
2834}
2835
2836/// Result of an elicitation request
2837#[derive(Debug, Clone, Serialize, Deserialize)]
2838pub struct ElicitResult {
2839    /// The user's action
2840    pub action: ElicitAction,
2841    /// Submitted form data (only present when action is Accept and mode was Form)
2842    #[serde(default, skip_serializing_if = "Option::is_none")]
2843    pub content: Option<std::collections::HashMap<String, ElicitFieldValue>>,
2844}
2845
2846impl ElicitResult {
2847    /// Create an accept result with content
2848    pub fn accept(content: std::collections::HashMap<String, ElicitFieldValue>) -> Self {
2849        Self {
2850            action: ElicitAction::Accept,
2851            content: Some(content),
2852        }
2853    }
2854
2855    /// Create a decline result
2856    pub fn decline() -> Self {
2857        Self {
2858            action: ElicitAction::Decline,
2859            content: None,
2860        }
2861    }
2862
2863    /// Create a cancel result
2864    pub fn cancel() -> Self {
2865        Self {
2866            action: ElicitAction::Cancel,
2867            content: None,
2868        }
2869    }
2870}
2871
2872/// Value from an elicitation form field
2873#[derive(Debug, Clone, Serialize, Deserialize)]
2874#[serde(untagged)]
2875pub enum ElicitFieldValue {
2876    String(String),
2877    Number(f64),
2878    Integer(i64),
2879    Boolean(bool),
2880    StringArray(Vec<String>),
2881}
2882
2883/// Parameters for elicitation complete notification
2884#[derive(Debug, Clone, Serialize, Deserialize)]
2885#[serde(rename_all = "camelCase")]
2886pub struct ElicitationCompleteParams {
2887    /// The ID of the elicitation that completed
2888    pub elicitation_id: String,
2889}
2890
2891// =============================================================================
2892// Common
2893// =============================================================================
2894
2895#[derive(Debug, Clone, Default, Serialize)]
2896pub struct EmptyResult {}
2897
2898// =============================================================================
2899// Parsing
2900// =============================================================================
2901
2902impl McpRequest {
2903    /// Parse from JSON-RPC request
2904    pub fn from_jsonrpc(req: &JsonRpcRequest) -> Result<Self, crate::error::Error> {
2905        let params = req
2906            .params
2907            .clone()
2908            .unwrap_or(Value::Object(Default::default()));
2909
2910        match req.method.as_str() {
2911            "initialize" => {
2912                let p: InitializeParams = serde_json::from_value(params)?;
2913                Ok(McpRequest::Initialize(p))
2914            }
2915            "tools/list" => {
2916                let p: ListToolsParams = serde_json::from_value(params).unwrap_or_default();
2917                Ok(McpRequest::ListTools(p))
2918            }
2919            "tools/call" => {
2920                let p: CallToolParams = serde_json::from_value(params)?;
2921                Ok(McpRequest::CallTool(p))
2922            }
2923            "resources/list" => {
2924                let p: ListResourcesParams = serde_json::from_value(params).unwrap_or_default();
2925                Ok(McpRequest::ListResources(p))
2926            }
2927            "resources/templates/list" => {
2928                let p: ListResourceTemplatesParams =
2929                    serde_json::from_value(params).unwrap_or_default();
2930                Ok(McpRequest::ListResourceTemplates(p))
2931            }
2932            "resources/read" => {
2933                let p: ReadResourceParams = serde_json::from_value(params)?;
2934                Ok(McpRequest::ReadResource(p))
2935            }
2936            "resources/subscribe" => {
2937                let p: SubscribeResourceParams = serde_json::from_value(params)?;
2938                Ok(McpRequest::SubscribeResource(p))
2939            }
2940            "resources/unsubscribe" => {
2941                let p: UnsubscribeResourceParams = serde_json::from_value(params)?;
2942                Ok(McpRequest::UnsubscribeResource(p))
2943            }
2944            "prompts/list" => {
2945                let p: ListPromptsParams = serde_json::from_value(params).unwrap_or_default();
2946                Ok(McpRequest::ListPrompts(p))
2947            }
2948            "prompts/get" => {
2949                let p: GetPromptParams = serde_json::from_value(params)?;
2950                Ok(McpRequest::GetPrompt(p))
2951            }
2952            "tasks/enqueue" => {
2953                let p: EnqueueTaskParams = serde_json::from_value(params)?;
2954                Ok(McpRequest::EnqueueTask(p))
2955            }
2956            "tasks/list" => {
2957                let p: ListTasksParams = serde_json::from_value(params).unwrap_or_default();
2958                Ok(McpRequest::ListTasks(p))
2959            }
2960            "tasks/get" => {
2961                let p: GetTaskInfoParams = serde_json::from_value(params)?;
2962                Ok(McpRequest::GetTaskInfo(p))
2963            }
2964            "tasks/result" => {
2965                let p: GetTaskResultParams = serde_json::from_value(params)?;
2966                Ok(McpRequest::GetTaskResult(p))
2967            }
2968            "tasks/cancel" => {
2969                let p: CancelTaskParams = serde_json::from_value(params)?;
2970                Ok(McpRequest::CancelTask(p))
2971            }
2972            "ping" => Ok(McpRequest::Ping),
2973            "logging/setLevel" => {
2974                let p: SetLogLevelParams = serde_json::from_value(params)?;
2975                Ok(McpRequest::SetLoggingLevel(p))
2976            }
2977            "completion/complete" => {
2978                let p: CompleteParams = serde_json::from_value(params)?;
2979                Ok(McpRequest::Complete(p))
2980            }
2981            method => Ok(McpRequest::Unknown {
2982                method: method.to_string(),
2983                params: req.params.clone(),
2984            }),
2985        }
2986    }
2987}
2988
2989impl McpNotification {
2990    /// Parse from JSON-RPC notification
2991    pub fn from_jsonrpc(notif: &JsonRpcNotification) -> Result<Self, crate::error::Error> {
2992        let params = notif
2993            .params
2994            .clone()
2995            .unwrap_or(Value::Object(Default::default()));
2996
2997        match notif.method.as_str() {
2998            notifications::INITIALIZED => Ok(McpNotification::Initialized),
2999            notifications::CANCELLED => {
3000                let p: CancelledParams = serde_json::from_value(params)?;
3001                Ok(McpNotification::Cancelled(p))
3002            }
3003            notifications::PROGRESS => {
3004                let p: ProgressParams = serde_json::from_value(params)?;
3005                Ok(McpNotification::Progress(p))
3006            }
3007            notifications::ROOTS_LIST_CHANGED => Ok(McpNotification::RootsListChanged),
3008            method => Ok(McpNotification::Unknown {
3009                method: method.to_string(),
3010                params: notif.params.clone(),
3011            }),
3012        }
3013    }
3014}
3015
3016#[cfg(test)]
3017mod tests {
3018    use super::*;
3019
3020    #[test]
3021    fn test_elicit_form_schema_builder() {
3022        let schema = ElicitFormSchema::new()
3023            .string_field("name", Some("Your name"), true)
3024            .number_field("age", Some("Your age"), false)
3025            .boolean_field("agree", Some("Do you agree?"), true)
3026            .enum_field(
3027                "color",
3028                Some("Favorite color"),
3029                vec!["red".to_string(), "green".to_string(), "blue".to_string()],
3030                false,
3031            );
3032
3033        assert_eq!(schema.schema_type, "object");
3034        assert_eq!(schema.properties.len(), 4);
3035        assert_eq!(schema.required.len(), 2);
3036        assert!(schema.required.contains(&"name".to_string()));
3037        assert!(schema.required.contains(&"agree".to_string()));
3038    }
3039
3040    #[test]
3041    fn test_elicit_form_schema_serialization() {
3042        let schema = ElicitFormSchema::new().string_field("username", Some("Enter username"), true);
3043
3044        let json = serde_json::to_value(&schema).unwrap();
3045        assert_eq!(json["type"], "object");
3046        assert!(json["properties"]["username"]["type"] == "string");
3047        assert!(
3048            json["required"]
3049                .as_array()
3050                .unwrap()
3051                .contains(&serde_json::json!("username"))
3052        );
3053    }
3054
3055    #[test]
3056    fn test_elicit_result_accept() {
3057        let mut content = std::collections::HashMap::new();
3058        content.insert(
3059            "name".to_string(),
3060            ElicitFieldValue::String("Alice".to_string()),
3061        );
3062        content.insert("age".to_string(), ElicitFieldValue::Integer(30));
3063
3064        let result = ElicitResult::accept(content);
3065        assert_eq!(result.action, ElicitAction::Accept);
3066        assert!(result.content.is_some());
3067    }
3068
3069    #[test]
3070    fn test_elicit_result_decline() {
3071        let result = ElicitResult::decline();
3072        assert_eq!(result.action, ElicitAction::Decline);
3073        assert!(result.content.is_none());
3074    }
3075
3076    #[test]
3077    fn test_elicit_result_cancel() {
3078        let result = ElicitResult::cancel();
3079        assert_eq!(result.action, ElicitAction::Cancel);
3080        assert!(result.content.is_none());
3081    }
3082
3083    #[test]
3084    fn test_elicit_mode_serialization() {
3085        assert_eq!(
3086            serde_json::to_string(&ElicitMode::Form).unwrap(),
3087            "\"form\""
3088        );
3089        assert_eq!(serde_json::to_string(&ElicitMode::Url).unwrap(), "\"url\"");
3090    }
3091
3092    #[test]
3093    fn test_elicit_action_serialization() {
3094        assert_eq!(
3095            serde_json::to_string(&ElicitAction::Accept).unwrap(),
3096            "\"accept\""
3097        );
3098        assert_eq!(
3099            serde_json::to_string(&ElicitAction::Decline).unwrap(),
3100            "\"decline\""
3101        );
3102        assert_eq!(
3103            serde_json::to_string(&ElicitAction::Cancel).unwrap(),
3104            "\"cancel\""
3105        );
3106    }
3107
3108    #[test]
3109    fn test_elicitation_capability() {
3110        let cap = ElicitationCapability {
3111            form: Some(ElicitationFormCapability {}),
3112            url: None,
3113        };
3114
3115        let json = serde_json::to_value(&cap).unwrap();
3116        assert!(json["form"].is_object());
3117        assert!(json.get("url").is_none());
3118    }
3119
3120    #[test]
3121    fn test_client_capabilities_with_elicitation() {
3122        let caps = ClientCapabilities {
3123            roots: None,
3124            sampling: None,
3125            elicitation: Some(ElicitationCapability {
3126                form: Some(ElicitationFormCapability {}),
3127                url: Some(ElicitationUrlCapability {}),
3128            }),
3129        };
3130
3131        let json = serde_json::to_value(&caps).unwrap();
3132        assert!(json["elicitation"]["form"].is_object());
3133        assert!(json["elicitation"]["url"].is_object());
3134    }
3135
3136    #[test]
3137    fn test_elicit_url_params() {
3138        let params = ElicitUrlParams {
3139            mode: ElicitMode::Url,
3140            elicitation_id: "abc123".to_string(),
3141            message: "Please authorize".to_string(),
3142            url: "https://example.com/auth".to_string(),
3143            meta: None,
3144        };
3145
3146        let json = serde_json::to_value(&params).unwrap();
3147        assert_eq!(json["mode"], "url");
3148        assert_eq!(json["elicitationId"], "abc123");
3149        assert_eq!(json["message"], "Please authorize");
3150        assert_eq!(json["url"], "https://example.com/auth");
3151    }
3152
3153    #[test]
3154    fn test_elicitation_complete_params() {
3155        let params = ElicitationCompleteParams {
3156            elicitation_id: "xyz789".to_string(),
3157        };
3158
3159        let json = serde_json::to_value(&params).unwrap();
3160        assert_eq!(json["elicitationId"], "xyz789");
3161    }
3162
3163    #[test]
3164    fn test_root_new() {
3165        let root = Root::new("file:///home/user/project");
3166        assert_eq!(root.uri, "file:///home/user/project");
3167        assert!(root.name.is_none());
3168    }
3169
3170    #[test]
3171    fn test_root_with_name() {
3172        let root = Root::with_name("file:///home/user/project", "My Project");
3173        assert_eq!(root.uri, "file:///home/user/project");
3174        assert_eq!(root.name.as_deref(), Some("My Project"));
3175    }
3176
3177    #[test]
3178    fn test_root_serialization() {
3179        let root = Root::with_name("file:///workspace", "Workspace");
3180        let json = serde_json::to_value(&root).unwrap();
3181        assert_eq!(json["uri"], "file:///workspace");
3182        assert_eq!(json["name"], "Workspace");
3183    }
3184
3185    #[test]
3186    fn test_root_serialization_without_name() {
3187        let root = Root::new("file:///workspace");
3188        let json = serde_json::to_value(&root).unwrap();
3189        assert_eq!(json["uri"], "file:///workspace");
3190        assert!(json.get("name").is_none());
3191    }
3192
3193    #[test]
3194    fn test_root_deserialization() {
3195        let json = serde_json::json!({
3196            "uri": "file:///home/user",
3197            "name": "Home"
3198        });
3199        let root: Root = serde_json::from_value(json).unwrap();
3200        assert_eq!(root.uri, "file:///home/user");
3201        assert_eq!(root.name.as_deref(), Some("Home"));
3202    }
3203
3204    #[test]
3205    fn test_list_roots_result() {
3206        let result = ListRootsResult {
3207            roots: vec![
3208                Root::new("file:///project1"),
3209                Root::with_name("file:///project2", "Project 2"),
3210            ],
3211        };
3212
3213        let json = serde_json::to_value(&result).unwrap();
3214        let roots = json["roots"].as_array().unwrap();
3215        assert_eq!(roots.len(), 2);
3216        assert_eq!(roots[0]["uri"], "file:///project1");
3217        assert_eq!(roots[1]["name"], "Project 2");
3218    }
3219
3220    #[test]
3221    fn test_roots_capability_serialization() {
3222        let cap = RootsCapability { list_changed: true };
3223        let json = serde_json::to_value(&cap).unwrap();
3224        assert_eq!(json["listChanged"], true);
3225    }
3226
3227    #[test]
3228    fn test_client_capabilities_with_roots() {
3229        let caps = ClientCapabilities {
3230            roots: Some(RootsCapability { list_changed: true }),
3231            sampling: None,
3232            elicitation: None,
3233        };
3234
3235        let json = serde_json::to_value(&caps).unwrap();
3236        assert_eq!(json["roots"]["listChanged"], true);
3237    }
3238
3239    #[test]
3240    fn test_roots_list_changed_notification_parsing() {
3241        let notif = JsonRpcNotification {
3242            jsonrpc: "2.0".to_string(),
3243            method: notifications::ROOTS_LIST_CHANGED.to_string(),
3244            params: None,
3245        };
3246
3247        let mcp_notif = McpNotification::from_jsonrpc(&notif).unwrap();
3248        assert!(matches!(mcp_notif, McpNotification::RootsListChanged));
3249    }
3250
3251    // =========================================================================
3252    // Completion Tests
3253    // =========================================================================
3254
3255    #[test]
3256    fn test_prompt_reference() {
3257        let ref_ = PromptReference::new("my-prompt");
3258        assert_eq!(ref_.ref_type, "ref/prompt");
3259        assert_eq!(ref_.name, "my-prompt");
3260
3261        let json = serde_json::to_value(&ref_).unwrap();
3262        assert_eq!(json["type"], "ref/prompt");
3263        assert_eq!(json["name"], "my-prompt");
3264    }
3265
3266    #[test]
3267    fn test_resource_reference() {
3268        let ref_ = ResourceReference::new("file:///path/to/file");
3269        assert_eq!(ref_.ref_type, "ref/resource");
3270        assert_eq!(ref_.uri, "file:///path/to/file");
3271
3272        let json = serde_json::to_value(&ref_).unwrap();
3273        assert_eq!(json["type"], "ref/resource");
3274        assert_eq!(json["uri"], "file:///path/to/file");
3275    }
3276
3277    #[test]
3278    fn test_completion_reference_prompt() {
3279        let ref_ = CompletionReference::prompt("test-prompt");
3280        let json = serde_json::to_value(&ref_).unwrap();
3281        assert_eq!(json["type"], "ref/prompt");
3282        assert_eq!(json["name"], "test-prompt");
3283    }
3284
3285    #[test]
3286    fn test_completion_reference_resource() {
3287        let ref_ = CompletionReference::resource("file:///test");
3288        let json = serde_json::to_value(&ref_).unwrap();
3289        assert_eq!(json["type"], "ref/resource");
3290        assert_eq!(json["uri"], "file:///test");
3291    }
3292
3293    #[test]
3294    fn test_completion_argument() {
3295        let arg = CompletionArgument::new("query", "SELECT * FROM");
3296        assert_eq!(arg.name, "query");
3297        assert_eq!(arg.value, "SELECT * FROM");
3298    }
3299
3300    #[test]
3301    fn test_complete_params_serialization() {
3302        let params = CompleteParams {
3303            reference: CompletionReference::prompt("sql-prompt"),
3304            argument: CompletionArgument::new("query", "SEL"),
3305        };
3306
3307        let json = serde_json::to_value(&params).unwrap();
3308        assert_eq!(json["ref"]["type"], "ref/prompt");
3309        assert_eq!(json["ref"]["name"], "sql-prompt");
3310        assert_eq!(json["argument"]["name"], "query");
3311        assert_eq!(json["argument"]["value"], "SEL");
3312    }
3313
3314    #[test]
3315    fn test_completion_new() {
3316        let completion = Completion::new(vec!["SELECT".to_string(), "SET".to_string()]);
3317        assert_eq!(completion.values.len(), 2);
3318        assert!(completion.total.is_none());
3319        assert!(completion.has_more.is_none());
3320    }
3321
3322    #[test]
3323    fn test_completion_with_pagination() {
3324        let completion =
3325            Completion::with_pagination(vec!["a".to_string(), "b".to_string()], 100, true);
3326        assert_eq!(completion.values.len(), 2);
3327        assert_eq!(completion.total, Some(100));
3328        assert_eq!(completion.has_more, Some(true));
3329    }
3330
3331    #[test]
3332    fn test_complete_result() {
3333        let result = CompleteResult::new(vec!["option1".to_string(), "option2".to_string()]);
3334        let json = serde_json::to_value(&result).unwrap();
3335        assert!(json["completion"]["values"].is_array());
3336        assert_eq!(json["completion"]["values"][0], "option1");
3337    }
3338
3339    // =========================================================================
3340    // Sampling Tests
3341    // =========================================================================
3342
3343    #[test]
3344    fn test_model_hint() {
3345        let hint = ModelHint::new("claude-3-opus");
3346        assert_eq!(hint.name, "claude-3-opus");
3347    }
3348
3349    #[test]
3350    fn test_model_preferences_builder() {
3351        let prefs = ModelPreferences::new()
3352            .speed(0.8)
3353            .intelligence(0.9)
3354            .cost(0.5)
3355            .hint("gpt-4")
3356            .hint("claude-3");
3357
3358        assert_eq!(prefs.speed_priority, Some(0.8));
3359        assert_eq!(prefs.intelligence_priority, Some(0.9));
3360        assert_eq!(prefs.cost_priority, Some(0.5));
3361        assert_eq!(prefs.hints.len(), 2);
3362    }
3363
3364    #[test]
3365    fn test_model_preferences_clamping() {
3366        let prefs = ModelPreferences::new().speed(1.5).cost(-0.5);
3367
3368        assert_eq!(prefs.speed_priority, Some(1.0)); // Clamped to max
3369        assert_eq!(prefs.cost_priority, Some(0.0)); // Clamped to min
3370    }
3371
3372    #[test]
3373    fn test_include_context_serialization() {
3374        assert_eq!(
3375            serde_json::to_string(&IncludeContext::AllServers).unwrap(),
3376            "\"allServers\""
3377        );
3378        assert_eq!(
3379            serde_json::to_string(&IncludeContext::ThisServer).unwrap(),
3380            "\"thisServer\""
3381        );
3382        assert_eq!(
3383            serde_json::to_string(&IncludeContext::None).unwrap(),
3384            "\"none\""
3385        );
3386    }
3387
3388    #[test]
3389    fn test_sampling_message_user() {
3390        let msg = SamplingMessage::user("Hello, how are you?");
3391        assert_eq!(msg.role, ContentRole::User);
3392        assert!(
3393            matches!(msg.content, SamplingContent::Text { text } if text == "Hello, how are you?")
3394        );
3395    }
3396
3397    #[test]
3398    fn test_sampling_message_assistant() {
3399        let msg = SamplingMessage::assistant("I'm doing well!");
3400        assert_eq!(msg.role, ContentRole::Assistant);
3401    }
3402
3403    #[test]
3404    fn test_sampling_content_text_serialization() {
3405        let content = SamplingContent::Text {
3406            text: "Hello".to_string(),
3407        };
3408        let json = serde_json::to_value(&content).unwrap();
3409        assert_eq!(json["type"], "text");
3410        assert_eq!(json["text"], "Hello");
3411    }
3412
3413    #[test]
3414    fn test_sampling_content_image_serialization() {
3415        let content = SamplingContent::Image {
3416            data: "base64data".to_string(),
3417            mime_type: "image/png".to_string(),
3418        };
3419        let json = serde_json::to_value(&content).unwrap();
3420        assert_eq!(json["type"], "image");
3421        assert_eq!(json["data"], "base64data");
3422        assert_eq!(json["mimeType"], "image/png");
3423    }
3424
3425    #[test]
3426    fn test_create_message_params() {
3427        let params = CreateMessageParams::new(
3428            vec![
3429                SamplingMessage::user("What is 2+2?"),
3430                SamplingMessage::assistant("4"),
3431                SamplingMessage::user("And 3+3?"),
3432            ],
3433            100,
3434        )
3435        .system_prompt("You are a math tutor")
3436        .temperature(0.7)
3437        .stop_sequence("END")
3438        .include_context(IncludeContext::ThisServer);
3439
3440        assert_eq!(params.messages.len(), 3);
3441        assert_eq!(params.max_tokens, 100);
3442        assert_eq!(
3443            params.system_prompt.as_deref(),
3444            Some("You are a math tutor")
3445        );
3446        assert_eq!(params.temperature, Some(0.7));
3447        assert_eq!(params.stop_sequences.len(), 1);
3448        assert_eq!(params.include_context, Some(IncludeContext::ThisServer));
3449    }
3450
3451    #[test]
3452    fn test_create_message_params_serialization() {
3453        let params = CreateMessageParams::new(vec![SamplingMessage::user("Hello")], 50);
3454
3455        let json = serde_json::to_value(&params).unwrap();
3456        assert!(json["messages"].is_array());
3457        assert_eq!(json["maxTokens"], 50);
3458    }
3459
3460    #[test]
3461    fn test_create_message_result_deserialization() {
3462        let json = serde_json::json!({
3463            "content": {
3464                "type": "text",
3465                "text": "The answer is 42"
3466            },
3467            "model": "claude-3-opus",
3468            "role": "assistant",
3469            "stopReason": "end_turn"
3470        });
3471
3472        let result: CreateMessageResult = serde_json::from_value(json).unwrap();
3473        assert_eq!(result.model, "claude-3-opus");
3474        assert_eq!(result.role, ContentRole::Assistant);
3475        assert_eq!(result.stop_reason.as_deref(), Some("end_turn"));
3476    }
3477
3478    #[test]
3479    fn test_completions_capability_serialization() {
3480        let cap = CompletionsCapability {};
3481        let json = serde_json::to_value(&cap).unwrap();
3482        assert!(json.is_object());
3483    }
3484
3485    #[test]
3486    fn test_server_capabilities_with_completions() {
3487        let caps = ServerCapabilities {
3488            completions: Some(CompletionsCapability {}),
3489            ..Default::default()
3490        };
3491
3492        let json = serde_json::to_value(&caps).unwrap();
3493        assert!(json["completions"].is_object());
3494    }
3495
3496    #[test]
3497    fn test_content_resource_link_serialization() {
3498        let content = Content::ResourceLink {
3499            uri: "file:///test.txt".to_string(),
3500            name: Some("test.txt".to_string()),
3501            description: Some("A test file".to_string()),
3502            mime_type: Some("text/plain".to_string()),
3503            annotations: None,
3504        };
3505        let json = serde_json::to_value(&content).unwrap();
3506        assert_eq!(json["type"], "resource_link");
3507        assert_eq!(json["uri"], "file:///test.txt");
3508        assert_eq!(json["name"], "test.txt");
3509        assert_eq!(json["description"], "A test file");
3510        assert_eq!(json["mimeType"], "text/plain");
3511    }
3512
3513    #[test]
3514    fn test_call_tool_result_resource_link() {
3515        let result = CallToolResult::resource_link("file:///output.json");
3516        assert_eq!(result.content.len(), 1);
3517        assert!(!result.is_error);
3518        match &result.content[0] {
3519            Content::ResourceLink { uri, .. } => assert_eq!(uri, "file:///output.json"),
3520            _ => panic!("Expected ResourceLink content"),
3521        }
3522    }
3523
3524    #[test]
3525    fn test_call_tool_result_image() {
3526        let result = CallToolResult::image("base64data", "image/png");
3527        assert_eq!(result.content.len(), 1);
3528        match &result.content[0] {
3529            Content::Image {
3530                data, mime_type, ..
3531            } => {
3532                assert_eq!(data, "base64data");
3533                assert_eq!(mime_type, "image/png");
3534            }
3535            _ => panic!("Expected Image content"),
3536        }
3537    }
3538
3539    #[test]
3540    fn test_call_tool_result_audio() {
3541        let result = CallToolResult::audio("audiodata", "audio/wav");
3542        assert_eq!(result.content.len(), 1);
3543        match &result.content[0] {
3544            Content::Audio {
3545                data, mime_type, ..
3546            } => {
3547                assert_eq!(data, "audiodata");
3548                assert_eq!(mime_type, "audio/wav");
3549            }
3550            _ => panic!("Expected Audio content"),
3551        }
3552    }
3553
3554    #[test]
3555    fn test_sampling_tool_serialization() {
3556        let tool = SamplingTool {
3557            name: "get_weather".to_string(),
3558            description: Some("Get current weather".to_string()),
3559            input_schema: serde_json::json!({
3560                "type": "object",
3561                "properties": {
3562                    "location": { "type": "string" }
3563                }
3564            }),
3565        };
3566        let json = serde_json::to_value(&tool).unwrap();
3567        assert_eq!(json["name"], "get_weather");
3568        assert_eq!(json["description"], "Get current weather");
3569        assert!(json["inputSchema"]["properties"]["location"].is_object());
3570    }
3571
3572    #[test]
3573    fn test_tool_choice_modes() {
3574        let auto = ToolChoice::auto();
3575        assert_eq!(auto.mode, "auto");
3576
3577        let required = ToolChoice::required();
3578        assert_eq!(required.mode, "required");
3579
3580        let none = ToolChoice::none();
3581        assert_eq!(none.mode, "none");
3582
3583        // Test serialization
3584        let json = serde_json::to_value(&auto).unwrap();
3585        assert_eq!(json["type"], "auto");
3586    }
3587
3588    #[test]
3589    fn test_sampling_content_tool_use() {
3590        let content = SamplingContent::ToolUse {
3591            id: "tool_123".to_string(),
3592            name: "get_weather".to_string(),
3593            input: serde_json::json!({"location": "San Francisco"}),
3594        };
3595        let json = serde_json::to_value(&content).unwrap();
3596        assert_eq!(json["type"], "tool_use");
3597        assert_eq!(json["id"], "tool_123");
3598        assert_eq!(json["name"], "get_weather");
3599        assert_eq!(json["input"]["location"], "San Francisco");
3600    }
3601
3602    #[test]
3603    fn test_sampling_content_tool_result() {
3604        let content = SamplingContent::ToolResult {
3605            tool_use_id: "tool_123".to_string(),
3606            content: vec![SamplingContent::Text {
3607                text: "72F, sunny".to_string(),
3608            }],
3609            is_error: None,
3610        };
3611        let json = serde_json::to_value(&content).unwrap();
3612        assert_eq!(json["type"], "tool_result");
3613        assert_eq!(json["tool_use_id"], "tool_123");
3614        assert_eq!(json["content"][0]["type"], "text");
3615    }
3616
3617    #[test]
3618    fn test_sampling_content_or_array_single() {
3619        let json = serde_json::json!({
3620            "type": "text",
3621            "text": "Hello"
3622        });
3623        let content: SamplingContentOrArray = serde_json::from_value(json).unwrap();
3624        let items = content.items();
3625        assert_eq!(items.len(), 1);
3626        match items[0] {
3627            SamplingContent::Text { text } => assert_eq!(text, "Hello"),
3628            _ => panic!("Expected text content"),
3629        }
3630    }
3631
3632    #[test]
3633    fn test_sampling_content_or_array_multiple() {
3634        let json = serde_json::json!([
3635            { "type": "text", "text": "Hello" },
3636            { "type": "text", "text": "World" }
3637        ]);
3638        let content: SamplingContentOrArray = serde_json::from_value(json).unwrap();
3639        let items = content.items();
3640        assert_eq!(items.len(), 2);
3641    }
3642
3643    #[test]
3644    fn test_create_message_params_with_tools() {
3645        let tool = SamplingTool {
3646            name: "calculator".to_string(),
3647            description: Some("Do math".to_string()),
3648            input_schema: serde_json::json!({"type": "object"}),
3649        };
3650        let params = CreateMessageParams::new(vec![], 100)
3651            .tools(vec![tool])
3652            .tool_choice(ToolChoice::auto());
3653
3654        let json = serde_json::to_value(&params).unwrap();
3655        assert!(json["tools"].is_array());
3656        assert_eq!(json["tools"][0]["name"], "calculator");
3657        assert_eq!(json["toolChoice"]["type"], "auto");
3658    }
3659
3660    #[test]
3661    fn test_create_message_result_content_items() {
3662        let result = CreateMessageResult {
3663            content: SamplingContentOrArray::Array(vec![
3664                SamplingContent::Text {
3665                    text: "First".to_string(),
3666                },
3667                SamplingContent::Text {
3668                    text: "Second".to_string(),
3669                },
3670            ]),
3671            model: "test".to_string(),
3672            role: ContentRole::Assistant,
3673            stop_reason: None,
3674        };
3675        let items = result.content_items();
3676        assert_eq!(items.len(), 2);
3677    }
3678
3679    #[test]
3680    fn test_sampling_content_as_text() {
3681        let text_content = SamplingContent::Text {
3682            text: "Hello".to_string(),
3683        };
3684        assert_eq!(text_content.as_text(), Some("Hello"));
3685
3686        let image_content = SamplingContent::Image {
3687            data: "base64data".to_string(),
3688            mime_type: "image/png".to_string(),
3689        };
3690        assert_eq!(image_content.as_text(), None);
3691
3692        let audio_content = SamplingContent::Audio {
3693            data: "base64audio".to_string(),
3694            mime_type: "audio/wav".to_string(),
3695        };
3696        assert_eq!(audio_content.as_text(), None);
3697    }
3698
3699    #[test]
3700    fn test_create_message_result_first_text_single() {
3701        let result = CreateMessageResult {
3702            content: SamplingContentOrArray::Single(SamplingContent::Text {
3703                text: "Hello, world!".to_string(),
3704            }),
3705            model: "test".to_string(),
3706            role: ContentRole::Assistant,
3707            stop_reason: None,
3708        };
3709        assert_eq!(result.first_text(), Some("Hello, world!"));
3710    }
3711
3712    #[test]
3713    fn test_create_message_result_first_text_array() {
3714        let result = CreateMessageResult {
3715            content: SamplingContentOrArray::Array(vec![
3716                SamplingContent::Text {
3717                    text: "First".to_string(),
3718                },
3719                SamplingContent::Text {
3720                    text: "Second".to_string(),
3721                },
3722            ]),
3723            model: "test".to_string(),
3724            role: ContentRole::Assistant,
3725            stop_reason: None,
3726        };
3727        assert_eq!(result.first_text(), Some("First"));
3728    }
3729
3730    #[test]
3731    fn test_create_message_result_first_text_skips_non_text() {
3732        let result = CreateMessageResult {
3733            content: SamplingContentOrArray::Array(vec![
3734                SamplingContent::Image {
3735                    data: "base64data".to_string(),
3736                    mime_type: "image/png".to_string(),
3737                },
3738                SamplingContent::Text {
3739                    text: "After image".to_string(),
3740                },
3741            ]),
3742            model: "test".to_string(),
3743            role: ContentRole::Assistant,
3744            stop_reason: None,
3745        };
3746        assert_eq!(result.first_text(), Some("After image"));
3747    }
3748
3749    #[test]
3750    fn test_create_message_result_first_text_none() {
3751        let result = CreateMessageResult {
3752            content: SamplingContentOrArray::Single(SamplingContent::Image {
3753                data: "base64data".to_string(),
3754                mime_type: "image/png".to_string(),
3755            }),
3756            model: "test".to_string(),
3757            role: ContentRole::Assistant,
3758            stop_reason: None,
3759        };
3760        assert_eq!(result.first_text(), None);
3761    }
3762}