1use std::collections::HashMap;
7
8use serde::de::DeserializeOwned;
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11
12use crate::error::JsonRpcError;
13
14pub const JSONRPC_VERSION: &str = "2.0";
16
17pub const LATEST_PROTOCOL_VERSION: &str = "2025-11-25";
19
20pub const SUPPORTED_PROTOCOL_VERSIONS: &[&str] = &["2025-11-25", "2025-03-26"];
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct JsonRpcRequest {
26 pub jsonrpc: String,
28 pub id: RequestId,
30 pub method: String,
32 #[serde(default, skip_serializing_if = "Option::is_none")]
34 pub params: Option<Value>,
35}
36
37impl JsonRpcRequest {
38 pub fn new(id: impl Into<RequestId>, method: impl Into<String>) -> Self {
40 Self {
41 jsonrpc: JSONRPC_VERSION.to_string(),
42 id: id.into(),
43 method: method.into(),
44 params: None,
45 }
46 }
47
48 pub fn with_params(mut self, params: Value) -> Self {
50 self.params = Some(params);
51 self
52 }
53
54 pub fn validate(&self) -> Result<(), JsonRpcError> {
57 if self.jsonrpc != JSONRPC_VERSION {
58 return Err(JsonRpcError::invalid_request(format!(
59 "Invalid JSON-RPC version: expected '{}', got '{}'",
60 JSONRPC_VERSION, self.jsonrpc
61 )));
62 }
63 Ok(())
64 }
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize)]
69pub struct JsonRpcResultResponse {
70 pub jsonrpc: String,
72 pub id: RequestId,
74 pub result: Value,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct JsonRpcErrorResponse {
81 pub jsonrpc: String,
83 #[serde(skip_serializing_if = "Option::is_none")]
85 pub id: Option<RequestId>,
86 pub error: JsonRpcError,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
92#[serde(untagged)]
93pub enum JsonRpcResponse {
94 Result(JsonRpcResultResponse),
96 Error(JsonRpcErrorResponse),
98}
99
100impl JsonRpcResponse {
101 pub fn result(id: RequestId, result: Value) -> Self {
103 Self::Result(JsonRpcResultResponse {
104 jsonrpc: JSONRPC_VERSION.to_string(),
105 id,
106 result,
107 })
108 }
109
110 pub fn error(id: Option<RequestId>, error: JsonRpcError) -> Self {
112 Self::Error(JsonRpcErrorResponse {
113 jsonrpc: JSONRPC_VERSION.to_string(),
114 id,
115 error,
116 })
117 }
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
122#[serde(untagged)]
123pub enum JsonRpcMessage {
124 Single(JsonRpcRequest),
126 Batch(Vec<JsonRpcRequest>),
128}
129
130impl JsonRpcMessage {
131 pub fn is_batch(&self) -> bool {
133 matches!(self, JsonRpcMessage::Batch(_))
134 }
135
136 pub fn len(&self) -> usize {
138 match self {
139 JsonRpcMessage::Single(_) => 1,
140 JsonRpcMessage::Batch(batch) => batch.len(),
141 }
142 }
143
144 pub fn is_empty(&self) -> bool {
146 self.len() == 0
147 }
148}
149
150#[derive(Debug, Clone, Serialize, Deserialize)]
152#[serde(untagged)]
153pub enum JsonRpcResponseMessage {
154 Single(JsonRpcResponse),
156 Batch(Vec<JsonRpcResponse>),
158}
159
160impl JsonRpcResponseMessage {
161 pub fn is_batch(&self) -> bool {
163 matches!(self, JsonRpcResponseMessage::Batch(_))
164 }
165}
166
167#[derive(Debug, Clone, Serialize, Deserialize)]
169pub struct JsonRpcNotification {
170 pub jsonrpc: String,
171 pub method: String,
172 #[serde(default, skip_serializing_if = "Option::is_none")]
173 pub params: Option<Value>,
174}
175
176impl JsonRpcNotification {
177 pub fn new(method: impl Into<String>) -> Self {
178 Self {
179 jsonrpc: JSONRPC_VERSION.to_string(),
180 method: method.into(),
181 params: None,
182 }
183 }
184
185 pub fn with_params(mut self, params: Value) -> Self {
186 self.params = Some(params);
187 self
188 }
189}
190
191pub mod notifications {
193 pub const INITIALIZED: &str = "notifications/initialized";
195 pub const CANCELLED: &str = "notifications/cancelled";
197 pub const PROGRESS: &str = "notifications/progress";
199 pub const TOOLS_LIST_CHANGED: &str = "notifications/tools/list_changed";
201 pub const RESOURCES_LIST_CHANGED: &str = "notifications/resources/list_changed";
203 pub const RESOURCE_UPDATED: &str = "notifications/resources/updated";
205 pub const PROMPTS_LIST_CHANGED: &str = "notifications/prompts/list_changed";
207 pub const ROOTS_LIST_CHANGED: &str = "notifications/roots/list_changed";
209 pub const MESSAGE: &str = "notifications/message";
211 pub const TASK_STATUS_CHANGED: &str = "notifications/tasks/status";
213 pub const ELICITATION_COMPLETE: &str = "notifications/elicitation/complete";
215}
216
217#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
221#[serde(rename_all = "lowercase")]
222pub enum LogLevel {
223 Emergency,
225 Alert,
227 Critical,
229 Error,
231 Warning,
233 Notice,
235 #[default]
237 Info,
238 Debug,
240}
241
242impl std::fmt::Display for LogLevel {
243 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244 match self {
245 LogLevel::Emergency => write!(f, "emergency"),
246 LogLevel::Alert => write!(f, "alert"),
247 LogLevel::Critical => write!(f, "critical"),
248 LogLevel::Error => write!(f, "error"),
249 LogLevel::Warning => write!(f, "warning"),
250 LogLevel::Notice => write!(f, "notice"),
251 LogLevel::Info => write!(f, "info"),
252 LogLevel::Debug => write!(f, "debug"),
253 }
254 }
255}
256
257#[derive(Debug, Clone, Serialize, Deserialize)]
259pub struct LoggingMessageParams {
260 pub level: LogLevel,
262 #[serde(skip_serializing_if = "Option::is_none")]
264 pub logger: Option<String>,
265 #[serde(default)]
267 pub data: Value,
268 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
270 pub meta: Option<Value>,
271}
272
273impl LoggingMessageParams {
274 pub fn new(level: LogLevel, data: impl Into<Value>) -> Self {
276 Self {
277 level,
278 logger: None,
279 data: data.into(),
280 meta: None,
281 }
282 }
283
284 pub fn with_logger(mut self, logger: impl Into<String>) -> Self {
286 self.logger = Some(logger.into());
287 self
288 }
289
290 pub fn with_data(mut self, data: impl Into<Value>) -> Self {
292 self.data = data.into();
293 self
294 }
295}
296
297#[derive(Debug, Clone, Deserialize)]
299pub struct SetLogLevelParams {
300 pub level: LogLevel,
302 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
304 pub meta: Option<RequestMeta>,
305}
306
307#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
309#[serde(untagged)]
310pub enum RequestId {
311 String(String),
312 Number(i64),
313}
314
315impl From<String> for RequestId {
316 fn from(s: String) -> Self {
317 RequestId::String(s)
318 }
319}
320
321impl From<&str> for RequestId {
322 fn from(s: &str) -> Self {
323 RequestId::String(s.to_string())
324 }
325}
326
327impl From<i64> for RequestId {
328 fn from(n: i64) -> Self {
329 RequestId::Number(n)
330 }
331}
332
333impl From<i32> for RequestId {
334 fn from(n: i32) -> Self {
335 RequestId::Number(n as i64)
336 }
337}
338
339#[derive(Debug, Clone)]
345pub enum McpRequest {
346 Initialize(InitializeParams),
348 ListTools(ListToolsParams),
350 CallTool(CallToolParams),
352 ListResources(ListResourcesParams),
354 ListResourceTemplates(ListResourceTemplatesParams),
356 ReadResource(ReadResourceParams),
358 SubscribeResource(SubscribeResourceParams),
360 UnsubscribeResource(UnsubscribeResourceParams),
362 ListPrompts(ListPromptsParams),
364 GetPrompt(GetPromptParams),
366 ListTasks(ListTasksParams),
368 GetTaskInfo(GetTaskInfoParams),
370 GetTaskResult(GetTaskResultParams),
372 CancelTask(CancelTaskParams),
374 Ping,
376 SetLoggingLevel(SetLogLevelParams),
378 Complete(CompleteParams),
380 Unknown {
382 method: String,
383 params: Option<Value>,
384 },
385}
386
387impl McpRequest {
388 pub fn method_name(&self) -> &str {
390 match self {
391 McpRequest::Initialize(_) => "initialize",
392 McpRequest::ListTools(_) => "tools/list",
393 McpRequest::CallTool(_) => "tools/call",
394 McpRequest::ListResources(_) => "resources/list",
395 McpRequest::ListResourceTemplates(_) => "resources/templates/list",
396 McpRequest::ReadResource(_) => "resources/read",
397 McpRequest::SubscribeResource(_) => "resources/subscribe",
398 McpRequest::UnsubscribeResource(_) => "resources/unsubscribe",
399 McpRequest::ListPrompts(_) => "prompts/list",
400 McpRequest::GetPrompt(_) => "prompts/get",
401 McpRequest::ListTasks(_) => "tasks/list",
402 McpRequest::GetTaskInfo(_) => "tasks/get",
403 McpRequest::GetTaskResult(_) => "tasks/result",
404 McpRequest::CancelTask(_) => "tasks/cancel",
405 McpRequest::Ping => "ping",
406 McpRequest::SetLoggingLevel(_) => "logging/setLevel",
407 McpRequest::Complete(_) => "completion/complete",
408 McpRequest::Unknown { method, .. } => method,
409 }
410 }
411}
412
413#[derive(Debug, Clone)]
415pub enum McpNotification {
416 Initialized,
418 Cancelled(CancelledParams),
420 Progress(ProgressParams),
422 RootsListChanged,
424 Unknown {
426 method: String,
427 params: Option<Value>,
428 },
429}
430
431#[derive(Debug, Clone, Serialize, Deserialize)]
433#[serde(rename_all = "camelCase")]
434pub struct CancelledParams {
435 #[serde(default, skip_serializing_if = "Option::is_none")]
437 pub request_id: Option<RequestId>,
438 #[serde(skip_serializing_if = "Option::is_none")]
440 pub reason: Option<String>,
441 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
443 pub meta: Option<Value>,
444}
445
446#[derive(Debug, Clone, Serialize, Deserialize)]
448#[serde(rename_all = "camelCase")]
449pub struct ProgressParams {
450 pub progress_token: ProgressToken,
452 pub progress: f64,
454 #[serde(skip_serializing_if = "Option::is_none")]
456 pub total: Option<f64>,
457 #[serde(skip_serializing_if = "Option::is_none")]
459 pub message: Option<String>,
460 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
462 pub meta: Option<Value>,
463}
464
465#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
467#[serde(untagged)]
468pub enum ProgressToken {
469 String(String),
470 Number(i64),
471}
472
473#[derive(Debug, Clone, Default, Serialize, Deserialize)]
475#[serde(rename_all = "camelCase")]
476pub struct RequestMeta {
477 #[serde(skip_serializing_if = "Option::is_none")]
479 pub progress_token: Option<ProgressToken>,
480}
481
482#[derive(Debug, Clone, Serialize)]
484#[serde(untagged)]
485pub enum McpResponse {
486 Initialize(InitializeResult),
487 ListTools(ListToolsResult),
488 CallTool(CallToolResult),
489 ListResources(ListResourcesResult),
490 ListResourceTemplates(ListResourceTemplatesResult),
491 ReadResource(ReadResourceResult),
492 SubscribeResource(EmptyResult),
493 UnsubscribeResource(EmptyResult),
494 ListPrompts(ListPromptsResult),
495 GetPrompt(GetPromptResult),
496 CreateTask(CreateTaskResult),
497 ListTasks(ListTasksResult),
498 GetTaskInfo(TaskObject),
499 GetTaskResult(CallToolResult),
500 CancelTask(TaskObject),
501 SetLoggingLevel(EmptyResult),
502 Complete(CompleteResult),
503 Pong(EmptyResult),
504 Empty(EmptyResult),
505}
506
507#[derive(Debug, Clone, Serialize, Deserialize)]
512#[serde(rename_all = "camelCase")]
513pub struct InitializeParams {
514 pub protocol_version: String,
515 pub capabilities: ClientCapabilities,
516 pub client_info: Implementation,
517 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
519 pub meta: Option<Value>,
520}
521
522#[derive(Debug, Clone, Default, Serialize, Deserialize)]
523pub struct ClientCapabilities {
524 #[serde(default, skip_serializing_if = "Option::is_none")]
525 pub roots: Option<RootsCapability>,
526 #[serde(default, skip_serializing_if = "Option::is_none")]
527 pub sampling: Option<SamplingCapability>,
528 #[serde(default, skip_serializing_if = "Option::is_none")]
529 pub elicitation: Option<ElicitationCapability>,
530 #[serde(default, skip_serializing_if = "Option::is_none")]
531 pub tasks: Option<ClientTasksCapability>,
532 #[serde(default, skip_serializing_if = "Option::is_none")]
534 pub experimental: Option<HashMap<String, serde_json::Value>>,
535 #[serde(default, skip_serializing_if = "Option::is_none")]
537 pub extensions: Option<HashMap<String, serde_json::Value>>,
538}
539
540#[derive(Debug, Clone, Default, Serialize, Deserialize)]
542pub struct ElicitationCapability {
543 #[serde(default, skip_serializing_if = "Option::is_none")]
545 pub form: Option<ElicitationFormCapability>,
546 #[serde(default, skip_serializing_if = "Option::is_none")]
548 pub url: Option<ElicitationUrlCapability>,
549}
550
551#[derive(Debug, Clone, Default, Serialize, Deserialize)]
553pub struct ElicitationFormCapability {}
554
555#[derive(Debug, Clone, Default, Serialize, Deserialize)]
557pub struct ElicitationUrlCapability {}
558
559#[derive(Debug, Clone, Default, Serialize, Deserialize)]
561#[serde(rename_all = "camelCase")]
562pub struct ClientTasksCapability {
563 #[serde(default, skip_serializing_if = "Option::is_none")]
565 pub list: Option<ClientTasksListCapability>,
566 #[serde(default, skip_serializing_if = "Option::is_none")]
568 pub cancel: Option<ClientTasksCancelCapability>,
569 #[serde(default, skip_serializing_if = "Option::is_none")]
571 pub requests: Option<ClientTasksRequestsCapability>,
572}
573
574#[derive(Debug, Clone, Default, Serialize, Deserialize)]
576pub struct ClientTasksListCapability {}
577
578#[derive(Debug, Clone, Default, Serialize, Deserialize)]
580pub struct ClientTasksCancelCapability {}
581
582#[derive(Debug, Clone, Default, Serialize, Deserialize)]
584#[serde(rename_all = "camelCase")]
585pub struct ClientTasksRequestsCapability {
586 #[serde(default, skip_serializing_if = "Option::is_none")]
588 pub sampling: Option<ClientTasksSamplingCapability>,
589 #[serde(default, skip_serializing_if = "Option::is_none")]
591 pub elicitation: Option<ClientTasksElicitationCapability>,
592}
593
594#[derive(Debug, Clone, Default, Serialize, Deserialize)]
596#[serde(rename_all = "camelCase")]
597pub struct ClientTasksSamplingCapability {
598 #[serde(default, skip_serializing_if = "Option::is_none")]
600 pub create_message: Option<ClientTasksSamplingCreateMessageCapability>,
601}
602
603#[derive(Debug, Clone, Default, Serialize, Deserialize)]
605pub struct ClientTasksSamplingCreateMessageCapability {}
606
607#[derive(Debug, Clone, Default, Serialize, Deserialize)]
609#[serde(rename_all = "camelCase")]
610pub struct ClientTasksElicitationCapability {
611 #[serde(default, skip_serializing_if = "Option::is_none")]
613 pub create: Option<ClientTasksElicitationCreateCapability>,
614}
615
616#[derive(Debug, Clone, Default, Serialize, Deserialize)]
618pub struct ClientTasksElicitationCreateCapability {}
619
620#[derive(Debug, Clone, Default, Serialize, Deserialize)]
622#[serde(rename_all = "camelCase")]
623pub struct RootsCapability {
624 #[serde(default)]
626 pub list_changed: bool,
627}
628
629#[derive(Debug, Clone, Serialize, Deserialize)]
636pub struct Root {
637 pub uri: String,
639 #[serde(default, skip_serializing_if = "Option::is_none")]
641 pub name: Option<String>,
642 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
644 pub meta: Option<Value>,
645}
646
647impl Root {
648 pub fn new(uri: impl Into<String>) -> Self {
650 Self {
651 uri: uri.into(),
652 name: None,
653 meta: None,
654 }
655 }
656
657 pub fn with_name(uri: impl Into<String>, name: impl Into<String>) -> Self {
659 Self {
660 uri: uri.into(),
661 name: Some(name.into()),
662 meta: None,
663 }
664 }
665}
666
667#[derive(Debug, Clone, Default, Serialize, Deserialize)]
669pub struct ListRootsParams {
670 #[serde(default, rename = "_meta", skip_serializing_if = "Option::is_none")]
672 pub meta: Option<RequestMeta>,
673}
674
675#[derive(Debug, Clone, Serialize, Deserialize)]
677pub struct ListRootsResult {
678 pub roots: Vec<Root>,
680 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
682 pub meta: Option<Value>,
683}
684
685#[derive(Debug, Clone, Default, Serialize, Deserialize)]
686pub struct SamplingCapability {
687 #[serde(default, skip_serializing_if = "Option::is_none")]
689 pub tools: Option<SamplingToolsCapability>,
690 #[serde(default, skip_serializing_if = "Option::is_none")]
692 pub context: Option<SamplingContextCapability>,
693}
694
695#[derive(Debug, Clone, Default, Serialize, Deserialize)]
697pub struct SamplingToolsCapability {}
698
699#[derive(Debug, Clone, Default, Serialize, Deserialize)]
701pub struct SamplingContextCapability {}
702
703#[derive(Debug, Clone, Default, Serialize, Deserialize)]
705pub struct CompletionsCapability {}
706
707#[derive(Debug, Clone, Serialize, Deserialize)]
713pub struct PromptReference {
714 #[serde(rename = "type")]
716 pub ref_type: String,
717 pub name: String,
719}
720
721impl PromptReference {
722 pub fn new(name: impl Into<String>) -> Self {
724 Self {
725 ref_type: "ref/prompt".to_string(),
726 name: name.into(),
727 }
728 }
729}
730
731#[derive(Debug, Clone, Serialize, Deserialize)]
733pub struct ResourceReference {
734 #[serde(rename = "type")]
736 pub ref_type: String,
737 pub uri: String,
739}
740
741impl ResourceReference {
742 pub fn new(uri: impl Into<String>) -> Self {
744 Self {
745 ref_type: "ref/resource".to_string(),
746 uri: uri.into(),
747 }
748 }
749}
750
751#[derive(Debug, Clone, Serialize, Deserialize)]
753#[serde(tag = "type")]
754pub enum CompletionReference {
755 #[serde(rename = "ref/prompt")]
757 Prompt {
758 name: String,
760 },
761 #[serde(rename = "ref/resource")]
763 Resource {
764 uri: String,
766 },
767}
768
769impl CompletionReference {
770 pub fn prompt(name: impl Into<String>) -> Self {
772 Self::Prompt { name: name.into() }
773 }
774
775 pub fn resource(uri: impl Into<String>) -> Self {
777 Self::Resource { uri: uri.into() }
778 }
779}
780
781#[derive(Debug, Clone, Serialize, Deserialize)]
783pub struct CompletionArgument {
784 pub name: String,
786 pub value: String,
788}
789
790impl CompletionArgument {
791 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
793 Self {
794 name: name.into(),
795 value: value.into(),
796 }
797 }
798}
799
800#[derive(Debug, Clone, Serialize, Deserialize)]
802#[serde(rename_all = "camelCase")]
803pub struct CompleteParams {
804 #[serde(rename = "ref")]
806 pub reference: CompletionReference,
807 pub argument: CompletionArgument,
809 #[serde(default, skip_serializing_if = "Option::is_none")]
811 pub context: Option<CompletionContext>,
812 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
814 pub meta: Option<Value>,
815}
816
817#[derive(Debug, Clone, Serialize, Deserialize)]
819#[serde(rename_all = "camelCase")]
820pub struct CompletionContext {
821 #[serde(default, skip_serializing_if = "Option::is_none")]
823 pub arguments: Option<std::collections::HashMap<String, String>>,
824}
825
826#[derive(Debug, Clone, Serialize, Deserialize)]
828#[serde(rename_all = "camelCase")]
829pub struct Completion {
830 pub values: Vec<String>,
832 #[serde(default, skip_serializing_if = "Option::is_none")]
834 pub total: Option<u32>,
835 #[serde(default, skip_serializing_if = "Option::is_none")]
837 pub has_more: Option<bool>,
838}
839
840impl Completion {
841 pub fn new(values: Vec<String>) -> Self {
843 Self {
844 values,
845 total: None,
846 has_more: None,
847 }
848 }
849
850 pub fn with_pagination(values: Vec<String>, total: u32, has_more: bool) -> Self {
852 Self {
853 values,
854 total: Some(total),
855 has_more: Some(has_more),
856 }
857 }
858}
859
860#[derive(Debug, Clone, Serialize, Deserialize)]
862pub struct CompleteResult {
863 pub completion: Completion,
865 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
867 pub meta: Option<Value>,
868}
869
870impl CompleteResult {
871 pub fn new(values: Vec<String>) -> Self {
873 Self {
874 completion: Completion::new(values),
875 meta: None,
876 }
877 }
878
879 pub fn with_pagination(values: Vec<String>, total: u32, has_more: bool) -> Self {
881 Self {
882 completion: Completion::with_pagination(values, total, has_more),
883 meta: None,
884 }
885 }
886}
887
888#[derive(Debug, Clone, Serialize, Deserialize)]
894pub struct ModelHint {
895 #[serde(default, skip_serializing_if = "Option::is_none")]
897 pub name: Option<String>,
898}
899
900impl ModelHint {
901 pub fn new(name: impl Into<String>) -> Self {
903 Self {
904 name: Some(name.into()),
905 }
906 }
907}
908
909#[derive(Debug, Clone, Default, Serialize, Deserialize)]
911#[serde(rename_all = "camelCase")]
912pub struct ModelPreferences {
913 #[serde(default, skip_serializing_if = "Option::is_none")]
915 pub speed_priority: Option<f64>,
916 #[serde(default, skip_serializing_if = "Option::is_none")]
918 pub intelligence_priority: Option<f64>,
919 #[serde(default, skip_serializing_if = "Option::is_none")]
921 pub cost_priority: Option<f64>,
922 #[serde(default, skip_serializing_if = "Vec::is_empty")]
924 pub hints: Vec<ModelHint>,
925}
926
927impl ModelPreferences {
928 pub fn new() -> Self {
930 Self::default()
931 }
932
933 pub fn speed(mut self, priority: f64) -> Self {
935 self.speed_priority = Some(priority.clamp(0.0, 1.0));
936 self
937 }
938
939 pub fn intelligence(mut self, priority: f64) -> Self {
941 self.intelligence_priority = Some(priority.clamp(0.0, 1.0));
942 self
943 }
944
945 pub fn cost(mut self, priority: f64) -> Self {
947 self.cost_priority = Some(priority.clamp(0.0, 1.0));
948 self
949 }
950
951 pub fn hint(mut self, name: impl Into<String>) -> Self {
953 self.hints.push(ModelHint::new(name));
954 self
955 }
956}
957
958#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
960#[serde(rename_all = "camelCase")]
961pub enum IncludeContext {
962 AllServers,
964 ThisServer,
966 #[default]
968 None,
969}
970
971#[derive(Debug, Clone, Serialize, Deserialize)]
973pub struct SamplingMessage {
974 pub role: ContentRole,
976 pub content: SamplingContentOrArray,
978 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
980 pub meta: Option<Value>,
981}
982
983impl SamplingMessage {
984 pub fn user(text: impl Into<String>) -> Self {
986 Self {
987 role: ContentRole::User,
988 content: SamplingContentOrArray::Single(SamplingContent::Text {
989 text: text.into(),
990 annotations: None,
991 meta: None,
992 }),
993 meta: None,
994 }
995 }
996
997 pub fn assistant(text: impl Into<String>) -> Self {
999 Self {
1000 role: ContentRole::Assistant,
1001 content: SamplingContentOrArray::Single(SamplingContent::Text {
1002 text: text.into(),
1003 annotations: None,
1004 meta: None,
1005 }),
1006 meta: None,
1007 }
1008 }
1009}
1010
1011#[derive(Debug, Clone, Serialize, Deserialize)]
1016#[serde(rename_all = "camelCase")]
1017pub struct SamplingTool {
1018 pub name: String,
1020 #[serde(default, skip_serializing_if = "Option::is_none")]
1022 pub title: Option<String>,
1023 #[serde(skip_serializing_if = "Option::is_none")]
1025 pub description: Option<String>,
1026 pub input_schema: Value,
1028 #[serde(default, skip_serializing_if = "Option::is_none")]
1030 pub output_schema: Option<Value>,
1031 #[serde(default, skip_serializing_if = "Option::is_none")]
1033 pub icons: Option<Vec<ToolIcon>>,
1034 #[serde(default, skip_serializing_if = "Option::is_none")]
1036 pub annotations: Option<ToolAnnotations>,
1037 #[serde(default, skip_serializing_if = "Option::is_none")]
1039 pub execution: Option<ToolExecution>,
1040}
1041
1042#[derive(Debug, Clone, Serialize, Deserialize)]
1046pub struct ToolChoice {
1047 pub mode: String,
1049 #[serde(skip_serializing_if = "Option::is_none")]
1051 pub name: Option<String>,
1052}
1053
1054impl ToolChoice {
1055 pub fn auto() -> Self {
1057 Self {
1058 mode: "auto".to_string(),
1059 name: None,
1060 }
1061 }
1062
1063 pub fn required() -> Self {
1065 Self {
1066 mode: "required".to_string(),
1067 name: None,
1068 }
1069 }
1070
1071 pub fn none() -> Self {
1073 Self {
1074 mode: "none".to_string(),
1075 name: None,
1076 }
1077 }
1078
1079 pub fn tool(name: impl Into<String>) -> Self {
1081 Self {
1082 mode: "tool".to_string(),
1083 name: Some(name.into()),
1084 }
1085 }
1086}
1087
1088#[derive(Debug, Clone, Serialize, Deserialize)]
1090#[serde(tag = "type", rename_all = "lowercase")]
1091pub enum SamplingContent {
1092 Text {
1094 text: String,
1096 #[serde(default, skip_serializing_if = "Option::is_none")]
1098 annotations: Option<ContentAnnotations>,
1099 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1101 meta: Option<Value>,
1102 },
1103 Image {
1105 data: String,
1107 #[serde(rename = "mimeType")]
1109 mime_type: String,
1110 #[serde(default, skip_serializing_if = "Option::is_none")]
1112 annotations: Option<ContentAnnotations>,
1113 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1115 meta: Option<Value>,
1116 },
1117 Audio {
1119 data: String,
1121 #[serde(rename = "mimeType")]
1123 mime_type: String,
1124 #[serde(default, skip_serializing_if = "Option::is_none")]
1126 annotations: Option<ContentAnnotations>,
1127 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1129 meta: Option<Value>,
1130 },
1131 #[serde(rename = "tool_use")]
1133 ToolUse {
1134 id: String,
1136 name: String,
1138 input: Value,
1140 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1142 meta: Option<Value>,
1143 },
1144 #[serde(rename = "tool_result")]
1146 ToolResult {
1147 #[serde(rename = "toolUseId")]
1149 tool_use_id: String,
1150 content: Vec<SamplingContent>,
1152 #[serde(
1154 default,
1155 rename = "structuredContent",
1156 skip_serializing_if = "Option::is_none"
1157 )]
1158 structured_content: Option<Value>,
1159 #[serde(default, rename = "isError", skip_serializing_if = "Option::is_none")]
1161 is_error: Option<bool>,
1162 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1164 meta: Option<Value>,
1165 },
1166}
1167
1168impl SamplingContent {
1169 pub fn as_text(&self) -> Option<&str> {
1190 match self {
1191 SamplingContent::Text { text, .. } => Some(text),
1192 _ => None,
1193 }
1194 }
1195}
1196
1197#[derive(Debug, Clone, Serialize, Deserialize)]
1202#[serde(untagged)]
1203pub enum SamplingContentOrArray {
1204 Single(SamplingContent),
1206 Array(Vec<SamplingContent>),
1208}
1209
1210impl SamplingContentOrArray {
1211 pub fn items(&self) -> Vec<&SamplingContent> {
1213 match self {
1214 Self::Single(c) => vec![c],
1215 Self::Array(arr) => arr.iter().collect(),
1216 }
1217 }
1218
1219 pub fn into_items(self) -> Vec<SamplingContent> {
1221 match self {
1222 Self::Single(c) => vec![c],
1223 Self::Array(arr) => arr,
1224 }
1225 }
1226}
1227
1228#[derive(Debug, Clone, Serialize, Deserialize)]
1230#[serde(rename_all = "camelCase")]
1231pub struct CreateMessageParams {
1232 pub messages: Vec<SamplingMessage>,
1234 pub max_tokens: u32,
1236 #[serde(default, skip_serializing_if = "Option::is_none")]
1238 pub system_prompt: Option<String>,
1239 #[serde(default, skip_serializing_if = "Option::is_none")]
1241 pub temperature: Option<f64>,
1242 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1244 pub stop_sequences: Vec<String>,
1245 #[serde(default, skip_serializing_if = "Option::is_none")]
1247 pub model_preferences: Option<ModelPreferences>,
1248 #[serde(default, skip_serializing_if = "Option::is_none")]
1250 pub include_context: Option<IncludeContext>,
1251 #[serde(default, skip_serializing_if = "Option::is_none")]
1253 pub metadata: Option<serde_json::Map<String, Value>>,
1254 #[serde(default, skip_serializing_if = "Option::is_none")]
1256 pub tools: Option<Vec<SamplingTool>>,
1257 #[serde(default, skip_serializing_if = "Option::is_none")]
1259 pub tool_choice: Option<ToolChoice>,
1260 #[serde(default, skip_serializing_if = "Option::is_none")]
1262 pub task: Option<TaskRequestParams>,
1263 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1265 pub meta: Option<Value>,
1266}
1267
1268impl CreateMessageParams {
1269 pub fn new(messages: Vec<SamplingMessage>, max_tokens: u32) -> Self {
1271 Self {
1272 messages,
1273 max_tokens,
1274 system_prompt: None,
1275 temperature: None,
1276 stop_sequences: Vec::new(),
1277 model_preferences: None,
1278 include_context: None,
1279 metadata: None,
1280 tools: None,
1281 tool_choice: None,
1282 task: None,
1283 meta: None,
1284 }
1285 }
1286
1287 pub fn system_prompt(mut self, prompt: impl Into<String>) -> Self {
1289 self.system_prompt = Some(prompt.into());
1290 self
1291 }
1292
1293 pub fn temperature(mut self, temp: f64) -> Self {
1295 self.temperature = Some(temp.clamp(0.0, 1.0));
1296 self
1297 }
1298
1299 pub fn stop_sequence(mut self, seq: impl Into<String>) -> Self {
1301 self.stop_sequences.push(seq.into());
1302 self
1303 }
1304
1305 pub fn model_preferences(mut self, prefs: ModelPreferences) -> Self {
1307 self.model_preferences = Some(prefs);
1308 self
1309 }
1310
1311 pub fn include_context(mut self, mode: IncludeContext) -> Self {
1313 self.include_context = Some(mode);
1314 self
1315 }
1316
1317 pub fn tools(mut self, tools: Vec<SamplingTool>) -> Self {
1319 self.tools = Some(tools);
1320 self
1321 }
1322
1323 pub fn tool_choice(mut self, choice: ToolChoice) -> Self {
1325 self.tool_choice = Some(choice);
1326 self
1327 }
1328}
1329
1330#[derive(Debug, Clone, Serialize, Deserialize)]
1332#[serde(rename_all = "camelCase")]
1333pub struct CreateMessageResult {
1334 pub content: SamplingContentOrArray,
1336 pub model: String,
1338 pub role: ContentRole,
1340 #[serde(default, skip_serializing_if = "Option::is_none")]
1342 pub stop_reason: Option<String>,
1343 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1345 pub meta: Option<Value>,
1346}
1347
1348impl CreateMessageResult {
1349 pub fn content_items(&self) -> Vec<&SamplingContent> {
1351 self.content.items()
1352 }
1353
1354 pub fn first_text(&self) -> Option<&str> {
1378 self.content.items().iter().find_map(|c| c.as_text())
1379 }
1380}
1381
1382#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1384#[serde(rename_all = "camelCase")]
1385pub struct Implementation {
1386 pub name: String,
1388 pub version: String,
1390 #[serde(skip_serializing_if = "Option::is_none")]
1392 pub title: Option<String>,
1393 #[serde(skip_serializing_if = "Option::is_none")]
1395 pub description: Option<String>,
1396 #[serde(skip_serializing_if = "Option::is_none")]
1398 pub icons: Option<Vec<ToolIcon>>,
1399 #[serde(skip_serializing_if = "Option::is_none")]
1401 pub website_url: Option<String>,
1402 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1404 pub meta: Option<Value>,
1405}
1406
1407#[derive(Debug, Clone, Serialize, Deserialize)]
1408#[serde(rename_all = "camelCase")]
1409pub struct InitializeResult {
1410 pub protocol_version: String,
1411 pub capabilities: ServerCapabilities,
1412 pub server_info: Implementation,
1413 #[serde(skip_serializing_if = "Option::is_none")]
1416 pub instructions: Option<String>,
1417 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1419 pub meta: Option<Value>,
1420}
1421
1422#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1423#[serde(rename_all = "camelCase")]
1424pub struct ServerCapabilities {
1425 #[serde(default, skip_serializing_if = "Option::is_none")]
1426 pub tools: Option<ToolsCapability>,
1427 #[serde(default, skip_serializing_if = "Option::is_none")]
1428 pub resources: Option<ResourcesCapability>,
1429 #[serde(default, skip_serializing_if = "Option::is_none")]
1430 pub prompts: Option<PromptsCapability>,
1431 #[serde(default, skip_serializing_if = "Option::is_none")]
1433 pub logging: Option<LoggingCapability>,
1434 #[serde(default, skip_serializing_if = "Option::is_none")]
1435 pub tasks: Option<TasksCapability>,
1436 #[serde(default, skip_serializing_if = "Option::is_none")]
1438 pub completions: Option<CompletionsCapability>,
1439 #[serde(default, skip_serializing_if = "Option::is_none")]
1441 pub experimental: Option<HashMap<String, serde_json::Value>>,
1442 #[serde(default, skip_serializing_if = "Option::is_none")]
1444 pub extensions: Option<HashMap<String, serde_json::Value>>,
1445}
1446
1447#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1449pub struct LoggingCapability {}
1450
1451#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1453#[serde(rename_all = "camelCase")]
1454pub struct TasksCapability {
1455 #[serde(default, skip_serializing_if = "Option::is_none")]
1457 pub list: Option<TasksListCapability>,
1458 #[serde(default, skip_serializing_if = "Option::is_none")]
1460 pub cancel: Option<TasksCancelCapability>,
1461 #[serde(default, skip_serializing_if = "Option::is_none")]
1463 pub requests: Option<TasksRequestsCapability>,
1464}
1465
1466#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1468pub struct TasksListCapability {}
1469
1470#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1472pub struct TasksCancelCapability {}
1473
1474#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1476#[serde(rename_all = "camelCase")]
1477pub struct TasksRequestsCapability {
1478 #[serde(default, skip_serializing_if = "Option::is_none")]
1480 pub tools: Option<TasksToolsRequestsCapability>,
1481}
1482
1483#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1485#[serde(rename_all = "camelCase")]
1486pub struct TasksToolsRequestsCapability {
1487 #[serde(default, skip_serializing_if = "Option::is_none")]
1489 pub call: Option<TasksToolsCallCapability>,
1490}
1491
1492#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1494pub struct TasksToolsCallCapability {}
1495
1496#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1497#[serde(rename_all = "camelCase")]
1498pub struct ToolsCapability {
1499 #[serde(default)]
1500 pub list_changed: bool,
1501}
1502
1503#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1504#[serde(rename_all = "camelCase")]
1505pub struct ResourcesCapability {
1506 #[serde(default)]
1507 pub subscribe: bool,
1508 #[serde(default)]
1509 pub list_changed: bool,
1510}
1511
1512#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1513#[serde(rename_all = "camelCase")]
1514pub struct PromptsCapability {
1515 #[serde(default)]
1516 pub list_changed: bool,
1517}
1518
1519#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1524pub struct ListToolsParams {
1525 #[serde(default, skip_serializing_if = "Option::is_none")]
1526 pub cursor: Option<String>,
1527 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1529 pub meta: Option<RequestMeta>,
1530}
1531
1532#[derive(Debug, Clone, Serialize, Deserialize)]
1533#[serde(rename_all = "camelCase")]
1534pub struct ListToolsResult {
1535 pub tools: Vec<ToolDefinition>,
1536 #[serde(default, skip_serializing_if = "Option::is_none")]
1537 pub next_cursor: Option<String>,
1538 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1540 pub meta: Option<Value>,
1541}
1542
1543#[derive(Debug, Clone, Serialize, Deserialize)]
1545#[serde(rename_all = "camelCase")]
1546pub struct ToolDefinition {
1547 pub name: String,
1548 #[serde(skip_serializing_if = "Option::is_none")]
1550 pub title: Option<String>,
1551 #[serde(skip_serializing_if = "Option::is_none")]
1552 pub description: Option<String>,
1553 pub input_schema: Value,
1554 #[serde(skip_serializing_if = "Option::is_none")]
1556 pub output_schema: Option<Value>,
1557 #[serde(skip_serializing_if = "Option::is_none")]
1559 pub icons: Option<Vec<ToolIcon>>,
1560 #[serde(skip_serializing_if = "Option::is_none")]
1563 pub annotations: Option<ToolAnnotations>,
1564 #[serde(skip_serializing_if = "Option::is_none")]
1566 pub execution: Option<ToolExecution>,
1567 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1569 pub meta: Option<Value>,
1570}
1571
1572#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1574#[serde(rename_all = "lowercase")]
1575pub enum IconTheme {
1576 Light,
1578 Dark,
1580}
1581
1582#[derive(Debug, Clone, Serialize, Deserialize)]
1584#[serde(rename_all = "camelCase")]
1585pub struct ToolIcon {
1586 pub src: String,
1588 #[serde(skip_serializing_if = "Option::is_none")]
1590 pub mime_type: Option<String>,
1591 #[serde(skip_serializing_if = "Option::is_none")]
1593 pub sizes: Option<Vec<String>>,
1594 #[serde(skip_serializing_if = "Option::is_none")]
1596 pub theme: Option<IconTheme>,
1597}
1598
1599#[derive(Debug, Clone, Serialize, Deserialize)]
1602#[serde(rename_all = "camelCase")]
1603pub struct ToolAnnotations {
1604 #[serde(skip_serializing_if = "Option::is_none")]
1606 pub title: Option<String>,
1607 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1609 pub read_only_hint: bool,
1610 #[serde(default = "default_true", skip_serializing_if = "is_true")]
1613 pub destructive_hint: bool,
1614 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1617 pub idempotent_hint: bool,
1618 #[serde(default = "default_true", skip_serializing_if = "is_true")]
1620 pub open_world_hint: bool,
1621}
1622
1623impl Default for ToolAnnotations {
1624 fn default() -> Self {
1625 Self {
1626 title: None,
1627 read_only_hint: false,
1628 destructive_hint: true,
1629 idempotent_hint: false,
1630 open_world_hint: true,
1631 }
1632 }
1633}
1634
1635impl ToolAnnotations {
1636 pub fn is_read_only(&self) -> bool {
1638 self.read_only_hint
1639 }
1640
1641 pub fn is_destructive(&self) -> bool {
1643 self.destructive_hint
1644 }
1645
1646 pub fn is_idempotent(&self) -> bool {
1648 self.idempotent_hint
1649 }
1650
1651 pub fn is_open_world(&self) -> bool {
1653 self.open_world_hint
1654 }
1655}
1656
1657impl ToolDefinition {
1658 pub fn is_read_only(&self) -> bool {
1662 self.annotations.as_ref().is_some_and(|a| a.read_only_hint)
1663 }
1664
1665 pub fn is_destructive(&self) -> bool {
1669 self.annotations.as_ref().is_none_or(|a| a.destructive_hint)
1670 }
1671
1672 pub fn is_idempotent(&self) -> bool {
1676 self.annotations.as_ref().is_some_and(|a| a.idempotent_hint)
1677 }
1678
1679 pub fn is_open_world(&self) -> bool {
1683 self.annotations.as_ref().is_none_or(|a| a.open_world_hint)
1684 }
1685}
1686
1687fn default_true() -> bool {
1688 true
1689}
1690
1691fn is_true(v: &bool) -> bool {
1692 *v
1693}
1694
1695#[derive(Debug, Clone, Serialize, Deserialize)]
1696pub struct CallToolParams {
1697 pub name: String,
1698 #[serde(default)]
1699 pub arguments: Value,
1700 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1702 pub meta: Option<RequestMeta>,
1703 #[serde(default, skip_serializing_if = "Option::is_none")]
1705 pub task: Option<TaskRequestParams>,
1706}
1707
1708#[derive(Debug, Clone, Serialize, Deserialize)]
1729#[serde(rename_all = "camelCase")]
1730pub struct CallToolResult {
1731 pub content: Vec<Content>,
1733 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1735 pub is_error: bool,
1736 #[serde(default, skip_serializing_if = "Option::is_none")]
1738 pub structured_content: Option<Value>,
1739 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1741 pub meta: Option<Value>,
1742}
1743
1744impl CallToolResult {
1745 pub fn text(text: impl Into<String>) -> Self {
1749 Self {
1750 content: vec![Content::Text {
1751 text: text.into(),
1752 annotations: None,
1753 meta: None,
1754 }],
1755 is_error: false,
1756 structured_content: None,
1757 meta: None,
1758 }
1759 }
1760
1761 pub fn error(message: impl Into<String>) -> Self {
1766 Self {
1767 content: vec![Content::Text {
1768 text: message.into(),
1769 annotations: None,
1770 meta: None,
1771 }],
1772 is_error: true,
1773 structured_content: None,
1774 meta: None,
1775 }
1776 }
1777
1778 pub fn json(value: Value) -> Self {
1786 let text = serde_json::to_string_pretty(&value).unwrap_or_default();
1787 Self {
1788 content: vec![Content::Text {
1789 text,
1790 annotations: None,
1791 meta: None,
1792 }],
1793 is_error: false,
1794 structured_content: Some(value),
1795 meta: None,
1796 }
1797 }
1798
1799 pub fn from_serialize(
1831 value: &impl serde::Serialize,
1832 ) -> std::result::Result<Self, crate::error::Error> {
1833 let json_value = serde_json::to_value(value)
1834 .map_err(|e| crate::error::Error::tool(format!("Serialization failed: {}", e)))?;
1835 Ok(Self::json(json_value))
1836 }
1837
1838 pub fn from_list<T: serde::Serialize>(
1865 key: &str,
1866 items: &[T],
1867 ) -> std::result::Result<Self, crate::error::Error> {
1868 Self::from_serialize(&serde_json::json!({ key: items, "count": items.len() }))
1869 }
1870
1871 pub fn image(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1873 Self {
1874 content: vec![Content::Image {
1875 data: data.into(),
1876 mime_type: mime_type.into(),
1877 annotations: None,
1878 meta: None,
1879 }],
1880 is_error: false,
1881 structured_content: None,
1882 meta: None,
1883 }
1884 }
1885
1886 pub fn audio(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1888 Self {
1889 content: vec![Content::Audio {
1890 data: data.into(),
1891 mime_type: mime_type.into(),
1892 annotations: None,
1893 meta: None,
1894 }],
1895 is_error: false,
1896 structured_content: None,
1897 meta: None,
1898 }
1899 }
1900
1901 pub fn resource_link(uri: impl Into<String>, name: impl Into<String>) -> Self {
1903 Self {
1904 content: vec![Content::ResourceLink {
1905 uri: uri.into(),
1906 name: name.into(),
1907 title: None,
1908 description: None,
1909 mime_type: None,
1910 size: None,
1911 icons: None,
1912 annotations: None,
1913 meta: None,
1914 }],
1915 is_error: false,
1916 structured_content: None,
1917 meta: None,
1918 }
1919 }
1920
1921 pub fn resource_link_with_meta(
1923 uri: impl Into<String>,
1924 name: impl Into<String>,
1925 description: Option<String>,
1926 mime_type: Option<String>,
1927 ) -> Self {
1928 Self {
1929 content: vec![Content::ResourceLink {
1930 uri: uri.into(),
1931 name: name.into(),
1932 title: None,
1933 description,
1934 mime_type,
1935 size: None,
1936 icons: None,
1937 annotations: None,
1938 meta: None,
1939 }],
1940 is_error: false,
1941 structured_content: None,
1942 meta: None,
1943 }
1944 }
1945
1946 pub fn resource(resource: ResourceContent) -> Self {
1948 Self {
1949 content: vec![Content::Resource {
1950 resource,
1951 annotations: None,
1952 meta: None,
1953 }],
1954 is_error: false,
1955 structured_content: None,
1956 meta: None,
1957 }
1958 }
1959
1960 pub fn all_text(&self) -> String {
1974 self.content.iter().filter_map(|c| c.as_text()).collect()
1975 }
1976
1977 pub fn first_text(&self) -> Option<&str> {
1990 self.content.iter().find_map(|c| c.as_text())
1991 }
1992
1993 pub fn as_json(&self) -> Option<Result<Value, serde_json::Error>> {
2010 if let Some(ref sc) = self.structured_content {
2011 return Some(Ok(sc.clone()));
2012 }
2013 self.first_text().map(serde_json::from_str)
2014 }
2015
2016 pub fn deserialize<T: DeserializeOwned>(&self) -> Option<Result<T, serde_json::Error>> {
2036 if let Some(ref sc) = self.structured_content {
2037 return Some(serde_json::from_value(sc.clone()));
2038 }
2039 self.first_text().map(serde_json::from_str)
2040 }
2041}
2042
2043#[derive(Debug, Clone, Serialize, Deserialize)]
2048#[serde(tag = "type", rename_all = "snake_case")]
2049pub enum Content {
2050 Text {
2052 text: String,
2054 #[serde(skip_serializing_if = "Option::is_none")]
2056 annotations: Option<ContentAnnotations>,
2057 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2059 meta: Option<Value>,
2060 },
2061 Image {
2063 data: String,
2065 #[serde(rename = "mimeType")]
2067 mime_type: String,
2068 #[serde(skip_serializing_if = "Option::is_none")]
2070 annotations: Option<ContentAnnotations>,
2071 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2073 meta: Option<Value>,
2074 },
2075 Audio {
2077 data: String,
2079 #[serde(rename = "mimeType")]
2081 mime_type: String,
2082 #[serde(skip_serializing_if = "Option::is_none")]
2084 annotations: Option<ContentAnnotations>,
2085 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2087 meta: Option<Value>,
2088 },
2089 Resource {
2091 resource: ResourceContent,
2093 #[serde(skip_serializing_if = "Option::is_none")]
2095 annotations: Option<ContentAnnotations>,
2096 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2098 meta: Option<Value>,
2099 },
2100 ResourceLink {
2102 uri: String,
2104 name: String,
2106 #[serde(default, skip_serializing_if = "Option::is_none")]
2108 title: Option<String>,
2109 #[serde(skip_serializing_if = "Option::is_none")]
2111 description: Option<String>,
2112 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
2114 mime_type: Option<String>,
2115 #[serde(default, skip_serializing_if = "Option::is_none")]
2117 size: Option<u64>,
2118 #[serde(default, skip_serializing_if = "Option::is_none")]
2120 icons: Option<Vec<ToolIcon>>,
2121 #[serde(skip_serializing_if = "Option::is_none")]
2122 annotations: Option<ContentAnnotations>,
2123 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2125 meta: Option<Value>,
2126 },
2127}
2128
2129#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2131pub struct ContentAnnotations {
2132 #[serde(skip_serializing_if = "Option::is_none")]
2134 pub audience: Option<Vec<ContentRole>>,
2135 #[serde(skip_serializing_if = "Option::is_none")]
2137 pub priority: Option<f64>,
2138 #[serde(rename = "lastModified", skip_serializing_if = "Option::is_none")]
2140 pub last_modified: Option<String>,
2141}
2142
2143impl Content {
2144 pub fn text(text: impl Into<String>) -> Self {
2170 Content::Text {
2171 text: text.into(),
2172 annotations: None,
2173 meta: None,
2174 }
2175 }
2176
2177 pub fn as_text(&self) -> Option<&str> {
2190 match self {
2191 Content::Text { text, .. } => Some(text),
2192 _ => None,
2193 }
2194 }
2195}
2196
2197#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2201#[serde(rename_all = "lowercase")]
2202pub enum ContentRole {
2203 User,
2205 Assistant,
2207}
2208
2209#[derive(Debug, Clone, Serialize, Deserialize)]
2213#[serde(rename_all = "camelCase")]
2214pub struct ResourceContent {
2215 pub uri: String,
2217 #[serde(skip_serializing_if = "Option::is_none")]
2219 pub mime_type: Option<String>,
2220 #[serde(skip_serializing_if = "Option::is_none")]
2222 pub text: Option<String>,
2223 #[serde(skip_serializing_if = "Option::is_none")]
2225 pub blob: Option<String>,
2226 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2228 pub meta: Option<Value>,
2229}
2230
2231#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2236pub struct ListResourcesParams {
2237 #[serde(default, skip_serializing_if = "Option::is_none")]
2238 pub cursor: Option<String>,
2239 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2241 pub meta: Option<RequestMeta>,
2242}
2243
2244#[derive(Debug, Clone, Serialize, Deserialize)]
2245#[serde(rename_all = "camelCase")]
2246pub struct ListResourcesResult {
2247 pub resources: Vec<ResourceDefinition>,
2248 #[serde(default, skip_serializing_if = "Option::is_none")]
2249 pub next_cursor: Option<String>,
2250 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2252 pub meta: Option<Value>,
2253}
2254
2255#[derive(Debug, Clone, Serialize, Deserialize)]
2256#[serde(rename_all = "camelCase")]
2257pub struct ResourceDefinition {
2258 pub uri: String,
2259 pub name: String,
2260 #[serde(skip_serializing_if = "Option::is_none")]
2262 pub title: Option<String>,
2263 #[serde(skip_serializing_if = "Option::is_none")]
2264 pub description: Option<String>,
2265 #[serde(skip_serializing_if = "Option::is_none")]
2266 pub mime_type: Option<String>,
2267 #[serde(skip_serializing_if = "Option::is_none")]
2269 pub icons: Option<Vec<ToolIcon>>,
2270 #[serde(skip_serializing_if = "Option::is_none")]
2272 pub size: Option<u64>,
2273 #[serde(skip_serializing_if = "Option::is_none")]
2275 pub annotations: Option<ContentAnnotations>,
2276 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2278 pub meta: Option<Value>,
2279}
2280
2281#[derive(Debug, Clone, Serialize, Deserialize)]
2282pub struct ReadResourceParams {
2283 pub uri: String,
2284 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2286 pub meta: Option<RequestMeta>,
2287}
2288
2289#[derive(Debug, Clone, Serialize, Deserialize)]
2290pub struct ReadResourceResult {
2291 pub contents: Vec<ResourceContent>,
2292 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2294 pub meta: Option<Value>,
2295}
2296
2297impl ReadResourceResult {
2298 pub fn text(uri: impl Into<String>, content: impl Into<String>) -> Self {
2308 Self {
2309 contents: vec![ResourceContent {
2310 uri: uri.into(),
2311 mime_type: Some("text/plain".to_string()),
2312 text: Some(content.into()),
2313 blob: None,
2314 meta: None,
2315 }],
2316 meta: None,
2317 }
2318 }
2319
2320 pub fn text_with_mime(
2334 uri: impl Into<String>,
2335 content: impl Into<String>,
2336 mime_type: impl Into<String>,
2337 ) -> Self {
2338 Self {
2339 contents: vec![ResourceContent {
2340 uri: uri.into(),
2341 mime_type: Some(mime_type.into()),
2342 text: Some(content.into()),
2343 blob: None,
2344 meta: None,
2345 }],
2346 meta: None,
2347 }
2348 }
2349
2350 pub fn json<T: serde::Serialize>(uri: impl Into<String>, value: &T) -> Self {
2364 let json_string =
2365 serde_json::to_string_pretty(value).unwrap_or_else(|_| "null".to_string());
2366 Self {
2367 contents: vec![ResourceContent {
2368 uri: uri.into(),
2369 mime_type: Some("application/json".to_string()),
2370 text: Some(json_string),
2371 blob: None,
2372 meta: None,
2373 }],
2374 meta: None,
2375 }
2376 }
2377
2378 pub fn blob(uri: impl Into<String>, bytes: &[u8]) -> Self {
2389 use base64::Engine;
2390 let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
2391 Self {
2392 contents: vec![ResourceContent {
2393 uri: uri.into(),
2394 mime_type: Some("application/octet-stream".to_string()),
2395 text: None,
2396 blob: Some(encoded),
2397 meta: None,
2398 }],
2399 meta: None,
2400 }
2401 }
2402
2403 pub fn blob_with_mime(
2414 uri: impl Into<String>,
2415 bytes: &[u8],
2416 mime_type: impl Into<String>,
2417 ) -> Self {
2418 use base64::Engine;
2419 let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
2420 Self {
2421 contents: vec![ResourceContent {
2422 uri: uri.into(),
2423 mime_type: Some(mime_type.into()),
2424 text: None,
2425 blob: Some(encoded),
2426 meta: None,
2427 }],
2428 meta: None,
2429 }
2430 }
2431
2432 pub fn first_text(&self) -> Option<&str> {
2445 self.contents.first().and_then(|c| c.text.as_deref())
2446 }
2447
2448 pub fn first_uri(&self) -> Option<&str> {
2461 self.contents.first().map(|c| c.uri.as_str())
2462 }
2463
2464 pub fn as_json(&self) -> Option<Result<Value, serde_json::Error>> {
2479 self.first_text().map(serde_json::from_str)
2480 }
2481
2482 pub fn deserialize<T: DeserializeOwned>(&self) -> Option<Result<T, serde_json::Error>> {
2501 self.first_text().map(serde_json::from_str)
2502 }
2503}
2504
2505#[derive(Debug, Clone, Deserialize)]
2506pub struct SubscribeResourceParams {
2507 pub uri: String,
2508 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2510 pub meta: Option<RequestMeta>,
2511}
2512
2513#[derive(Debug, Clone, Deserialize)]
2514pub struct UnsubscribeResourceParams {
2515 pub uri: String,
2516 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2518 pub meta: Option<RequestMeta>,
2519}
2520
2521#[derive(Debug, Clone, Default, Deserialize)]
2523pub struct ListResourceTemplatesParams {
2524 #[serde(default)]
2526 pub cursor: Option<String>,
2527 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2529 pub meta: Option<RequestMeta>,
2530}
2531
2532#[derive(Debug, Clone, Serialize)]
2534#[serde(rename_all = "camelCase")]
2535pub struct ListResourceTemplatesResult {
2536 pub resource_templates: Vec<ResourceTemplateDefinition>,
2538 #[serde(skip_serializing_if = "Option::is_none")]
2540 pub next_cursor: Option<String>,
2541 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2543 pub meta: Option<Value>,
2544}
2545
2546#[derive(Debug, Clone, Serialize, Deserialize)]
2562#[serde(rename_all = "camelCase")]
2563pub struct ResourceTemplateDefinition {
2564 pub uri_template: String,
2566 pub name: String,
2568 #[serde(skip_serializing_if = "Option::is_none")]
2570 pub title: Option<String>,
2571 #[serde(skip_serializing_if = "Option::is_none")]
2573 pub description: Option<String>,
2574 #[serde(skip_serializing_if = "Option::is_none")]
2576 pub mime_type: Option<String>,
2577 #[serde(skip_serializing_if = "Option::is_none")]
2579 pub icons: Option<Vec<ToolIcon>>,
2580 #[serde(skip_serializing_if = "Option::is_none")]
2582 pub annotations: Option<ContentAnnotations>,
2583 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2585 pub arguments: Vec<PromptArgument>,
2586 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2588 pub meta: Option<Value>,
2589}
2590
2591#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2596pub struct ListPromptsParams {
2597 #[serde(default, skip_serializing_if = "Option::is_none")]
2598 pub cursor: Option<String>,
2599 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2601 pub meta: Option<RequestMeta>,
2602}
2603
2604#[derive(Debug, Clone, Serialize, Deserialize)]
2605#[serde(rename_all = "camelCase")]
2606pub struct ListPromptsResult {
2607 pub prompts: Vec<PromptDefinition>,
2608 #[serde(default, skip_serializing_if = "Option::is_none")]
2609 pub next_cursor: Option<String>,
2610 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2612 pub meta: Option<Value>,
2613}
2614
2615#[derive(Debug, Clone, Serialize, Deserialize)]
2616pub struct PromptDefinition {
2617 pub name: String,
2618 #[serde(skip_serializing_if = "Option::is_none")]
2620 pub title: Option<String>,
2621 #[serde(skip_serializing_if = "Option::is_none")]
2622 pub description: Option<String>,
2623 #[serde(skip_serializing_if = "Option::is_none")]
2625 pub icons: Option<Vec<ToolIcon>>,
2626 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2627 pub arguments: Vec<PromptArgument>,
2628 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2630 pub meta: Option<Value>,
2631}
2632
2633#[derive(Debug, Clone, Serialize, Deserialize)]
2634pub struct PromptArgument {
2635 pub name: String,
2636 #[serde(skip_serializing_if = "Option::is_none")]
2637 pub description: Option<String>,
2638 #[serde(default)]
2639 pub required: bool,
2640}
2641
2642#[derive(Debug, Clone, Serialize, Deserialize)]
2643pub struct GetPromptParams {
2644 pub name: String,
2645 #[serde(default)]
2646 pub arguments: std::collections::HashMap<String, String>,
2647 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2649 pub meta: Option<RequestMeta>,
2650}
2651
2652#[derive(Debug, Clone, Serialize, Deserialize)]
2653pub struct GetPromptResult {
2654 #[serde(default, skip_serializing_if = "Option::is_none")]
2655 pub description: Option<String>,
2656 pub messages: Vec<PromptMessage>,
2657 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2659 pub meta: Option<Value>,
2660}
2661
2662impl GetPromptResult {
2663 pub fn user_message(text: impl Into<String>) -> Self {
2673 Self {
2674 description: None,
2675 messages: vec![PromptMessage {
2676 role: PromptRole::User,
2677 content: Content::Text {
2678 text: text.into(),
2679 annotations: None,
2680 meta: None,
2681 },
2682 meta: None,
2683 }],
2684 meta: None,
2685 }
2686 }
2687
2688 pub fn user_message_with_description(
2701 text: impl Into<String>,
2702 description: impl Into<String>,
2703 ) -> Self {
2704 Self {
2705 description: Some(description.into()),
2706 messages: vec![PromptMessage {
2707 role: PromptRole::User,
2708 content: Content::Text {
2709 text: text.into(),
2710 annotations: None,
2711 meta: None,
2712 },
2713 meta: None,
2714 }],
2715 meta: None,
2716 }
2717 }
2718
2719 pub fn assistant_message(text: impl Into<String>) -> Self {
2729 Self {
2730 description: None,
2731 messages: vec![PromptMessage {
2732 role: PromptRole::Assistant,
2733 content: Content::Text {
2734 text: text.into(),
2735 annotations: None,
2736 meta: None,
2737 },
2738 meta: None,
2739 }],
2740 meta: None,
2741 }
2742 }
2743
2744 pub fn builder() -> GetPromptResultBuilder {
2759 GetPromptResultBuilder::new()
2760 }
2761
2762 pub fn first_message_text(&self) -> Option<&str> {
2776 self.messages.first().and_then(|m| m.content.as_text())
2777 }
2778
2779 pub fn as_json(&self) -> Option<Result<Value, serde_json::Error>> {
2794 self.first_message_text().map(serde_json::from_str)
2795 }
2796
2797 pub fn deserialize<T: DeserializeOwned>(&self) -> Option<Result<T, serde_json::Error>> {
2816 self.first_message_text().map(serde_json::from_str)
2817 }
2818}
2819
2820#[derive(Debug, Clone, Default)]
2822pub struct GetPromptResultBuilder {
2823 description: Option<String>,
2824 messages: Vec<PromptMessage>,
2825}
2826
2827impl GetPromptResultBuilder {
2828 pub fn new() -> Self {
2830 Self::default()
2831 }
2832
2833 pub fn description(mut self, description: impl Into<String>) -> Self {
2835 self.description = Some(description.into());
2836 self
2837 }
2838
2839 pub fn user(mut self, text: impl Into<String>) -> Self {
2841 self.messages.push(PromptMessage {
2842 role: PromptRole::User,
2843 content: Content::Text {
2844 text: text.into(),
2845 annotations: None,
2846 meta: None,
2847 },
2848 meta: None,
2849 });
2850 self
2851 }
2852
2853 pub fn assistant(mut self, text: impl Into<String>) -> Self {
2855 self.messages.push(PromptMessage {
2856 role: PromptRole::Assistant,
2857 content: Content::Text {
2858 text: text.into(),
2859 annotations: None,
2860 meta: None,
2861 },
2862 meta: None,
2863 });
2864 self
2865 }
2866
2867 pub fn build(self) -> GetPromptResult {
2869 GetPromptResult {
2870 description: self.description,
2871 messages: self.messages,
2872 meta: None,
2873 }
2874 }
2875}
2876
2877#[derive(Debug, Clone, Serialize, Deserialize)]
2878pub struct PromptMessage {
2879 pub role: PromptRole,
2880 pub content: Content,
2881 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2883 pub meta: Option<Value>,
2884}
2885
2886#[derive(Debug, Clone, Serialize, Deserialize)]
2887#[serde(rename_all = "lowercase")]
2888pub enum PromptRole {
2889 User,
2890 Assistant,
2891}
2892
2893#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
2899#[serde(rename_all = "camelCase")]
2900pub enum TaskSupportMode {
2901 Required,
2903 Optional,
2905 #[default]
2907 Forbidden,
2908}
2909
2910#[derive(Debug, Clone, Serialize, Deserialize)]
2912#[serde(rename_all = "camelCase")]
2913pub struct ToolExecution {
2914 #[serde(default, skip_serializing_if = "Option::is_none")]
2916 pub task_support: Option<TaskSupportMode>,
2917}
2918
2919#[derive(Debug, Clone, Serialize, Deserialize)]
2921#[serde(rename_all = "camelCase")]
2922pub struct TaskRequestParams {
2923 #[serde(default, skip_serializing_if = "Option::is_none")]
2925 pub ttl: Option<u64>,
2926}
2927
2928#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2930#[serde(rename_all = "snake_case")]
2931pub enum TaskStatus {
2932 Working,
2934 InputRequired,
2936 Completed,
2938 Failed,
2940 Cancelled,
2942}
2943
2944impl std::fmt::Display for TaskStatus {
2945 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2946 match self {
2947 TaskStatus::Working => write!(f, "working"),
2948 TaskStatus::InputRequired => write!(f, "input_required"),
2949 TaskStatus::Completed => write!(f, "completed"),
2950 TaskStatus::Failed => write!(f, "failed"),
2951 TaskStatus::Cancelled => write!(f, "cancelled"),
2952 }
2953 }
2954}
2955
2956impl TaskStatus {
2957 pub fn is_terminal(&self) -> bool {
2959 matches!(
2960 self,
2961 TaskStatus::Completed | TaskStatus::Failed | TaskStatus::Cancelled
2962 )
2963 }
2964}
2965
2966#[derive(Debug, Clone, Serialize, Deserialize)]
2968#[serde(rename_all = "camelCase")]
2969pub struct TaskObject {
2970 pub task_id: String,
2972 pub status: TaskStatus,
2974 #[serde(skip_serializing_if = "Option::is_none")]
2976 pub status_message: Option<String>,
2977 pub created_at: String,
2979 pub last_updated_at: String,
2981 pub ttl: Option<u64>,
2983 #[serde(skip_serializing_if = "Option::is_none")]
2985 pub poll_interval: Option<u64>,
2986 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2988 pub meta: Option<Value>,
2989}
2990
2991#[deprecated(note = "Use TaskObject instead")]
2993pub type TaskInfo = TaskObject;
2994
2995#[derive(Debug, Clone, Serialize, Deserialize)]
2997#[serde(rename_all = "camelCase")]
2998pub struct CreateTaskResult {
2999 pub task: TaskObject,
3001 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3003 pub meta: Option<Value>,
3004}
3005
3006#[derive(Debug, Clone, Default, Deserialize)]
3008#[serde(rename_all = "camelCase")]
3009pub struct ListTasksParams {
3010 #[serde(default)]
3012 pub status: Option<TaskStatus>,
3013 #[serde(default)]
3015 pub cursor: Option<String>,
3016 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3018 pub meta: Option<RequestMeta>,
3019}
3020
3021#[derive(Debug, Clone, Serialize)]
3023#[serde(rename_all = "camelCase")]
3024pub struct ListTasksResult {
3025 pub tasks: Vec<TaskObject>,
3027 #[serde(skip_serializing_if = "Option::is_none")]
3029 pub next_cursor: Option<String>,
3030}
3031
3032#[derive(Debug, Clone, Deserialize)]
3034#[serde(rename_all = "camelCase")]
3035pub struct GetTaskInfoParams {
3036 pub task_id: String,
3038 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3040 pub meta: Option<RequestMeta>,
3041}
3042
3043#[derive(Debug, Clone, Deserialize)]
3045#[serde(rename_all = "camelCase")]
3046pub struct GetTaskResultParams {
3047 pub task_id: String,
3049 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3051 pub meta: Option<RequestMeta>,
3052}
3053
3054#[derive(Debug, Clone, Deserialize)]
3056#[serde(rename_all = "camelCase")]
3057pub struct CancelTaskParams {
3058 pub task_id: String,
3060 #[serde(default)]
3062 pub reason: Option<String>,
3063 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3065 pub meta: Option<RequestMeta>,
3066}
3067
3068#[derive(Debug, Clone, Serialize, Deserialize)]
3073#[serde(rename_all = "camelCase")]
3074pub struct TaskStatusParams {
3075 pub task_id: String,
3077 pub status: TaskStatus,
3079 #[serde(skip_serializing_if = "Option::is_none")]
3081 pub status_message: Option<String>,
3082 pub created_at: String,
3084 pub last_updated_at: String,
3086 pub ttl: Option<u64>,
3088 #[serde(skip_serializing_if = "Option::is_none")]
3090 pub poll_interval: Option<u64>,
3091 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3093 pub meta: Option<Value>,
3094}
3095
3096pub type TaskStatusChangedParams = TaskStatusParams;
3098
3099#[derive(Debug, Clone, Serialize, Deserialize)]
3105#[serde(rename_all = "camelCase")]
3106pub struct ElicitFormParams {
3107 #[serde(default, skip_serializing_if = "Option::is_none")]
3109 pub mode: Option<ElicitMode>,
3110 pub message: String,
3112 pub requested_schema: ElicitFormSchema,
3114 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3116 pub meta: Option<RequestMeta>,
3117}
3118
3119#[derive(Debug, Clone, Serialize, Deserialize)]
3121#[serde(rename_all = "camelCase")]
3122pub struct ElicitUrlParams {
3123 #[serde(default, skip_serializing_if = "Option::is_none")]
3125 pub mode: Option<ElicitMode>,
3126 pub elicitation_id: String,
3128 pub message: String,
3130 pub url: String,
3132 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3134 pub meta: Option<RequestMeta>,
3135}
3136
3137#[derive(Debug, Clone, Serialize, Deserialize)]
3139#[serde(untagged)]
3140pub enum ElicitRequestParams {
3141 Form(ElicitFormParams),
3142 Url(ElicitUrlParams),
3143}
3144
3145#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
3147#[serde(rename_all = "lowercase")]
3148pub enum ElicitMode {
3149 Form,
3151 Url,
3153}
3154
3155#[derive(Debug, Clone, Serialize, Deserialize)]
3159pub struct ElicitFormSchema {
3160 #[serde(rename = "type")]
3162 pub schema_type: String,
3163 pub properties: std::collections::HashMap<String, PrimitiveSchemaDefinition>,
3165 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3167 pub required: Vec<String>,
3168}
3169
3170impl ElicitFormSchema {
3171 pub fn new() -> Self {
3173 Self {
3174 schema_type: "object".to_string(),
3175 properties: std::collections::HashMap::new(),
3176 required: Vec::new(),
3177 }
3178 }
3179
3180 pub fn string_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
3182 self.properties.insert(
3183 name.to_string(),
3184 PrimitiveSchemaDefinition::String(StringSchema {
3185 schema_type: "string".to_string(),
3186 title: None,
3187 description: description.map(|s| s.to_string()),
3188 format: None,
3189 pattern: None,
3190 min_length: None,
3191 max_length: None,
3192 default: None,
3193 }),
3194 );
3195 if required {
3196 self.required.push(name.to_string());
3197 }
3198 self
3199 }
3200
3201 pub fn string_field_with_default(
3203 mut self,
3204 name: &str,
3205 description: Option<&str>,
3206 required: bool,
3207 default: &str,
3208 ) -> Self {
3209 self.properties.insert(
3210 name.to_string(),
3211 PrimitiveSchemaDefinition::String(StringSchema {
3212 schema_type: "string".to_string(),
3213 title: None,
3214 description: description.map(|s| s.to_string()),
3215 format: None,
3216 pattern: None,
3217 min_length: None,
3218 max_length: None,
3219 default: Some(default.to_string()),
3220 }),
3221 );
3222 if required {
3223 self.required.push(name.to_string());
3224 }
3225 self
3226 }
3227
3228 pub fn integer_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
3230 self.properties.insert(
3231 name.to_string(),
3232 PrimitiveSchemaDefinition::Integer(IntegerSchema {
3233 schema_type: "integer".to_string(),
3234 title: None,
3235 description: description.map(|s| s.to_string()),
3236 minimum: None,
3237 maximum: None,
3238 default: None,
3239 }),
3240 );
3241 if required {
3242 self.required.push(name.to_string());
3243 }
3244 self
3245 }
3246
3247 pub fn integer_field_with_default(
3249 mut self,
3250 name: &str,
3251 description: Option<&str>,
3252 required: bool,
3253 default: i64,
3254 ) -> Self {
3255 self.properties.insert(
3256 name.to_string(),
3257 PrimitiveSchemaDefinition::Integer(IntegerSchema {
3258 schema_type: "integer".to_string(),
3259 title: None,
3260 description: description.map(|s| s.to_string()),
3261 minimum: None,
3262 maximum: None,
3263 default: Some(default),
3264 }),
3265 );
3266 if required {
3267 self.required.push(name.to_string());
3268 }
3269 self
3270 }
3271
3272 pub fn number_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
3274 self.properties.insert(
3275 name.to_string(),
3276 PrimitiveSchemaDefinition::Number(NumberSchema {
3277 schema_type: "number".to_string(),
3278 title: None,
3279 description: description.map(|s| s.to_string()),
3280 minimum: None,
3281 maximum: None,
3282 default: None,
3283 }),
3284 );
3285 if required {
3286 self.required.push(name.to_string());
3287 }
3288 self
3289 }
3290
3291 pub fn number_field_with_default(
3293 mut self,
3294 name: &str,
3295 description: Option<&str>,
3296 required: bool,
3297 default: f64,
3298 ) -> Self {
3299 self.properties.insert(
3300 name.to_string(),
3301 PrimitiveSchemaDefinition::Number(NumberSchema {
3302 schema_type: "number".to_string(),
3303 title: None,
3304 description: description.map(|s| s.to_string()),
3305 minimum: None,
3306 maximum: None,
3307 default: Some(default),
3308 }),
3309 );
3310 if required {
3311 self.required.push(name.to_string());
3312 }
3313 self
3314 }
3315
3316 pub fn boolean_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
3318 self.properties.insert(
3319 name.to_string(),
3320 PrimitiveSchemaDefinition::Boolean(BooleanSchema {
3321 schema_type: "boolean".to_string(),
3322 title: None,
3323 description: description.map(|s| s.to_string()),
3324 default: None,
3325 }),
3326 );
3327 if required {
3328 self.required.push(name.to_string());
3329 }
3330 self
3331 }
3332
3333 pub fn boolean_field_with_default(
3335 mut self,
3336 name: &str,
3337 description: Option<&str>,
3338 required: bool,
3339 default: bool,
3340 ) -> Self {
3341 self.properties.insert(
3342 name.to_string(),
3343 PrimitiveSchemaDefinition::Boolean(BooleanSchema {
3344 schema_type: "boolean".to_string(),
3345 title: None,
3346 description: description.map(|s| s.to_string()),
3347 default: Some(default),
3348 }),
3349 );
3350 if required {
3351 self.required.push(name.to_string());
3352 }
3353 self
3354 }
3355
3356 pub fn enum_field(
3358 mut self,
3359 name: &str,
3360 description: Option<&str>,
3361 options: Vec<String>,
3362 required: bool,
3363 ) -> Self {
3364 self.properties.insert(
3365 name.to_string(),
3366 PrimitiveSchemaDefinition::SingleSelectEnum(SingleSelectEnumSchema {
3367 schema_type: "string".to_string(),
3368 title: None,
3369 description: description.map(|s| s.to_string()),
3370 enum_values: options,
3371 default: None,
3372 }),
3373 );
3374 if required {
3375 self.required.push(name.to_string());
3376 }
3377 self
3378 }
3379
3380 pub fn enum_field_with_default(
3382 mut self,
3383 name: &str,
3384 description: Option<&str>,
3385 required: bool,
3386 options: &[&str],
3387 default: &str,
3388 ) -> Self {
3389 self.properties.insert(
3390 name.to_string(),
3391 PrimitiveSchemaDefinition::SingleSelectEnum(SingleSelectEnumSchema {
3392 schema_type: "string".to_string(),
3393 title: None,
3394 description: description.map(|s| s.to_string()),
3395 enum_values: options.iter().map(|s| s.to_string()).collect(),
3396 default: Some(default.to_string()),
3397 }),
3398 );
3399 if required {
3400 self.required.push(name.to_string());
3401 }
3402 self
3403 }
3404
3405 pub fn raw_field(mut self, name: &str, schema: serde_json::Value, required: bool) -> Self {
3409 self.properties
3410 .insert(name.to_string(), PrimitiveSchemaDefinition::Raw(schema));
3411 if required {
3412 self.required.push(name.to_string());
3413 }
3414 self
3415 }
3416}
3417
3418impl Default for ElicitFormSchema {
3419 fn default() -> Self {
3420 Self::new()
3421 }
3422}
3423
3424#[derive(Debug, Clone, Serialize, Deserialize)]
3426#[serde(untagged)]
3427pub enum PrimitiveSchemaDefinition {
3428 String(StringSchema),
3430 Integer(IntegerSchema),
3432 Number(NumberSchema),
3434 Boolean(BooleanSchema),
3436 SingleSelectEnum(SingleSelectEnumSchema),
3438 MultiSelectEnum(MultiSelectEnumSchema),
3440 Raw(serde_json::Value),
3442}
3443
3444#[derive(Debug, Clone, Serialize, Deserialize)]
3446#[serde(rename_all = "camelCase")]
3447pub struct StringSchema {
3448 #[serde(rename = "type")]
3449 pub schema_type: String,
3450 #[serde(skip_serializing_if = "Option::is_none")]
3452 pub title: Option<String>,
3453 #[serde(skip_serializing_if = "Option::is_none")]
3454 pub description: Option<String>,
3455 #[serde(skip_serializing_if = "Option::is_none")]
3456 pub format: Option<String>,
3457 #[serde(skip_serializing_if = "Option::is_none")]
3459 pub pattern: Option<String>,
3460 #[serde(skip_serializing_if = "Option::is_none")]
3461 pub min_length: Option<u64>,
3462 #[serde(skip_serializing_if = "Option::is_none")]
3463 pub max_length: Option<u64>,
3464 #[serde(skip_serializing_if = "Option::is_none")]
3466 pub default: Option<String>,
3467}
3468
3469#[derive(Debug, Clone, Serialize, Deserialize)]
3471#[serde(rename_all = "camelCase")]
3472pub struct IntegerSchema {
3473 #[serde(rename = "type")]
3474 pub schema_type: String,
3475 #[serde(skip_serializing_if = "Option::is_none")]
3477 pub title: Option<String>,
3478 #[serde(skip_serializing_if = "Option::is_none")]
3479 pub description: Option<String>,
3480 #[serde(skip_serializing_if = "Option::is_none")]
3481 pub minimum: Option<i64>,
3482 #[serde(skip_serializing_if = "Option::is_none")]
3483 pub maximum: Option<i64>,
3484 #[serde(skip_serializing_if = "Option::is_none")]
3486 pub default: Option<i64>,
3487}
3488
3489#[derive(Debug, Clone, Serialize, Deserialize)]
3491#[serde(rename_all = "camelCase")]
3492pub struct NumberSchema {
3493 #[serde(rename = "type")]
3494 pub schema_type: String,
3495 #[serde(skip_serializing_if = "Option::is_none")]
3497 pub title: Option<String>,
3498 #[serde(skip_serializing_if = "Option::is_none")]
3499 pub description: Option<String>,
3500 #[serde(skip_serializing_if = "Option::is_none")]
3501 pub minimum: Option<f64>,
3502 #[serde(skip_serializing_if = "Option::is_none")]
3503 pub maximum: Option<f64>,
3504 #[serde(skip_serializing_if = "Option::is_none")]
3506 pub default: Option<f64>,
3507}
3508
3509#[derive(Debug, Clone, Serialize, Deserialize)]
3511#[serde(rename_all = "camelCase")]
3512pub struct BooleanSchema {
3513 #[serde(rename = "type")]
3514 pub schema_type: String,
3515 #[serde(skip_serializing_if = "Option::is_none")]
3517 pub title: Option<String>,
3518 #[serde(skip_serializing_if = "Option::is_none")]
3519 pub description: Option<String>,
3520 #[serde(skip_serializing_if = "Option::is_none")]
3522 pub default: Option<bool>,
3523}
3524
3525#[derive(Debug, Clone, Serialize, Deserialize)]
3527#[serde(rename_all = "camelCase")]
3528pub struct SingleSelectEnumSchema {
3529 #[serde(rename = "type")]
3530 pub schema_type: String,
3531 #[serde(skip_serializing_if = "Option::is_none")]
3533 pub title: Option<String>,
3534 #[serde(skip_serializing_if = "Option::is_none")]
3535 pub description: Option<String>,
3536 #[serde(rename = "enum")]
3537 pub enum_values: Vec<String>,
3538 #[serde(skip_serializing_if = "Option::is_none")]
3540 pub default: Option<String>,
3541}
3542
3543#[derive(Debug, Clone, Serialize, Deserialize)]
3545#[serde(rename_all = "camelCase")]
3546pub struct MultiSelectEnumSchema {
3547 #[serde(rename = "type")]
3548 pub schema_type: String,
3549 #[serde(skip_serializing_if = "Option::is_none")]
3551 pub title: Option<String>,
3552 #[serde(skip_serializing_if = "Option::is_none")]
3553 pub description: Option<String>,
3554 pub items: MultiSelectEnumItems,
3555 #[serde(skip_serializing_if = "Option::is_none")]
3556 pub unique_items: Option<bool>,
3557 #[serde(skip_serializing_if = "Option::is_none")]
3559 pub default: Option<Vec<String>>,
3560}
3561
3562#[derive(Debug, Clone, Serialize, Deserialize)]
3564pub struct MultiSelectEnumItems {
3565 #[serde(rename = "type")]
3566 pub schema_type: String,
3567 #[serde(rename = "enum")]
3568 pub enum_values: Vec<String>,
3569}
3570
3571#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
3573#[serde(rename_all = "lowercase")]
3574pub enum ElicitAction {
3575 Accept,
3577 Decline,
3579 Cancel,
3581}
3582
3583#[derive(Debug, Clone, Serialize, Deserialize)]
3585pub struct ElicitResult {
3586 pub action: ElicitAction,
3588 #[serde(default, skip_serializing_if = "Option::is_none")]
3590 pub content: Option<std::collections::HashMap<String, ElicitFieldValue>>,
3591 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3593 pub meta: Option<Value>,
3594}
3595
3596impl ElicitResult {
3597 pub fn accept(content: std::collections::HashMap<String, ElicitFieldValue>) -> Self {
3599 Self {
3600 action: ElicitAction::Accept,
3601 content: Some(content),
3602 meta: None,
3603 }
3604 }
3605
3606 pub fn decline() -> Self {
3608 Self {
3609 action: ElicitAction::Decline,
3610 content: None,
3611 meta: None,
3612 }
3613 }
3614
3615 pub fn cancel() -> Self {
3617 Self {
3618 action: ElicitAction::Cancel,
3619 content: None,
3620 meta: None,
3621 }
3622 }
3623}
3624
3625#[derive(Debug, Clone, Serialize, Deserialize)]
3627#[serde(untagged)]
3628pub enum ElicitFieldValue {
3629 String(String),
3630 Number(f64),
3631 Integer(i64),
3632 Boolean(bool),
3633 StringArray(Vec<String>),
3634}
3635
3636#[derive(Debug, Clone, Serialize, Deserialize)]
3638#[serde(rename_all = "camelCase")]
3639pub struct ElicitationCompleteParams {
3640 pub elicitation_id: String,
3642 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3644 pub meta: Option<Value>,
3645}
3646
3647#[derive(Debug, Clone, Default, Serialize)]
3652pub struct EmptyResult {}
3653
3654impl McpRequest {
3659 pub fn from_jsonrpc(req: &JsonRpcRequest) -> Result<Self, crate::error::Error> {
3661 let params = req
3662 .params
3663 .clone()
3664 .unwrap_or(Value::Object(Default::default()));
3665
3666 match req.method.as_str() {
3667 "initialize" => {
3668 let p: InitializeParams = serde_json::from_value(params)?;
3669 Ok(McpRequest::Initialize(p))
3670 }
3671 "tools/list" => {
3672 let p: ListToolsParams = serde_json::from_value(params).unwrap_or_default();
3673 Ok(McpRequest::ListTools(p))
3674 }
3675 "tools/call" => {
3676 let p: CallToolParams = serde_json::from_value(params)?;
3677 Ok(McpRequest::CallTool(p))
3678 }
3679 "resources/list" => {
3680 let p: ListResourcesParams = serde_json::from_value(params).unwrap_or_default();
3681 Ok(McpRequest::ListResources(p))
3682 }
3683 "resources/templates/list" => {
3684 let p: ListResourceTemplatesParams =
3685 serde_json::from_value(params).unwrap_or_default();
3686 Ok(McpRequest::ListResourceTemplates(p))
3687 }
3688 "resources/read" => {
3689 let p: ReadResourceParams = serde_json::from_value(params)?;
3690 Ok(McpRequest::ReadResource(p))
3691 }
3692 "resources/subscribe" => {
3693 let p: SubscribeResourceParams = serde_json::from_value(params)?;
3694 Ok(McpRequest::SubscribeResource(p))
3695 }
3696 "resources/unsubscribe" => {
3697 let p: UnsubscribeResourceParams = serde_json::from_value(params)?;
3698 Ok(McpRequest::UnsubscribeResource(p))
3699 }
3700 "prompts/list" => {
3701 let p: ListPromptsParams = serde_json::from_value(params).unwrap_or_default();
3702 Ok(McpRequest::ListPrompts(p))
3703 }
3704 "prompts/get" => {
3705 let p: GetPromptParams = serde_json::from_value(params)?;
3706 Ok(McpRequest::GetPrompt(p))
3707 }
3708 "tasks/list" => {
3709 let p: ListTasksParams = serde_json::from_value(params).unwrap_or_default();
3710 Ok(McpRequest::ListTasks(p))
3711 }
3712 "tasks/get" => {
3713 let p: GetTaskInfoParams = serde_json::from_value(params)?;
3714 Ok(McpRequest::GetTaskInfo(p))
3715 }
3716 "tasks/result" => {
3717 let p: GetTaskResultParams = serde_json::from_value(params)?;
3718 Ok(McpRequest::GetTaskResult(p))
3719 }
3720 "tasks/cancel" => {
3721 let p: CancelTaskParams = serde_json::from_value(params)?;
3722 Ok(McpRequest::CancelTask(p))
3723 }
3724 "ping" => Ok(McpRequest::Ping),
3725 "logging/setLevel" => {
3726 let p: SetLogLevelParams = serde_json::from_value(params)?;
3727 Ok(McpRequest::SetLoggingLevel(p))
3728 }
3729 "completion/complete" => {
3730 let p: CompleteParams = serde_json::from_value(params)?;
3731 Ok(McpRequest::Complete(p))
3732 }
3733 method => Ok(McpRequest::Unknown {
3734 method: method.to_string(),
3735 params: req.params.clone(),
3736 }),
3737 }
3738 }
3739}
3740
3741impl McpNotification {
3742 pub fn from_jsonrpc(notif: &JsonRpcNotification) -> Result<Self, crate::error::Error> {
3744 let params = notif
3745 .params
3746 .clone()
3747 .unwrap_or(Value::Object(Default::default()));
3748
3749 match notif.method.as_str() {
3750 notifications::INITIALIZED => Ok(McpNotification::Initialized),
3751 notifications::CANCELLED => {
3752 let p: CancelledParams = serde_json::from_value(params)?;
3753 Ok(McpNotification::Cancelled(p))
3754 }
3755 notifications::PROGRESS => {
3756 let p: ProgressParams = serde_json::from_value(params)?;
3757 Ok(McpNotification::Progress(p))
3758 }
3759 notifications::ROOTS_LIST_CHANGED => Ok(McpNotification::RootsListChanged),
3760 method => Ok(McpNotification::Unknown {
3761 method: method.to_string(),
3762 params: notif.params.clone(),
3763 }),
3764 }
3765 }
3766}
3767
3768#[cfg(test)]
3769mod tests {
3770 use super::*;
3771
3772 #[test]
3773 fn test_content_text_constructor() {
3774 let content = Content::text("hello world");
3775 assert_eq!(content.as_text(), Some("hello world"));
3776
3777 match &content {
3779 Content::Text {
3780 text, annotations, ..
3781 } => {
3782 assert_eq!(text, "hello world");
3783 assert!(annotations.is_none());
3784 }
3785 _ => panic!("expected Content::Text"),
3786 }
3787
3788 let content = Content::text(String::from("owned"));
3790 assert_eq!(content.as_text(), Some("owned"));
3791 }
3792
3793 #[test]
3794 fn test_elicit_form_schema_builder() {
3795 let schema = ElicitFormSchema::new()
3796 .string_field("name", Some("Your name"), true)
3797 .number_field("age", Some("Your age"), false)
3798 .boolean_field("agree", Some("Do you agree?"), true)
3799 .enum_field(
3800 "color",
3801 Some("Favorite color"),
3802 vec!["red".to_string(), "green".to_string(), "blue".to_string()],
3803 false,
3804 );
3805
3806 assert_eq!(schema.schema_type, "object");
3807 assert_eq!(schema.properties.len(), 4);
3808 assert_eq!(schema.required.len(), 2);
3809 assert!(schema.required.contains(&"name".to_string()));
3810 assert!(schema.required.contains(&"agree".to_string()));
3811 }
3812
3813 #[test]
3814 fn test_elicit_form_schema_serialization() {
3815 let schema = ElicitFormSchema::new().string_field("username", Some("Enter username"), true);
3816
3817 let json = serde_json::to_value(&schema).unwrap();
3818 assert_eq!(json["type"], "object");
3819 assert!(json["properties"]["username"]["type"] == "string");
3820 assert!(
3821 json["required"]
3822 .as_array()
3823 .unwrap()
3824 .contains(&serde_json::json!("username"))
3825 );
3826 }
3827
3828 #[test]
3829 fn test_elicit_result_accept() {
3830 let mut content = std::collections::HashMap::new();
3831 content.insert(
3832 "name".to_string(),
3833 ElicitFieldValue::String("Alice".to_string()),
3834 );
3835 content.insert("age".to_string(), ElicitFieldValue::Integer(30));
3836
3837 let result = ElicitResult::accept(content);
3838 assert_eq!(result.action, ElicitAction::Accept);
3839 assert!(result.content.is_some());
3840 }
3841
3842 #[test]
3843 fn test_elicit_result_decline() {
3844 let result = ElicitResult::decline();
3845 assert_eq!(result.action, ElicitAction::Decline);
3846 assert!(result.content.is_none());
3847 }
3848
3849 #[test]
3850 fn test_elicit_result_cancel() {
3851 let result = ElicitResult::cancel();
3852 assert_eq!(result.action, ElicitAction::Cancel);
3853 assert!(result.content.is_none());
3854 }
3855
3856 #[test]
3857 fn test_elicit_mode_serialization() {
3858 assert_eq!(
3859 serde_json::to_string(&ElicitMode::Form).unwrap(),
3860 "\"form\""
3861 );
3862 assert_eq!(serde_json::to_string(&ElicitMode::Url).unwrap(), "\"url\"");
3863 }
3864
3865 #[test]
3866 fn test_elicit_action_serialization() {
3867 assert_eq!(
3868 serde_json::to_string(&ElicitAction::Accept).unwrap(),
3869 "\"accept\""
3870 );
3871 assert_eq!(
3872 serde_json::to_string(&ElicitAction::Decline).unwrap(),
3873 "\"decline\""
3874 );
3875 assert_eq!(
3876 serde_json::to_string(&ElicitAction::Cancel).unwrap(),
3877 "\"cancel\""
3878 );
3879 }
3880
3881 #[test]
3882 fn test_elicitation_capability() {
3883 let cap = ElicitationCapability {
3884 form: Some(ElicitationFormCapability {}),
3885 url: None,
3886 };
3887
3888 let json = serde_json::to_value(&cap).unwrap();
3889 assert!(json["form"].is_object());
3890 assert!(json.get("url").is_none());
3891 }
3892
3893 #[test]
3894 fn test_client_capabilities_with_elicitation() {
3895 let caps = ClientCapabilities {
3896 roots: None,
3897 sampling: None,
3898 elicitation: Some(ElicitationCapability {
3899 form: Some(ElicitationFormCapability {}),
3900 url: Some(ElicitationUrlCapability {}),
3901 }),
3902 tasks: None,
3903 experimental: None,
3904 extensions: None,
3905 };
3906
3907 let json = serde_json::to_value(&caps).unwrap();
3908 assert!(json["elicitation"]["form"].is_object());
3909 assert!(json["elicitation"]["url"].is_object());
3910 }
3911
3912 #[test]
3913 fn test_elicit_url_params() {
3914 let params = ElicitUrlParams {
3915 mode: Some(ElicitMode::Url),
3916 elicitation_id: "abc123".to_string(),
3917 message: "Please authorize".to_string(),
3918 url: "https://example.com/auth".to_string(),
3919 meta: None,
3920 };
3921
3922 let json = serde_json::to_value(¶ms).unwrap();
3923 assert_eq!(json["mode"], "url");
3924 assert_eq!(json["elicitationId"], "abc123");
3925 assert_eq!(json["message"], "Please authorize");
3926 assert_eq!(json["url"], "https://example.com/auth");
3927 }
3928
3929 #[test]
3930 fn test_elicitation_complete_params() {
3931 let params = ElicitationCompleteParams {
3932 elicitation_id: "xyz789".to_string(),
3933 meta: None,
3934 };
3935
3936 let json = serde_json::to_value(¶ms).unwrap();
3937 assert_eq!(json["elicitationId"], "xyz789");
3938 }
3939
3940 #[test]
3941 fn test_root_new() {
3942 let root = Root::new("file:///home/user/project");
3943 assert_eq!(root.uri, "file:///home/user/project");
3944 assert!(root.name.is_none());
3945 }
3946
3947 #[test]
3948 fn test_root_with_name() {
3949 let root = Root::with_name("file:///home/user/project", "My Project");
3950 assert_eq!(root.uri, "file:///home/user/project");
3951 assert_eq!(root.name.as_deref(), Some("My Project"));
3952 }
3953
3954 #[test]
3955 fn test_root_serialization() {
3956 let root = Root::with_name("file:///workspace", "Workspace");
3957 let json = serde_json::to_value(&root).unwrap();
3958 assert_eq!(json["uri"], "file:///workspace");
3959 assert_eq!(json["name"], "Workspace");
3960 }
3961
3962 #[test]
3963 fn test_root_serialization_without_name() {
3964 let root = Root::new("file:///workspace");
3965 let json = serde_json::to_value(&root).unwrap();
3966 assert_eq!(json["uri"], "file:///workspace");
3967 assert!(json.get("name").is_none());
3968 }
3969
3970 #[test]
3971 fn test_root_deserialization() {
3972 let json = serde_json::json!({
3973 "uri": "file:///home/user",
3974 "name": "Home"
3975 });
3976 let root: Root = serde_json::from_value(json).unwrap();
3977 assert_eq!(root.uri, "file:///home/user");
3978 assert_eq!(root.name.as_deref(), Some("Home"));
3979 }
3980
3981 #[test]
3982 fn test_list_roots_result() {
3983 let result = ListRootsResult {
3984 roots: vec![
3985 Root::new("file:///project1"),
3986 Root::with_name("file:///project2", "Project 2"),
3987 ],
3988 meta: None,
3989 };
3990
3991 let json = serde_json::to_value(&result).unwrap();
3992 let roots = json["roots"].as_array().unwrap();
3993 assert_eq!(roots.len(), 2);
3994 assert_eq!(roots[0]["uri"], "file:///project1");
3995 assert_eq!(roots[1]["name"], "Project 2");
3996 }
3997
3998 #[test]
3999 fn test_roots_capability_serialization() {
4000 let cap = RootsCapability { list_changed: true };
4001 let json = serde_json::to_value(&cap).unwrap();
4002 assert_eq!(json["listChanged"], true);
4003 }
4004
4005 #[test]
4006 fn test_client_capabilities_with_roots() {
4007 let caps = ClientCapabilities {
4008 roots: Some(RootsCapability { list_changed: true }),
4009 sampling: None,
4010 elicitation: None,
4011 tasks: None,
4012 experimental: None,
4013 extensions: None,
4014 };
4015
4016 let json = serde_json::to_value(&caps).unwrap();
4017 assert_eq!(json["roots"]["listChanged"], true);
4018 }
4019
4020 #[test]
4021 fn test_roots_list_changed_notification_parsing() {
4022 let notif = JsonRpcNotification {
4023 jsonrpc: "2.0".to_string(),
4024 method: notifications::ROOTS_LIST_CHANGED.to_string(),
4025 params: None,
4026 };
4027
4028 let mcp_notif = McpNotification::from_jsonrpc(¬if).unwrap();
4029 assert!(matches!(mcp_notif, McpNotification::RootsListChanged));
4030 }
4031
4032 #[test]
4037 fn test_prompt_reference() {
4038 let ref_ = PromptReference::new("my-prompt");
4039 assert_eq!(ref_.ref_type, "ref/prompt");
4040 assert_eq!(ref_.name, "my-prompt");
4041
4042 let json = serde_json::to_value(&ref_).unwrap();
4043 assert_eq!(json["type"], "ref/prompt");
4044 assert_eq!(json["name"], "my-prompt");
4045 }
4046
4047 #[test]
4048 fn test_resource_reference() {
4049 let ref_ = ResourceReference::new("file:///path/to/file");
4050 assert_eq!(ref_.ref_type, "ref/resource");
4051 assert_eq!(ref_.uri, "file:///path/to/file");
4052
4053 let json = serde_json::to_value(&ref_).unwrap();
4054 assert_eq!(json["type"], "ref/resource");
4055 assert_eq!(json["uri"], "file:///path/to/file");
4056 }
4057
4058 #[test]
4059 fn test_completion_reference_prompt() {
4060 let ref_ = CompletionReference::prompt("test-prompt");
4061 let json = serde_json::to_value(&ref_).unwrap();
4062 assert_eq!(json["type"], "ref/prompt");
4063 assert_eq!(json["name"], "test-prompt");
4064 }
4065
4066 #[test]
4067 fn test_completion_reference_resource() {
4068 let ref_ = CompletionReference::resource("file:///test");
4069 let json = serde_json::to_value(&ref_).unwrap();
4070 assert_eq!(json["type"], "ref/resource");
4071 assert_eq!(json["uri"], "file:///test");
4072 }
4073
4074 #[test]
4075 fn test_completion_argument() {
4076 let arg = CompletionArgument::new("query", "SELECT * FROM");
4077 assert_eq!(arg.name, "query");
4078 assert_eq!(arg.value, "SELECT * FROM");
4079 }
4080
4081 #[test]
4082 fn test_complete_params_serialization() {
4083 let params = CompleteParams {
4084 reference: CompletionReference::prompt("sql-prompt"),
4085 argument: CompletionArgument::new("query", "SEL"),
4086 context: None,
4087 meta: None,
4088 };
4089
4090 let json = serde_json::to_value(¶ms).unwrap();
4091 assert_eq!(json["ref"]["type"], "ref/prompt");
4092 assert_eq!(json["ref"]["name"], "sql-prompt");
4093 assert_eq!(json["argument"]["name"], "query");
4094 assert_eq!(json["argument"]["value"], "SEL");
4095 assert!(json.get("context").is_none()); }
4097
4098 #[test]
4099 fn test_completion_new() {
4100 let completion = Completion::new(vec!["SELECT".to_string(), "SET".to_string()]);
4101 assert_eq!(completion.values.len(), 2);
4102 assert!(completion.total.is_none());
4103 assert!(completion.has_more.is_none());
4104 }
4105
4106 #[test]
4107 fn test_completion_with_pagination() {
4108 let completion =
4109 Completion::with_pagination(vec!["a".to_string(), "b".to_string()], 100, true);
4110 assert_eq!(completion.values.len(), 2);
4111 assert_eq!(completion.total, Some(100));
4112 assert_eq!(completion.has_more, Some(true));
4113 }
4114
4115 #[test]
4116 fn test_complete_result() {
4117 let result = CompleteResult::new(vec!["option1".to_string(), "option2".to_string()]);
4118 let json = serde_json::to_value(&result).unwrap();
4119 assert!(json["completion"]["values"].is_array());
4120 assert_eq!(json["completion"]["values"][0], "option1");
4121 }
4122
4123 #[test]
4128 fn test_model_hint() {
4129 let hint = ModelHint::new("claude-3-opus");
4130 assert_eq!(hint.name, Some("claude-3-opus".to_string()));
4131 }
4132
4133 #[test]
4134 fn test_model_preferences_builder() {
4135 let prefs = ModelPreferences::new()
4136 .speed(0.8)
4137 .intelligence(0.9)
4138 .cost(0.5)
4139 .hint("gpt-4")
4140 .hint("claude-3");
4141
4142 assert_eq!(prefs.speed_priority, Some(0.8));
4143 assert_eq!(prefs.intelligence_priority, Some(0.9));
4144 assert_eq!(prefs.cost_priority, Some(0.5));
4145 assert_eq!(prefs.hints.len(), 2);
4146 }
4147
4148 #[test]
4149 fn test_model_preferences_clamping() {
4150 let prefs = ModelPreferences::new().speed(1.5).cost(-0.5);
4151
4152 assert_eq!(prefs.speed_priority, Some(1.0)); assert_eq!(prefs.cost_priority, Some(0.0)); }
4155
4156 #[test]
4157 fn test_include_context_serialization() {
4158 assert_eq!(
4159 serde_json::to_string(&IncludeContext::AllServers).unwrap(),
4160 "\"allServers\""
4161 );
4162 assert_eq!(
4163 serde_json::to_string(&IncludeContext::ThisServer).unwrap(),
4164 "\"thisServer\""
4165 );
4166 assert_eq!(
4167 serde_json::to_string(&IncludeContext::None).unwrap(),
4168 "\"none\""
4169 );
4170 }
4171
4172 #[test]
4173 fn test_sampling_message_user() {
4174 let msg = SamplingMessage::user("Hello, how are you?");
4175 assert_eq!(msg.role, ContentRole::User);
4176 assert!(
4177 matches!(msg.content, SamplingContentOrArray::Single(SamplingContent::Text { ref text, .. }) if text == "Hello, how are you?")
4178 );
4179 }
4180
4181 #[test]
4182 fn test_sampling_message_assistant() {
4183 let msg = SamplingMessage::assistant("I'm doing well!");
4184 assert_eq!(msg.role, ContentRole::Assistant);
4185 }
4186
4187 #[test]
4188 fn test_sampling_content_text_serialization() {
4189 let content = SamplingContent::Text {
4190 text: "Hello".to_string(),
4191 annotations: None,
4192 meta: None,
4193 };
4194 let json = serde_json::to_value(&content).unwrap();
4195 assert_eq!(json["type"], "text");
4196 assert_eq!(json["text"], "Hello");
4197 }
4198
4199 #[test]
4200 fn test_sampling_content_image_serialization() {
4201 let content = SamplingContent::Image {
4202 data: "base64data".to_string(),
4203 mime_type: "image/png".to_string(),
4204 annotations: None,
4205 meta: None,
4206 };
4207 let json = serde_json::to_value(&content).unwrap();
4208 assert_eq!(json["type"], "image");
4209 assert_eq!(json["data"], "base64data");
4210 assert_eq!(json["mimeType"], "image/png");
4211 }
4212
4213 #[test]
4214 fn test_create_message_params() {
4215 let params = CreateMessageParams::new(
4216 vec![
4217 SamplingMessage::user("What is 2+2?"),
4218 SamplingMessage::assistant("4"),
4219 SamplingMessage::user("And 3+3?"),
4220 ],
4221 100,
4222 )
4223 .system_prompt("You are a math tutor")
4224 .temperature(0.7)
4225 .stop_sequence("END")
4226 .include_context(IncludeContext::ThisServer);
4227
4228 assert_eq!(params.messages.len(), 3);
4229 assert_eq!(params.max_tokens, 100);
4230 assert_eq!(
4231 params.system_prompt.as_deref(),
4232 Some("You are a math tutor")
4233 );
4234 assert_eq!(params.temperature, Some(0.7));
4235 assert_eq!(params.stop_sequences.len(), 1);
4236 assert_eq!(params.include_context, Some(IncludeContext::ThisServer));
4237 }
4238
4239 #[test]
4240 fn test_create_message_params_serialization() {
4241 let params = CreateMessageParams::new(vec![SamplingMessage::user("Hello")], 50);
4242
4243 let json = serde_json::to_value(¶ms).unwrap();
4244 assert!(json["messages"].is_array());
4245 assert_eq!(json["maxTokens"], 50);
4246 }
4247
4248 #[test]
4249 fn test_create_message_result_deserialization() {
4250 let json = serde_json::json!({
4251 "content": {
4252 "type": "text",
4253 "text": "The answer is 42"
4254 },
4255 "model": "claude-3-opus",
4256 "role": "assistant",
4257 "stopReason": "end_turn"
4258 });
4259
4260 let result: CreateMessageResult = serde_json::from_value(json).unwrap();
4261 assert_eq!(result.model, "claude-3-opus");
4262 assert_eq!(result.role, ContentRole::Assistant);
4263 assert_eq!(result.stop_reason.as_deref(), Some("end_turn"));
4264 }
4265
4266 #[test]
4267 fn test_completions_capability_serialization() {
4268 let cap = CompletionsCapability {};
4269 let json = serde_json::to_value(&cap).unwrap();
4270 assert!(json.is_object());
4271 }
4272
4273 #[test]
4274 fn test_server_capabilities_with_completions() {
4275 let caps = ServerCapabilities {
4276 completions: Some(CompletionsCapability {}),
4277 ..Default::default()
4278 };
4279
4280 let json = serde_json::to_value(&caps).unwrap();
4281 assert!(json["completions"].is_object());
4282 }
4283
4284 #[test]
4285 fn test_content_resource_link_serialization() {
4286 let content = Content::ResourceLink {
4287 uri: "file:///test.txt".to_string(),
4288 name: "test.txt".to_string(),
4289 title: None,
4290 description: Some("A test file".to_string()),
4291 mime_type: Some("text/plain".to_string()),
4292 size: None,
4293 icons: None,
4294 annotations: None,
4295 meta: None,
4296 };
4297 let json = serde_json::to_value(&content).unwrap();
4298 assert_eq!(json["type"], "resource_link");
4299 assert_eq!(json["uri"], "file:///test.txt");
4300 assert_eq!(json["name"], "test.txt");
4301 assert_eq!(json["description"], "A test file");
4302 assert_eq!(json["mimeType"], "text/plain");
4303 }
4304
4305 #[test]
4306 fn test_call_tool_result_resource_link() {
4307 let result = CallToolResult::resource_link("file:///output.json", "output.json");
4308 assert_eq!(result.content.len(), 1);
4309 assert!(!result.is_error);
4310 match &result.content[0] {
4311 Content::ResourceLink { uri, .. } => assert_eq!(uri, "file:///output.json"),
4312 _ => panic!("Expected ResourceLink content"),
4313 }
4314 }
4315
4316 #[test]
4317 fn test_call_tool_result_image() {
4318 let result = CallToolResult::image("base64data", "image/png");
4319 assert_eq!(result.content.len(), 1);
4320 match &result.content[0] {
4321 Content::Image {
4322 data, mime_type, ..
4323 } => {
4324 assert_eq!(data, "base64data");
4325 assert_eq!(mime_type, "image/png");
4326 }
4327 _ => panic!("Expected Image content"),
4328 }
4329 }
4330
4331 #[test]
4332 fn test_call_tool_result_audio() {
4333 let result = CallToolResult::audio("audiodata", "audio/wav");
4334 assert_eq!(result.content.len(), 1);
4335 match &result.content[0] {
4336 Content::Audio {
4337 data, mime_type, ..
4338 } => {
4339 assert_eq!(data, "audiodata");
4340 assert_eq!(mime_type, "audio/wav");
4341 }
4342 _ => panic!("Expected Audio content"),
4343 }
4344 }
4345
4346 #[test]
4347 fn test_sampling_tool_serialization() {
4348 let tool = SamplingTool {
4349 name: "get_weather".to_string(),
4350 title: None,
4351 description: Some("Get current weather".to_string()),
4352 input_schema: serde_json::json!({
4353 "type": "object",
4354 "properties": {
4355 "location": { "type": "string" }
4356 }
4357 }),
4358 output_schema: None,
4359 icons: None,
4360 annotations: None,
4361 execution: None,
4362 };
4363 let json = serde_json::to_value(&tool).unwrap();
4364 assert_eq!(json["name"], "get_weather");
4365 assert_eq!(json["description"], "Get current weather");
4366 assert!(json["inputSchema"]["properties"]["location"].is_object());
4367 }
4368
4369 #[test]
4370 fn test_tool_choice_modes() {
4371 let auto = ToolChoice::auto();
4372 assert_eq!(auto.mode, "auto");
4373 assert!(auto.name.is_none());
4374
4375 let required = ToolChoice::required();
4376 assert_eq!(required.mode, "required");
4377
4378 let none = ToolChoice::none();
4379 assert_eq!(none.mode, "none");
4380
4381 let tool = ToolChoice::tool("get_weather");
4382 assert_eq!(tool.mode, "tool");
4383 assert_eq!(tool.name.as_deref(), Some("get_weather"));
4384
4385 let json = serde_json::to_value(&auto).unwrap();
4387 assert_eq!(json["mode"], "auto");
4388 assert!(json.get("name").is_none());
4389
4390 let json = serde_json::to_value(&tool).unwrap();
4391 assert_eq!(json["mode"], "tool");
4392 assert_eq!(json["name"], "get_weather");
4393 }
4394
4395 #[test]
4396 fn test_sampling_content_tool_use() {
4397 let content = SamplingContent::ToolUse {
4398 id: "tool_123".to_string(),
4399 name: "get_weather".to_string(),
4400 input: serde_json::json!({"location": "San Francisco"}),
4401 meta: None,
4402 };
4403 let json = serde_json::to_value(&content).unwrap();
4404 assert_eq!(json["type"], "tool_use");
4405 assert_eq!(json["id"], "tool_123");
4406 assert_eq!(json["name"], "get_weather");
4407 assert_eq!(json["input"]["location"], "San Francisco");
4408 }
4409
4410 #[test]
4411 fn test_sampling_content_tool_result() {
4412 let content = SamplingContent::ToolResult {
4413 tool_use_id: "tool_123".to_string(),
4414 content: vec![SamplingContent::Text {
4415 text: "72F, sunny".to_string(),
4416 annotations: None,
4417 meta: None,
4418 }],
4419 structured_content: None,
4420 is_error: None,
4421 meta: None,
4422 };
4423 let json = serde_json::to_value(&content).unwrap();
4424 assert_eq!(json["type"], "tool_result");
4425 assert_eq!(json["toolUseId"], "tool_123");
4426 assert_eq!(json["content"][0]["type"], "text");
4427 }
4428
4429 #[test]
4430 fn test_sampling_content_or_array_single() {
4431 let json = serde_json::json!({
4432 "type": "text",
4433 "text": "Hello"
4434 });
4435 let content: SamplingContentOrArray = serde_json::from_value(json).unwrap();
4436 let items = content.items();
4437 assert_eq!(items.len(), 1);
4438 match items[0] {
4439 SamplingContent::Text { text, .. } => assert_eq!(text, "Hello"),
4440 _ => panic!("Expected text content"),
4441 }
4442 }
4443
4444 #[test]
4445 fn test_sampling_content_or_array_multiple() {
4446 let json = serde_json::json!([
4447 { "type": "text", "text": "Hello" },
4448 { "type": "text", "text": "World" }
4449 ]);
4450 let content: SamplingContentOrArray = serde_json::from_value(json).unwrap();
4451 let items = content.items();
4452 assert_eq!(items.len(), 2);
4453 }
4454
4455 #[test]
4456 fn test_create_message_params_with_tools() {
4457 let tool = SamplingTool {
4458 name: "calculator".to_string(),
4459 title: None,
4460 description: Some("Do math".to_string()),
4461 input_schema: serde_json::json!({"type": "object"}),
4462 output_schema: None,
4463 icons: None,
4464 annotations: None,
4465 execution: None,
4466 };
4467 let params = CreateMessageParams::new(vec![], 100)
4468 .tools(vec![tool])
4469 .tool_choice(ToolChoice::auto());
4470
4471 let json = serde_json::to_value(¶ms).unwrap();
4472 assert!(json["tools"].is_array());
4473 assert_eq!(json["tools"][0]["name"], "calculator");
4474 assert_eq!(json["toolChoice"]["mode"], "auto");
4475 }
4476
4477 #[test]
4478 fn test_create_message_result_content_items() {
4479 let result = CreateMessageResult {
4480 content: SamplingContentOrArray::Array(vec![
4481 SamplingContent::Text {
4482 text: "First".to_string(),
4483 annotations: None,
4484 meta: None,
4485 },
4486 SamplingContent::Text {
4487 text: "Second".to_string(),
4488 annotations: None,
4489 meta: None,
4490 },
4491 ]),
4492 model: "test".to_string(),
4493 role: ContentRole::Assistant,
4494 stop_reason: None,
4495 meta: None,
4496 };
4497 let items = result.content_items();
4498 assert_eq!(items.len(), 2);
4499 }
4500
4501 #[test]
4502 fn test_sampling_content_as_text() {
4503 let text_content = SamplingContent::Text {
4504 text: "Hello".to_string(),
4505 annotations: None,
4506 meta: None,
4507 };
4508 assert_eq!(text_content.as_text(), Some("Hello"));
4509
4510 let image_content = SamplingContent::Image {
4511 data: "base64data".to_string(),
4512 mime_type: "image/png".to_string(),
4513 annotations: None,
4514 meta: None,
4515 };
4516 assert_eq!(image_content.as_text(), None);
4517
4518 let audio_content = SamplingContent::Audio {
4519 data: "base64audio".to_string(),
4520 mime_type: "audio/wav".to_string(),
4521 annotations: None,
4522 meta: None,
4523 };
4524 assert_eq!(audio_content.as_text(), None);
4525 }
4526
4527 #[test]
4528 fn test_create_message_result_first_text_single() {
4529 let result = CreateMessageResult {
4530 content: SamplingContentOrArray::Single(SamplingContent::Text {
4531 text: "Hello, world!".to_string(),
4532 annotations: None,
4533 meta: None,
4534 }),
4535 model: "test".to_string(),
4536 role: ContentRole::Assistant,
4537 stop_reason: None,
4538 meta: None,
4539 };
4540 assert_eq!(result.first_text(), Some("Hello, world!"));
4541 }
4542
4543 #[test]
4544 fn test_create_message_result_first_text_array() {
4545 let result = CreateMessageResult {
4546 content: SamplingContentOrArray::Array(vec![
4547 SamplingContent::Text {
4548 text: "First".to_string(),
4549 annotations: None,
4550 meta: None,
4551 },
4552 SamplingContent::Text {
4553 text: "Second".to_string(),
4554 annotations: None,
4555 meta: None,
4556 },
4557 ]),
4558 model: "test".to_string(),
4559 role: ContentRole::Assistant,
4560 stop_reason: None,
4561 meta: None,
4562 };
4563 assert_eq!(result.first_text(), Some("First"));
4564 }
4565
4566 #[test]
4567 fn test_create_message_result_first_text_skips_non_text() {
4568 let result = CreateMessageResult {
4569 content: SamplingContentOrArray::Array(vec![
4570 SamplingContent::Image {
4571 data: "base64data".to_string(),
4572 mime_type: "image/png".to_string(),
4573 annotations: None,
4574 meta: None,
4575 },
4576 SamplingContent::Text {
4577 text: "After image".to_string(),
4578 annotations: None,
4579 meta: None,
4580 },
4581 ]),
4582 model: "test".to_string(),
4583 role: ContentRole::Assistant,
4584 stop_reason: None,
4585 meta: None,
4586 };
4587 assert_eq!(result.first_text(), Some("After image"));
4588 }
4589
4590 #[test]
4591 fn test_create_message_result_first_text_none() {
4592 let result = CreateMessageResult {
4593 content: SamplingContentOrArray::Single(SamplingContent::Image {
4594 data: "base64data".to_string(),
4595 mime_type: "image/png".to_string(),
4596 annotations: None,
4597 meta: None,
4598 }),
4599 model: "test".to_string(),
4600 role: ContentRole::Assistant,
4601 stop_reason: None,
4602 meta: None,
4603 };
4604 assert_eq!(result.first_text(), None);
4605 }
4606
4607 #[test]
4608 fn test_tool_annotations_accessors() {
4609 let annotations = ToolAnnotations {
4610 read_only_hint: true,
4611 destructive_hint: false,
4612 idempotent_hint: true,
4613 open_world_hint: false,
4614 ..Default::default()
4615 };
4616
4617 assert!(annotations.is_read_only());
4618 assert!(!annotations.is_destructive());
4619 assert!(annotations.is_idempotent());
4620 assert!(!annotations.is_open_world());
4621 }
4622
4623 #[test]
4624 fn test_tool_annotations_defaults() {
4625 let annotations = ToolAnnotations::default();
4627
4628 assert!(!annotations.is_read_only());
4629 assert!(annotations.is_destructive());
4630 assert!(!annotations.is_idempotent());
4631 assert!(annotations.is_open_world());
4632 }
4633
4634 #[test]
4635 fn test_tool_annotations_serde_defaults() {
4636 let annotations: ToolAnnotations = serde_json::from_str("{}").unwrap();
4639
4640 assert!(!annotations.is_read_only());
4641 assert!(annotations.is_destructive());
4642 assert!(!annotations.is_idempotent());
4643 assert!(annotations.is_open_world());
4644 }
4645
4646 #[test]
4647 fn test_tool_definition_accessors_with_annotations() {
4648 let def = ToolDefinition {
4649 name: "test".to_string(),
4650 title: None,
4651 description: None,
4652 input_schema: serde_json::json!({"type": "object"}),
4653 output_schema: None,
4654 icons: None,
4655 annotations: Some(ToolAnnotations {
4656 read_only_hint: true,
4657 idempotent_hint: true,
4658 destructive_hint: false,
4659 open_world_hint: false,
4660 ..Default::default()
4661 }),
4662 execution: None,
4663 meta: None,
4664 };
4665
4666 assert!(def.is_read_only());
4667 assert!(!def.is_destructive());
4668 assert!(def.is_idempotent());
4669 assert!(!def.is_open_world());
4670 }
4671
4672 #[test]
4673 fn test_tool_definition_accessors_without_annotations() {
4674 let def = ToolDefinition {
4675 name: "test".to_string(),
4676 title: None,
4677 description: None,
4678 input_schema: serde_json::json!({"type": "object"}),
4679 output_schema: None,
4680 icons: None,
4681 annotations: None,
4682 execution: None,
4683 meta: None,
4684 };
4685
4686 assert!(!def.is_read_only());
4688 assert!(def.is_destructive());
4689 assert!(!def.is_idempotent());
4690 assert!(def.is_open_world());
4691 }
4692
4693 #[test]
4694 fn test_call_tool_result_from_list() {
4695 #[derive(serde::Serialize)]
4696 struct Item {
4697 name: String,
4698 }
4699
4700 let items = vec![
4701 Item {
4702 name: "a".to_string(),
4703 },
4704 Item {
4705 name: "b".to_string(),
4706 },
4707 Item {
4708 name: "c".to_string(),
4709 },
4710 ];
4711
4712 let result = CallToolResult::from_list("items", &items).unwrap();
4713 assert!(!result.is_error);
4714
4715 let structured = result.structured_content.unwrap();
4716 assert_eq!(structured["count"], 3);
4717 assert_eq!(structured["items"].as_array().unwrap().len(), 3);
4718 assert_eq!(structured["items"][0]["name"], "a");
4719 }
4720
4721 #[test]
4722 fn test_call_tool_result_from_list_empty() {
4723 let items: Vec<String> = vec![];
4724 let result = CallToolResult::from_list("results", &items).unwrap();
4725 assert!(!result.is_error);
4726
4727 let structured = result.structured_content.unwrap();
4728 assert_eq!(structured["count"], 0);
4729 assert_eq!(structured["results"].as_array().unwrap().len(), 0);
4730 }
4731
4732 #[test]
4737 fn test_call_tool_result_as_json() {
4738 let result = CallToolResult::json(serde_json::json!({"key": "value"}));
4739 let value = result.as_json().unwrap().unwrap();
4740 assert_eq!(value["key"], "value");
4741 }
4742
4743 #[test]
4744 fn test_call_tool_result_as_json_from_text() {
4745 let result = CallToolResult::text(r#"{"key": "value"}"#);
4746 let value = result.as_json().unwrap().unwrap();
4747 assert_eq!(value["key"], "value");
4748 }
4749
4750 #[test]
4751 fn test_call_tool_result_as_json_none() {
4752 let result = CallToolResult::text("not json");
4753 let parsed = result.as_json().unwrap();
4754 assert!(parsed.is_err());
4755 }
4756
4757 #[test]
4758 fn test_call_tool_result_deserialize() {
4759 #[derive(Debug, serde::Deserialize, PartialEq)]
4760 struct Output {
4761 key: String,
4762 }
4763
4764 let result = CallToolResult::json(serde_json::json!({"key": "value"}));
4765 let output: Output = result.deserialize().unwrap().unwrap();
4766 assert_eq!(output.key, "value");
4767 }
4768
4769 #[test]
4770 fn test_call_tool_result_as_json_empty() {
4771 let result = CallToolResult {
4772 content: vec![],
4773 is_error: false,
4774 structured_content: None,
4775 meta: None,
4776 };
4777 assert!(result.as_json().is_none());
4778 }
4779
4780 #[test]
4781 fn test_call_tool_result_deserialize_from_text() {
4782 #[derive(Debug, serde::Deserialize, PartialEq)]
4783 struct Output {
4784 key: String,
4785 }
4786
4787 let result = CallToolResult::text(r#"{"key": "from_text"}"#);
4788 let output: Output = result.deserialize().unwrap().unwrap();
4789 assert_eq!(output.key, "from_text");
4790 }
4791
4792 #[test]
4793 fn test_read_resource_result_as_json() {
4794 let result = ReadResourceResult::json("data://config", &serde_json::json!({"port": 8080}));
4795 let value = result.as_json().unwrap().unwrap();
4796 assert_eq!(value["port"], 8080);
4797 }
4798
4799 #[test]
4800 fn test_read_resource_result_deserialize() {
4801 #[derive(Debug, serde::Deserialize, PartialEq)]
4802 struct Config {
4803 port: u16,
4804 }
4805
4806 let result = ReadResourceResult::json("data://config", &serde_json::json!({"port": 8080}));
4807 let config: Config = result.deserialize().unwrap().unwrap();
4808 assert_eq!(config.port, 8080);
4809 }
4810
4811 #[test]
4812 fn test_get_prompt_result_as_json() {
4813 let result = GetPromptResult::user_message(r#"{"action": "analyze"}"#);
4814 let value = result.as_json().unwrap().unwrap();
4815 assert_eq!(value["action"], "analyze");
4816 }
4817
4818 #[test]
4819 fn test_get_prompt_result_deserialize() {
4820 #[derive(Debug, serde::Deserialize, PartialEq)]
4821 struct Params {
4822 action: String,
4823 }
4824
4825 let result = GetPromptResult::user_message(r#"{"action": "analyze"}"#);
4826 let params: Params = result.deserialize().unwrap().unwrap();
4827 assert_eq!(params.action, "analyze");
4828 }
4829
4830 #[test]
4831 fn test_get_prompt_result_as_json_empty() {
4832 let result = GetPromptResult {
4833 description: None,
4834 messages: vec![],
4835 meta: None,
4836 };
4837 assert!(result.as_json().is_none());
4838 }
4839}