1use serde::{Deserialize, Serialize};
6
7use crate::jsonrpc::RequestId;
8use crate::types::{
9 ClientCapabilities, ClientInfo, Content, Prompt, PromptMessage, Resource, ResourceContent,
10 ResourceTemplate, ServerCapabilities, ServerInfo, Tool,
11};
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
21#[serde(untagged)]
22pub enum ProgressMarker {
23 String(String),
25 Number(i64),
27}
28
29impl From<String> for ProgressMarker {
30 fn from(s: String) -> Self {
31 ProgressMarker::String(s)
32 }
33}
34
35impl From<&str> for ProgressMarker {
36 fn from(s: &str) -> Self {
37 ProgressMarker::String(s.to_owned())
38 }
39}
40
41impl From<i64> for ProgressMarker {
42 fn from(n: i64) -> Self {
43 ProgressMarker::Number(n)
44 }
45}
46
47impl std::fmt::Display for ProgressMarker {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 match self {
50 ProgressMarker::String(s) => write!(f, "{s}"),
51 ProgressMarker::Number(n) => write!(f, "{n}"),
52 }
53 }
54}
55
56#[derive(Debug, Clone, Default, Serialize, Deserialize)]
58pub struct RequestMeta {
59 #[serde(rename = "progressTo\x6ben", skip_serializing_if = "Option::is_none")]
62 pub progress_marker: Option<ProgressMarker>,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct InitializeParams {
72 #[serde(rename = "protocolVersion")]
74 pub protocol_version: String,
75 pub capabilities: ClientCapabilities,
77 #[serde(rename = "clientInfo")]
79 pub client_info: ClientInfo,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct InitializeResult {
85 #[serde(rename = "protocolVersion")]
87 pub protocol_version: String,
88 pub capabilities: ServerCapabilities,
90 #[serde(rename = "serverInfo")]
92 pub server_info: ServerInfo,
93 #[serde(skip_serializing_if = "Option::is_none")]
95 pub instructions: Option<String>,
96}
97
98#[derive(Debug, Clone, Default, Serialize, Deserialize)]
104pub struct ListToolsParams {
105 #[serde(skip_serializing_if = "Option::is_none")]
107 pub cursor: Option<String>,
108 #[serde(
110 rename = "includeTags",
111 default,
112 skip_serializing_if = "Option::is_none"
113 )]
114 pub include_tags: Option<Vec<String>>,
115 #[serde(
117 rename = "excludeTags",
118 default,
119 skip_serializing_if = "Option::is_none"
120 )]
121 pub exclude_tags: Option<Vec<String>>,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct ListToolsResult {
127 pub tools: Vec<Tool>,
129 #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
131 pub next_cursor: Option<String>,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
136pub struct CallToolParams {
137 pub name: String,
139 #[serde(default, skip_serializing_if = "Option::is_none")]
141 pub arguments: Option<serde_json::Value>,
142 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
144 pub meta: Option<RequestMeta>,
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize)]
149pub struct CallToolResult {
150 pub content: Vec<Content>,
152 #[serde(
154 rename = "isError",
155 default,
156 skip_serializing_if = "std::ops::Not::not"
157 )]
158 pub is_error: bool,
159}
160
161#[derive(Debug, Clone, Default, Serialize, Deserialize)]
167pub struct ListResourcesParams {
168 #[serde(skip_serializing_if = "Option::is_none")]
170 pub cursor: Option<String>,
171 #[serde(
173 rename = "includeTags",
174 default,
175 skip_serializing_if = "Option::is_none"
176 )]
177 pub include_tags: Option<Vec<String>>,
178 #[serde(
180 rename = "excludeTags",
181 default,
182 skip_serializing_if = "Option::is_none"
183 )]
184 pub exclude_tags: Option<Vec<String>>,
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
189pub struct ListResourcesResult {
190 pub resources: Vec<Resource>,
192 #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
194 pub next_cursor: Option<String>,
195}
196
197#[derive(Debug, Clone, Default, Serialize, Deserialize)]
199pub struct ListResourceTemplatesParams {
200 #[serde(skip_serializing_if = "Option::is_none")]
202 pub cursor: Option<String>,
203 #[serde(
205 rename = "includeTags",
206 default,
207 skip_serializing_if = "Option::is_none"
208 )]
209 pub include_tags: Option<Vec<String>>,
210 #[serde(
212 rename = "excludeTags",
213 default,
214 skip_serializing_if = "Option::is_none"
215 )]
216 pub exclude_tags: Option<Vec<String>>,
217}
218
219#[derive(Debug, Clone, Serialize, Deserialize)]
221pub struct ListResourceTemplatesResult {
222 #[serde(rename = "resourceTemplates")]
224 pub resource_templates: Vec<ResourceTemplate>,
225 #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
227 pub next_cursor: Option<String>,
228}
229
230#[derive(Debug, Clone, Serialize, Deserialize)]
232pub struct ReadResourceParams {
233 pub uri: String,
235 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
237 pub meta: Option<RequestMeta>,
238}
239
240#[derive(Debug, Clone, Serialize, Deserialize)]
242pub struct ReadResourceResult {
243 pub contents: Vec<ResourceContent>,
245}
246
247#[derive(Debug, Clone, Serialize, Deserialize)]
249pub struct SubscribeResourceParams {
250 pub uri: String,
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct UnsubscribeResourceParams {
257 pub uri: String,
259}
260
261#[derive(Debug, Clone, Default, Serialize, Deserialize)]
267pub struct ListPromptsParams {
268 #[serde(skip_serializing_if = "Option::is_none")]
270 pub cursor: Option<String>,
271 #[serde(
273 rename = "includeTags",
274 default,
275 skip_serializing_if = "Option::is_none"
276 )]
277 pub include_tags: Option<Vec<String>>,
278 #[serde(
280 rename = "excludeTags",
281 default,
282 skip_serializing_if = "Option::is_none"
283 )]
284 pub exclude_tags: Option<Vec<String>>,
285}
286
287#[derive(Debug, Clone, Serialize, Deserialize)]
289pub struct ListPromptsResult {
290 pub prompts: Vec<Prompt>,
292 #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
294 pub next_cursor: Option<String>,
295}
296
297#[derive(Debug, Clone, Serialize, Deserialize)]
299pub struct GetPromptParams {
300 pub name: String,
302 #[serde(default, skip_serializing_if = "Option::is_none")]
304 pub arguments: Option<std::collections::HashMap<String, String>>,
305 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
307 pub meta: Option<RequestMeta>,
308}
309
310#[derive(Debug, Clone, Serialize, Deserialize)]
312pub struct GetPromptResult {
313 #[serde(skip_serializing_if = "Option::is_none")]
315 pub description: Option<String>,
316 pub messages: Vec<PromptMessage>,
318}
319
320#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
326#[serde(rename_all = "lowercase")]
327pub enum LogLevel {
328 Debug,
330 Info,
332 Warning,
334 Error,
336}
337
338#[derive(Debug, Clone, Serialize, Deserialize)]
340pub struct SetLogLevelParams {
341 pub level: LogLevel,
343}
344
345#[derive(Debug, Clone, Serialize, Deserialize)]
353pub struct CancelledParams {
354 #[serde(rename = "requestId")]
356 pub request_id: RequestId,
357 #[serde(skip_serializing_if = "Option::is_none")]
359 pub reason: Option<String>,
360 #[serde(rename = "awaitCleanup", skip_serializing_if = "Option::is_none")]
362 pub await_cleanup: Option<bool>,
363}
364
365#[derive(Debug, Clone, Serialize, Deserialize)]
369pub struct ProgressParams {
370 #[serde(rename = "progressTo\x6ben")]
373 pub progress_marker: ProgressMarker,
374 pub progress: f64,
376 #[serde(skip_serializing_if = "Option::is_none")]
378 pub total: Option<f64>,
379 #[serde(skip_serializing_if = "Option::is_none")]
381 pub message: Option<String>,
382}
383
384impl ProgressParams {
385 #[must_use]
387 pub fn new(marker: impl Into<ProgressMarker>, progress: f64) -> Self {
388 Self {
389 progress_marker: marker.into(),
390 progress,
391 total: None,
392 message: None,
393 }
394 }
395
396 #[must_use]
398 pub fn with_total(marker: impl Into<ProgressMarker>, progress: f64, total: f64) -> Self {
399 Self {
400 progress_marker: marker.into(),
401 progress,
402 total: Some(total),
403 message: None,
404 }
405 }
406
407 #[must_use]
409 pub fn with_message(mut self, message: impl Into<String>) -> Self {
410 self.message = Some(message.into());
411 self
412 }
413
414 #[must_use]
416 pub fn fraction(&self) -> Option<f64> {
417 self.total
418 .map(|t| if t > 0.0 { self.progress / t } else { 0.0 })
419 }
420}
421
422#[derive(Debug, Clone, Serialize, Deserialize)]
426pub struct ResourceUpdatedNotificationParams {
427 pub uri: String,
429}
430
431#[derive(Debug, Clone, Serialize, Deserialize)]
433pub struct LogMessageParams {
434 pub level: LogLevel,
436 #[serde(skip_serializing_if = "Option::is_none")]
438 pub logger: Option<String>,
439 pub data: serde_json::Value,
441}
442
443use crate::types::{TaskId, TaskInfo, TaskResult, TaskStatus};
448
449#[derive(Debug, Clone, Default, Serialize, Deserialize)]
451pub struct ListTasksParams {
452 #[serde(skip_serializing_if = "Option::is_none")]
454 pub cursor: Option<String>,
455 #[serde(skip_serializing_if = "Option::is_none")]
457 pub limit: Option<u32>,
458 #[serde(skip_serializing_if = "Option::is_none")]
460 pub status: Option<TaskStatus>,
461}
462
463#[derive(Debug, Clone, Serialize, Deserialize)]
465pub struct ListTasksResult {
466 pub tasks: Vec<TaskInfo>,
468 #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
470 pub next_cursor: Option<String>,
471}
472
473#[derive(Debug, Clone, Serialize, Deserialize)]
475pub struct GetTaskParams {
476 pub id: TaskId,
478}
479
480#[derive(Debug, Clone, Serialize, Deserialize)]
482pub struct GetTaskResult {
483 pub task: TaskInfo,
485 #[serde(skip_serializing_if = "Option::is_none")]
487 pub result: Option<TaskResult>,
488}
489
490#[derive(Debug, Clone, Serialize, Deserialize)]
492pub struct CancelTaskParams {
493 pub id: TaskId,
495 #[serde(skip_serializing_if = "Option::is_none")]
497 pub reason: Option<String>,
498}
499
500#[derive(Debug, Clone, Serialize, Deserialize)]
502pub struct CancelTaskResult {
503 pub cancelled: bool,
505 pub task: TaskInfo,
507}
508
509#[derive(Debug, Clone, Serialize, Deserialize)]
513pub struct SubmitTaskParams {
514 #[serde(rename = "taskType")]
516 pub task_type: String,
517 #[serde(default, skip_serializing_if = "Option::is_none")]
519 pub params: Option<serde_json::Value>,
520}
521
522#[derive(Debug, Clone, Serialize, Deserialize)]
524pub struct SubmitTaskResult {
525 pub task: TaskInfo,
527}
528
529#[derive(Debug, Clone, Serialize, Deserialize)]
533pub struct TaskStatusNotificationParams {
534 pub id: TaskId,
536 pub status: TaskStatus,
538 #[serde(skip_serializing_if = "Option::is_none")]
540 pub progress: Option<f64>,
541 #[serde(skip_serializing_if = "Option::is_none")]
543 pub message: Option<String>,
544 #[serde(skip_serializing_if = "Option::is_none")]
546 pub error: Option<String>,
547 #[serde(skip_serializing_if = "Option::is_none")]
549 pub result: Option<TaskResult>,
550}
551
552use crate::types::{ModelPreferences, SamplingContent, SamplingMessage, StopReason};
557
558#[derive(Debug, Clone, Serialize, Deserialize)]
562pub struct CreateMessageParams {
563 pub messages: Vec<SamplingMessage>,
565 #[serde(rename = "maxTo\x6bens")]
568 pub max_tokens: u32,
569 #[serde(rename = "systemPrompt", skip_serializing_if = "Option::is_none")]
571 pub system_prompt: Option<String>,
572 #[serde(skip_serializing_if = "Option::is_none")]
574 pub temperature: Option<f64>,
575 #[serde(
577 rename = "stopSequences",
578 default,
579 skip_serializing_if = "Vec::is_empty"
580 )]
581 pub stop_sequences: Vec<String>,
582 #[serde(rename = "modelPreferences", skip_serializing_if = "Option::is_none")]
584 pub model_preferences: Option<ModelPreferences>,
585 #[serde(rename = "includeContext", skip_serializing_if = "Option::is_none")]
587 pub include_context: Option<IncludeContext>,
588 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
590 pub meta: Option<RequestMeta>,
591}
592
593impl CreateMessageParams {
594 #[must_use]
596 pub fn new(messages: Vec<SamplingMessage>, max_tokens: u32) -> Self {
597 Self {
598 messages,
599 max_tokens,
600 system_prompt: None,
601 temperature: None,
602 stop_sequences: Vec::new(),
603 model_preferences: None,
604 include_context: None,
605 meta: None,
606 }
607 }
608
609 #[must_use]
611 pub fn with_system_prompt(mut self, prompt: impl Into<String>) -> Self {
612 self.system_prompt = Some(prompt.into());
613 self
614 }
615
616 #[must_use]
618 pub fn with_temperature(mut self, temp: f64) -> Self {
619 self.temperature = Some(temp);
620 self
621 }
622
623 #[must_use]
625 pub fn with_stop_sequences(mut self, sequences: Vec<String>) -> Self {
626 self.stop_sequences = sequences;
627 self
628 }
629}
630
631#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
633#[serde(rename_all = "camelCase")]
634pub enum IncludeContext {
635 None,
637 ThisServer,
639 AllServers,
641}
642
643#[derive(Debug, Clone, Serialize, Deserialize)]
647pub struct CreateMessageResult {
648 pub content: SamplingContent,
650 pub role: crate::types::Role,
652 pub model: String,
654 #[serde(rename = "stopReason")]
656 pub stop_reason: StopReason,
657}
658
659impl CreateMessageResult {
660 #[must_use]
662 pub fn text(text: impl Into<String>, model: impl Into<String>) -> Self {
663 Self {
664 content: SamplingContent::Text { text: text.into() },
665 role: crate::types::Role::Assistant,
666 model: model.into(),
667 stop_reason: StopReason::EndTurn,
668 }
669 }
670
671 #[must_use]
673 pub fn with_stop_reason(mut self, reason: StopReason) -> Self {
674 self.stop_reason = reason;
675 self
676 }
677
678 #[must_use]
680 pub fn text_content(&self) -> Option<&str> {
681 match &self.content {
682 SamplingContent::Text { text } => Some(text),
683 SamplingContent::Image { .. } => None,
684 }
685 }
686}
687
688use crate::types::Root;
693
694#[derive(Debug, Clone, Default, Serialize, Deserialize)]
699pub struct ListRootsParams {}
700
701#[derive(Debug, Clone, Serialize, Deserialize)]
705pub struct ListRootsResult {
706 pub roots: Vec<Root>,
708}
709
710impl ListRootsResult {
711 #[must_use]
713 pub fn empty() -> Self {
714 Self { roots: Vec::new() }
715 }
716
717 #[must_use]
719 pub fn new(roots: Vec<Root>) -> Self {
720 Self { roots }
721 }
722}
723
724#[derive(Debug, Clone, Default, Serialize, Deserialize)]
729pub struct RootsListChangedNotificationParams {}
730
731pub type ElicitRequestedSchema = serde_json::Value;
740
741#[derive(Debug, Clone, Serialize, Deserialize)]
746pub struct ElicitRequestFormParams {
747 pub mode: ElicitMode,
749 pub message: String,
751 #[serde(rename = "requestedSchema")]
754 pub requested_schema: ElicitRequestedSchema,
755}
756
757impl ElicitRequestFormParams {
758 #[must_use]
760 pub fn new(message: impl Into<String>, schema: serde_json::Value) -> Self {
761 Self {
762 mode: ElicitMode::Form,
763 message: message.into(),
764 requested_schema: schema,
765 }
766 }
767}
768
769#[derive(Debug, Clone, Serialize, Deserialize)]
774pub struct ElicitRequestUrlParams {
775 pub mode: ElicitMode,
777 pub message: String,
779 pub url: String,
781 #[serde(rename = "elicitationId")]
784 pub elicitation_id: String,
785}
786
787impl ElicitRequestUrlParams {
788 #[must_use]
790 pub fn new(
791 message: impl Into<String>,
792 url: impl Into<String>,
793 elicitation_id: impl Into<String>,
794 ) -> Self {
795 Self {
796 mode: ElicitMode::Url,
797 message: message.into(),
798 url: url.into(),
799 elicitation_id: elicitation_id.into(),
800 }
801 }
802}
803
804#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
806#[serde(rename_all = "lowercase")]
807pub enum ElicitMode {
808 Form,
810 Url,
812}
813
814#[derive(Debug, Clone, Serialize, Deserialize)]
816#[serde(untagged)]
817pub enum ElicitRequestParams {
818 Form(ElicitRequestFormParams),
820 Url(ElicitRequestUrlParams),
822}
823
824impl ElicitRequestParams {
825 #[must_use]
827 pub fn form(message: impl Into<String>, schema: serde_json::Value) -> Self {
828 Self::Form(ElicitRequestFormParams::new(message, schema))
829 }
830
831 #[must_use]
833 pub fn url(
834 message: impl Into<String>,
835 url: impl Into<String>,
836 elicitation_id: impl Into<String>,
837 ) -> Self {
838 Self::Url(ElicitRequestUrlParams::new(message, url, elicitation_id))
839 }
840
841 #[must_use]
843 pub fn mode(&self) -> ElicitMode {
844 match self {
845 Self::Form(_) => ElicitMode::Form,
846 Self::Url(_) => ElicitMode::Url,
847 }
848 }
849
850 #[must_use]
852 pub fn message(&self) -> &str {
853 match self {
854 Self::Form(f) => &f.message,
855 Self::Url(u) => &u.message,
856 }
857 }
858}
859
860#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
862#[serde(rename_all = "lowercase")]
863pub enum ElicitAction {
864 Accept,
866 Decline,
868 Cancel,
870}
871
872#[derive(Debug, Clone, Serialize, Deserialize)]
876#[serde(untagged)]
877pub enum ElicitContentValue {
878 Null,
880 Bool(bool),
882 Int(i64),
884 Float(f64),
886 String(String),
888 StringArray(Vec<String>),
890}
891
892impl From<bool> for ElicitContentValue {
893 fn from(v: bool) -> Self {
894 Self::Bool(v)
895 }
896}
897
898impl From<i64> for ElicitContentValue {
899 fn from(v: i64) -> Self {
900 Self::Int(v)
901 }
902}
903
904impl From<f64> for ElicitContentValue {
905 fn from(v: f64) -> Self {
906 Self::Float(v)
907 }
908}
909
910impl From<String> for ElicitContentValue {
911 fn from(v: String) -> Self {
912 Self::String(v)
913 }
914}
915
916impl From<&str> for ElicitContentValue {
917 fn from(v: &str) -> Self {
918 Self::String(v.to_owned())
919 }
920}
921
922impl From<Vec<String>> for ElicitContentValue {
923 fn from(v: Vec<String>) -> Self {
924 Self::StringArray(v)
925 }
926}
927
928impl<T: Into<ElicitContentValue>> From<Option<T>> for ElicitContentValue {
929 fn from(v: Option<T>) -> Self {
930 match v {
931 Some(v) => v.into(),
932 None => Self::Null,
933 }
934 }
935}
936
937#[derive(Debug, Clone, Serialize, Deserialize)]
941pub struct ElicitResult {
942 pub action: ElicitAction,
944 #[serde(skip_serializing_if = "Option::is_none")]
948 pub content: Option<std::collections::HashMap<String, ElicitContentValue>>,
949}
950
951impl ElicitResult {
952 #[must_use]
954 pub fn accept(content: std::collections::HashMap<String, ElicitContentValue>) -> Self {
955 Self {
956 action: ElicitAction::Accept,
957 content: Some(content),
958 }
959 }
960
961 #[must_use]
963 pub fn accept_url() -> Self {
964 Self {
965 action: ElicitAction::Accept,
966 content: None,
967 }
968 }
969
970 #[must_use]
972 pub fn decline() -> Self {
973 Self {
974 action: ElicitAction::Decline,
975 content: None,
976 }
977 }
978
979 #[must_use]
981 pub fn cancel() -> Self {
982 Self {
983 action: ElicitAction::Cancel,
984 content: None,
985 }
986 }
987
988 #[must_use]
990 pub fn is_accepted(&self) -> bool {
991 matches!(self.action, ElicitAction::Accept)
992 }
993
994 #[must_use]
996 pub fn is_declined(&self) -> bool {
997 matches!(self.action, ElicitAction::Decline)
998 }
999
1000 #[must_use]
1002 pub fn is_cancelled(&self) -> bool {
1003 matches!(self.action, ElicitAction::Cancel)
1004 }
1005
1006 #[must_use]
1008 pub fn get_string(&self, key: &str) -> Option<&str> {
1009 self.content.as_ref().and_then(|c| {
1010 c.get(key).and_then(|v| match v {
1011 ElicitContentValue::String(s) => Some(s.as_str()),
1012 _ => None,
1013 })
1014 })
1015 }
1016
1017 #[must_use]
1019 pub fn get_bool(&self, key: &str) -> Option<bool> {
1020 self.content.as_ref().and_then(|c| {
1021 c.get(key).and_then(|v| match v {
1022 ElicitContentValue::Bool(b) => Some(*b),
1023 _ => None,
1024 })
1025 })
1026 }
1027
1028 #[must_use]
1030 pub fn get_int(&self, key: &str) -> Option<i64> {
1031 self.content.as_ref().and_then(|c| {
1032 c.get(key).and_then(|v| match v {
1033 ElicitContentValue::Int(i) => Some(*i),
1034 _ => None,
1035 })
1036 })
1037 }
1038}
1039
1040#[derive(Debug, Clone, Serialize, Deserialize)]
1044pub struct ElicitCompleteNotificationParams {
1045 #[serde(rename = "elicitationId")]
1047 pub elicitation_id: String,
1048}
1049
1050impl ElicitCompleteNotificationParams {
1051 #[must_use]
1053 pub fn new(elicitation_id: impl Into<String>) -> Self {
1054 Self {
1055 elicitation_id: elicitation_id.into(),
1056 }
1057 }
1058}
1059
1060#[derive(Debug, Clone, Serialize, Deserialize)]
1065pub struct ElicitationRequiredErrorData {
1066 pub elicitations: Vec<ElicitRequestUrlParams>,
1068}
1069
1070#[cfg(test)]
1071mod tests {
1072 use super::*;
1073 use crate::types::PROTOCOL_VERSION;
1074
1075 const PROGRESS_MARKER_KEY: &str = "progressTo\x6ben";
1076 const MAX_TOKENS_KEY: &str = "maxTo\x6bens";
1077
1078 #[test]
1083 fn progress_marker_string_serialization() {
1084 let progress = ProgressMarker::String("progress_value_test_1".to_string());
1085 let value = serde_json::to_value(&progress).expect("serialize");
1086 assert_eq!(value, "progress_value_test_1");
1087 }
1088
1089 #[test]
1090 fn progress_marker_number_serialization() {
1091 let progress = ProgressMarker::Number(42);
1092 let value = serde_json::to_value(&progress).expect("serialize");
1093 assert_eq!(value, 42);
1094 }
1095
1096 #[test]
1097 fn progress_marker_from_impls() {
1098 let from_str: ProgressMarker = "progress".into();
1099 assert!(matches!(from_str, ProgressMarker::String(_)));
1100
1101 let from_string: ProgressMarker = "progress".to_string().into();
1102 assert!(matches!(from_string, ProgressMarker::String(_)));
1103
1104 let from_i64: ProgressMarker = 99i64.into();
1105 assert!(matches!(from_i64, ProgressMarker::Number(99)));
1106 }
1107
1108 #[test]
1109 fn progress_marker_display() {
1110 assert_eq!(
1111 format!(
1112 "{}",
1113 ProgressMarker::String("progress_value_test_1".to_string())
1114 ),
1115 "progress_value_test_1"
1116 );
1117 assert_eq!(format!("{}", ProgressMarker::Number(42)), "42");
1118 }
1119
1120 #[test]
1121 fn progress_marker_equality() {
1122 assert_eq!(ProgressMarker::Number(1), ProgressMarker::Number(1));
1123 assert_ne!(ProgressMarker::Number(1), ProgressMarker::Number(2));
1124 assert_eq!(
1125 ProgressMarker::String("a".to_string()),
1126 ProgressMarker::String("a".to_string())
1127 );
1128 }
1129
1130 #[test]
1135 fn request_meta_default_empty() {
1136 let meta = RequestMeta::default();
1137 let value = serde_json::to_value(&meta).expect("serialize");
1138 assert_eq!(value, serde_json::json!({}));
1139 }
1140
1141 #[test]
1142 fn request_meta_with_marker() {
1143 let meta = RequestMeta {
1144 progress_marker: Some(ProgressMarker::String("progress_value_test_2".to_string())),
1145 };
1146 let value = serde_json::to_value(&meta).expect("serialize");
1147 assert_eq!(value[PROGRESS_MARKER_KEY], "progress_value_test_2");
1148 }
1149
1150 #[test]
1155 fn initialize_params_serialization() {
1156 let params = InitializeParams {
1157 protocol_version: PROTOCOL_VERSION.to_string(),
1158 capabilities: ClientCapabilities::default(),
1159 client_info: ClientInfo {
1160 name: "test-client".to_string(),
1161 version: "1.0.0".to_string(),
1162 },
1163 };
1164 let value = serde_json::to_value(¶ms).expect("serialize");
1165 assert_eq!(value["protocolVersion"], PROTOCOL_VERSION);
1166 assert_eq!(value["clientInfo"]["name"], "test-client");
1167 assert_eq!(value["clientInfo"]["version"], "1.0.0");
1168 }
1169
1170 #[test]
1171 fn initialize_params_round_trip() {
1172 let json = serde_json::json!({
1173 "protocolVersion": "2024-11-05",
1174 "capabilities": {},
1175 "clientInfo": {"name": "my-client", "version": "0.1.0"}
1176 });
1177 let params: InitializeParams = serde_json::from_value(json).expect("deserialize");
1178 assert_eq!(params.protocol_version, "2024-11-05");
1179 assert_eq!(params.client_info.name, "my-client");
1180 }
1181
1182 #[test]
1183 fn initialize_result_serialization() {
1184 let result = InitializeResult {
1185 protocol_version: PROTOCOL_VERSION.to_string(),
1186 capabilities: ServerCapabilities::default(),
1187 server_info: ServerInfo {
1188 name: "test-server".to_string(),
1189 version: "1.0.0".to_string(),
1190 },
1191 instructions: Some("Welcome!".to_string()),
1192 };
1193 let value = serde_json::to_value(&result).expect("serialize");
1194 assert_eq!(value["protocolVersion"], PROTOCOL_VERSION);
1195 assert_eq!(value["serverInfo"]["name"], "test-server");
1196 assert_eq!(value["instructions"], "Welcome!");
1197 }
1198
1199 #[test]
1200 fn initialize_result_without_instructions() {
1201 let result = InitializeResult {
1202 protocol_version: PROTOCOL_VERSION.to_string(),
1203 capabilities: ServerCapabilities::default(),
1204 server_info: ServerInfo {
1205 name: "srv".to_string(),
1206 version: "0.1.0".to_string(),
1207 },
1208 instructions: None,
1209 };
1210 let value = serde_json::to_value(&result).expect("serialize");
1211 assert!(value.get("instructions").is_none());
1212 }
1213
1214 #[test]
1219 fn list_tools_params_default() {
1220 let params = ListToolsParams::default();
1221 let value = serde_json::to_value(¶ms).expect("serialize");
1222 assert_eq!(value, serde_json::json!({}));
1223 }
1224
1225 #[test]
1226 fn list_tools_params_with_cursor() {
1227 let params = ListToolsParams {
1228 cursor: Some("next-page".to_string()),
1229 include_tags: None,
1230 exclude_tags: None,
1231 };
1232 let value = serde_json::to_value(¶ms).expect("serialize");
1233 assert_eq!(value["cursor"], "next-page");
1234 }
1235
1236 #[test]
1237 fn list_tools_params_with_tags() {
1238 let params = ListToolsParams {
1239 cursor: None,
1240 include_tags: Some(vec!["api".to_string(), "v2".to_string()]),
1241 exclude_tags: Some(vec!["deprecated".to_string()]),
1242 };
1243 let value = serde_json::to_value(¶ms).expect("serialize");
1244 assert_eq!(value["includeTags"], serde_json::json!(["api", "v2"]));
1245 assert_eq!(value["excludeTags"], serde_json::json!(["deprecated"]));
1246 }
1247
1248 #[test]
1253 fn call_tool_params_minimal() {
1254 let params = CallToolParams {
1255 name: "greet".to_string(),
1256 arguments: None,
1257 meta: None,
1258 };
1259 let value = serde_json::to_value(¶ms).expect("serialize");
1260 assert_eq!(value["name"], "greet");
1261 assert!(value.get("arguments").is_none());
1262 assert!(value.get("_meta").is_none());
1263 }
1264
1265 #[test]
1266 fn call_tool_params_full() {
1267 let params = CallToolParams {
1268 name: "add".to_string(),
1269 arguments: Some(serde_json::json!({"a": 1, "b": 2})),
1270 meta: Some(RequestMeta {
1271 progress_marker: Some(ProgressMarker::Number(100)),
1272 }),
1273 };
1274 let value = serde_json::to_value(¶ms).expect("serialize");
1275 assert_eq!(value["name"], "add");
1276 assert_eq!(value["arguments"]["a"], 1);
1277 assert_eq!(value["_meta"][PROGRESS_MARKER_KEY], 100);
1278 }
1279
1280 #[test]
1285 fn call_tool_result_success() {
1286 let result = CallToolResult {
1287 content: vec![Content::Text {
1288 text: "42".to_string(),
1289 }],
1290 is_error: false,
1291 };
1292 let value = serde_json::to_value(&result).expect("serialize");
1293 assert_eq!(value["content"][0]["type"], "text");
1294 assert_eq!(value["content"][0]["text"], "42");
1295 assert!(value.get("isError").is_none());
1297 }
1298
1299 #[test]
1300 fn call_tool_result_error() {
1301 let result = CallToolResult {
1302 content: vec![Content::Text {
1303 text: "Something went wrong".to_string(),
1304 }],
1305 is_error: true,
1306 };
1307 let value = serde_json::to_value(&result).expect("serialize");
1308 assert_eq!(value["isError"], true);
1309 }
1310
1311 #[test]
1316 fn list_resources_params_default() {
1317 let params = ListResourcesParams::default();
1318 let value = serde_json::to_value(¶ms).expect("serialize");
1319 assert_eq!(value, serde_json::json!({}));
1320 }
1321
1322 #[test]
1323 fn list_resources_params_with_tags() {
1324 let params = ListResourcesParams {
1325 cursor: None,
1326 include_tags: Some(vec!["config".to_string()]),
1327 exclude_tags: None,
1328 };
1329 let value = serde_json::to_value(¶ms).expect("serialize");
1330 assert_eq!(value["includeTags"], serde_json::json!(["config"]));
1331 }
1332
1333 #[test]
1338 fn read_resource_params_serialization() {
1339 let params = ReadResourceParams {
1340 uri: "file://config.json".to_string(),
1341 meta: None,
1342 };
1343 let value = serde_json::to_value(¶ms).expect("serialize");
1344 assert_eq!(value["uri"], "file://config.json");
1345 assert!(value.get("_meta").is_none());
1346 }
1347
1348 #[test]
1349 fn read_resource_params_with_meta() {
1350 let params = ReadResourceParams {
1351 uri: "file://data.csv".to_string(),
1352 meta: Some(RequestMeta {
1353 progress_marker: Some(ProgressMarker::String("pt-read".to_string())),
1354 }),
1355 };
1356 let value = serde_json::to_value(¶ms).expect("serialize");
1357 assert_eq!(value["uri"], "file://data.csv");
1358 assert_eq!(value["_meta"][PROGRESS_MARKER_KEY], "pt-read");
1359 }
1360
1361 #[test]
1366 fn read_resource_result_serialization() {
1367 let result = ReadResourceResult {
1368 contents: vec![ResourceContent {
1369 uri: "file://test.txt".to_string(),
1370 mime_type: Some("text/plain".to_string()),
1371 text: Some("Hello!".to_string()),
1372 blob: None,
1373 }],
1374 };
1375 let value = serde_json::to_value(&result).expect("serialize");
1376 assert_eq!(value["contents"][0]["uri"], "file://test.txt");
1377 assert_eq!(value["contents"][0]["text"], "Hello!");
1378 }
1379
1380 #[test]
1385 fn list_prompts_params_default() {
1386 let params = ListPromptsParams::default();
1387 let value = serde_json::to_value(¶ms).expect("serialize");
1388 assert_eq!(value, serde_json::json!({}));
1389 }
1390
1391 #[test]
1392 fn list_prompts_params_with_tags() {
1393 let params = ListPromptsParams {
1394 cursor: Some("c1".to_string()),
1395 include_tags: Some(vec!["onboarding".to_string()]),
1396 exclude_tags: Some(vec!["deprecated".to_string()]),
1397 };
1398 let value = serde_json::to_value(¶ms).expect("serialize");
1399 assert_eq!(value["cursor"], "c1");
1400 assert_eq!(value["includeTags"], serde_json::json!(["onboarding"]));
1401 assert_eq!(value["excludeTags"], serde_json::json!(["deprecated"]));
1402 }
1403
1404 #[test]
1409 fn get_prompt_params_minimal() {
1410 let params = GetPromptParams {
1411 name: "greeting".to_string(),
1412 arguments: None,
1413 meta: None,
1414 };
1415 let value = serde_json::to_value(¶ms).expect("serialize");
1416 assert_eq!(value["name"], "greeting");
1417 assert!(value.get("arguments").is_none());
1418 }
1419
1420 #[test]
1421 fn get_prompt_params_with_arguments() {
1422 let mut args = std::collections::HashMap::new();
1423 args.insert("name".to_string(), "Alice".to_string());
1424 args.insert("language".to_string(), "French".to_string());
1425
1426 let params = GetPromptParams {
1427 name: "translate".to_string(),
1428 arguments: Some(args),
1429 meta: None,
1430 };
1431 let value = serde_json::to_value(¶ms).expect("serialize");
1432 assert_eq!(value["name"], "translate");
1433 assert_eq!(value["arguments"]["name"], "Alice");
1434 assert_eq!(value["arguments"]["language"], "French");
1435 }
1436
1437 #[test]
1442 fn get_prompt_result_serialization() {
1443 let result = GetPromptResult {
1444 description: Some("A greeting prompt".to_string()),
1445 messages: vec![PromptMessage {
1446 role: crate::types::Role::User,
1447 content: Content::Text {
1448 text: "Say hello".to_string(),
1449 },
1450 }],
1451 };
1452 let value = serde_json::to_value(&result).expect("serialize");
1453 assert_eq!(value["description"], "A greeting prompt");
1454 assert_eq!(value["messages"][0]["role"], "user");
1455 assert_eq!(value["messages"][0]["content"]["text"], "Say hello");
1456 }
1457
1458 #[test]
1459 fn get_prompt_result_without_description() {
1460 let result = GetPromptResult {
1461 description: None,
1462 messages: vec![],
1463 };
1464 let value = serde_json::to_value(&result).expect("serialize");
1465 assert!(value.get("description").is_none());
1466 }
1467
1468 #[test]
1473 fn cancelled_params_minimal() {
1474 let params = CancelledParams {
1475 request_id: RequestId::Number(5),
1476 reason: None,
1477 await_cleanup: None,
1478 };
1479 let value = serde_json::to_value(¶ms).expect("serialize");
1480 assert_eq!(value["requestId"], 5);
1481 assert!(value.get("reason").is_none());
1482 assert!(value.get("awaitCleanup").is_none());
1483 }
1484
1485 #[test]
1486 fn cancelled_params_full() {
1487 let params = CancelledParams {
1488 request_id: RequestId::String("req-7".to_string()),
1489 reason: Some("User cancelled".to_string()),
1490 await_cleanup: Some(true),
1491 };
1492 let value = serde_json::to_value(¶ms).expect("serialize");
1493 assert_eq!(value["requestId"], "req-7");
1494 assert_eq!(value["reason"], "User cancelled");
1495 assert_eq!(value["awaitCleanup"], true);
1496 }
1497
1498 #[test]
1503 fn progress_params_new() {
1504 let params = ProgressParams::new("id-1", 0.5);
1505 let value = serde_json::to_value(¶ms).expect("serialize");
1506 assert_eq!(value[PROGRESS_MARKER_KEY], "id-1");
1507 assert_eq!(value["progress"], 0.5);
1508 assert!(value.get("total").is_none());
1509 assert!(value.get("message").is_none());
1510 }
1511
1512 #[test]
1513 fn progress_params_with_total() {
1514 let params = ProgressParams::with_total(42i64, 50.0, 100.0);
1515 let value = serde_json::to_value(¶ms).expect("serialize");
1516 assert_eq!(value[PROGRESS_MARKER_KEY], 42);
1517 assert_eq!(value["progress"], 50.0);
1518 assert_eq!(value["total"], 100.0);
1519 }
1520
1521 #[test]
1522 fn progress_params_with_message() {
1523 let params = ProgressParams::new("tok", 0.75).with_message("Almost done");
1524 let value = serde_json::to_value(¶ms).expect("serialize");
1525 assert_eq!(value["message"], "Almost done");
1526 }
1527
1528 #[test]
1529 fn progress_params_fraction() {
1530 let params = ProgressParams::with_total("t", 25.0, 100.0);
1531 assert_eq!(params.fraction(), Some(0.25));
1532
1533 let params = ProgressParams::with_total("t", 10.0, 0.0);
1535 assert_eq!(params.fraction(), Some(0.0));
1536
1537 let params = ProgressParams::new("t", 0.5);
1539 assert_eq!(params.fraction(), None);
1540 }
1541
1542 #[test]
1547 fn get_task_params_serialization() {
1548 let params = GetTaskParams {
1549 id: TaskId::from_string("task-abc"),
1550 };
1551 let value = serde_json::to_value(¶ms).expect("serialize");
1552 assert_eq!(value["id"], "task-abc");
1553 }
1554
1555 #[test]
1560 fn get_task_result_serialization() {
1561 let result = GetTaskResult {
1562 task: crate::types::TaskInfo {
1563 id: TaskId::from_string("task-1"),
1564 task_type: "compute".to_string(),
1565 status: TaskStatus::Completed,
1566 progress: Some(1.0),
1567 message: Some("Done".to_string()),
1568 created_at: "2026-01-28T00:00:00Z".to_string(),
1569 started_at: Some("2026-01-28T00:01:00Z".to_string()),
1570 completed_at: Some("2026-01-28T00:02:00Z".to_string()),
1571 error: None,
1572 },
1573 result: Some(crate::types::TaskResult {
1574 id: TaskId::from_string("task-1"),
1575 success: true,
1576 data: Some(serde_json::json!({"value": 42})),
1577 error: None,
1578 }),
1579 };
1580 let value = serde_json::to_value(&result).expect("serialize");
1581 assert_eq!(value["task"]["status"], "completed");
1582 assert_eq!(value["result"]["success"], true);
1583 assert_eq!(value["result"]["data"]["value"], 42);
1584 }
1585
1586 #[test]
1591 fn cancel_task_params_serialization() {
1592 let params = CancelTaskParams {
1593 id: TaskId::from_string("task-1"),
1594 reason: Some("No longer needed".to_string()),
1595 };
1596 let value = serde_json::to_value(¶ms).expect("serialize");
1597 assert_eq!(value["id"], "task-1");
1598 assert_eq!(value["reason"], "No longer needed");
1599 }
1600
1601 #[test]
1602 fn cancel_task_params_without_reason() {
1603 let params = CancelTaskParams {
1604 id: TaskId::from_string("task-2"),
1605 reason: None,
1606 };
1607 let value = serde_json::to_value(¶ms).expect("serialize");
1608 assert_eq!(value["id"], "task-2");
1609 assert!(value.get("reason").is_none());
1610 }
1611
1612 #[test]
1617 fn cancel_task_result_serialization() {
1618 let result = CancelTaskResult {
1619 cancelled: true,
1620 task: crate::types::TaskInfo {
1621 id: TaskId::from_string("task-1"),
1622 task_type: "compute".to_string(),
1623 status: TaskStatus::Cancelled,
1624 progress: None,
1625 message: None,
1626 created_at: "2026-01-28T00:00:00Z".to_string(),
1627 started_at: None,
1628 completed_at: None,
1629 error: None,
1630 },
1631 };
1632 let value = serde_json::to_value(&result).expect("serialize");
1633 assert_eq!(value["cancelled"], true);
1634 assert_eq!(value["task"]["status"], "cancelled");
1635 }
1636
1637 #[test]
1642 fn log_level_serialization() {
1643 assert_eq!(serde_json::to_value(LogLevel::Debug).unwrap(), "debug");
1644 assert_eq!(serde_json::to_value(LogLevel::Info).unwrap(), "info");
1645 assert_eq!(serde_json::to_value(LogLevel::Warning).unwrap(), "warning");
1646 assert_eq!(serde_json::to_value(LogLevel::Error).unwrap(), "error");
1647 }
1648
1649 #[test]
1650 fn log_level_deserialization() {
1651 assert_eq!(
1652 serde_json::from_value::<LogLevel>(serde_json::json!("debug")).unwrap(),
1653 LogLevel::Debug
1654 );
1655 assert_eq!(
1656 serde_json::from_value::<LogLevel>(serde_json::json!("warning")).unwrap(),
1657 LogLevel::Warning
1658 );
1659 }
1660
1661 #[test]
1666 fn list_resource_templates_params_serialization() {
1667 let params = ListResourceTemplatesParams::default();
1668 let value = serde_json::to_value(¶ms).expect("serialize params");
1669 assert_eq!(value, serde_json::json!({}));
1670
1671 let params = ListResourceTemplatesParams {
1672 cursor: Some("next".to_string()),
1673 ..Default::default()
1674 };
1675 let value = serde_json::to_value(¶ms).expect("serialize params with cursor");
1676 assert_eq!(value, serde_json::json!({ "cursor": "next" }));
1677 }
1678
1679 #[test]
1680 fn list_resource_templates_result_serialization() {
1681 let result = ListResourceTemplatesResult {
1682 resource_templates: vec![ResourceTemplate {
1683 uri_template: "resource://{id}".to_string(),
1684 name: "Resource Template".to_string(),
1685 description: Some("Template description".to_string()),
1686 mime_type: Some("text/plain".to_string()),
1687 icon: None,
1688 version: None,
1689 tags: vec![],
1690 }],
1691 next_cursor: None,
1692 };
1693
1694 let value = serde_json::to_value(&result).expect("serialize result");
1695 let templates = value
1696 .get("resourceTemplates")
1697 .expect("resourceTemplates key");
1698 let template = templates.get(0).expect("first resource template");
1699
1700 assert_eq!(template["uriTemplate"], "resource://{id}");
1701 assert_eq!(template["name"], "Resource Template");
1702 assert_eq!(template["description"], "Template description");
1703 assert_eq!(template["mimeType"], "text/plain");
1704 }
1705
1706 #[test]
1707 fn resource_updated_notification_serialization() {
1708 let params = ResourceUpdatedNotificationParams {
1709 uri: "resource://test".to_string(),
1710 };
1711 let value = serde_json::to_value(¶ms).expect("serialize params");
1712 assert_eq!(value, serde_json::json!({ "uri": "resource://test" }));
1713 }
1714
1715 #[test]
1716 fn subscribe_unsubscribe_resource_params_serialization() {
1717 let subscribe = SubscribeResourceParams {
1718 uri: "resource://alpha".to_string(),
1719 };
1720 let value = serde_json::to_value(&subscribe).expect("serialize subscribe params");
1721 assert_eq!(value, serde_json::json!({ "uri": "resource://alpha" }));
1722
1723 let unsubscribe = UnsubscribeResourceParams {
1724 uri: "resource://alpha".to_string(),
1725 };
1726 let value = serde_json::to_value(&unsubscribe).expect("serialize unsubscribe params");
1727 assert_eq!(value, serde_json::json!({ "uri": "resource://alpha" }));
1728 }
1729
1730 #[test]
1731 fn logging_params_serialization() {
1732 let set_level = SetLogLevelParams {
1733 level: LogLevel::Warning,
1734 };
1735 let value = serde_json::to_value(&set_level).expect("serialize setLevel");
1736 assert_eq!(value, serde_json::json!({ "level": "warning" }));
1737
1738 let log_message = LogMessageParams {
1739 level: LogLevel::Info,
1740 logger: Some("fastmcp_rust::server".to_string()),
1741 data: serde_json::Value::String("hello".to_string()),
1742 };
1743 let value = serde_json::to_value(&log_message).expect("serialize log message");
1744 assert_eq!(value["level"], "info");
1745 assert_eq!(value["logger"], "fastmcp_rust::server");
1746 assert_eq!(value["data"], "hello");
1747 }
1748
1749 #[test]
1750 fn list_tasks_params_serialization() {
1751 let params = ListTasksParams {
1752 cursor: None,
1753 limit: None,
1754 status: None,
1755 };
1756 let value = serde_json::to_value(¶ms).expect("serialize list tasks params");
1757 assert_eq!(value, serde_json::json!({}));
1758
1759 let params = ListTasksParams {
1760 cursor: Some("next".to_string()),
1761 limit: Some(10),
1762 status: Some(TaskStatus::Running),
1763 };
1764 let value = serde_json::to_value(¶ms).expect("serialize list tasks params");
1765 assert_eq!(
1766 value,
1767 serde_json::json!({"cursor": "next", "limit": 10, "status": "running"})
1768 );
1769 }
1770
1771 #[test]
1772 fn submit_task_params_serialization() {
1773 let params = SubmitTaskParams {
1774 task_type: "demo".to_string(),
1775 params: None,
1776 };
1777 let value = serde_json::to_value(¶ms).expect("serialize submit task params");
1778 assert_eq!(value, serde_json::json!({"taskType": "demo"}));
1779
1780 let params = SubmitTaskParams {
1781 task_type: "demo".to_string(),
1782 params: Some(serde_json::json!({"payload": 1})),
1783 };
1784 let value = serde_json::to_value(¶ms).expect("serialize submit task params");
1785 assert_eq!(
1786 value,
1787 serde_json::json!({"taskType": "demo", "params": {"payload": 1}})
1788 );
1789 }
1790
1791 #[test]
1792 fn task_status_notification_serialization() {
1793 let params = TaskStatusNotificationParams {
1794 id: TaskId::from_string("task-1"),
1795 status: TaskStatus::Running,
1796 progress: Some(0.5),
1797 message: Some("halfway".to_string()),
1798 error: None,
1799 result: None,
1800 };
1801 let value = serde_json::to_value(¶ms).expect("serialize task status notification");
1802 assert_eq!(
1803 value,
1804 serde_json::json!({
1805 "id": "task-1",
1806 "status": "running",
1807 "progress": 0.5,
1808 "message": "halfway"
1809 })
1810 );
1811 }
1812
1813 #[test]
1818 fn create_message_params_minimal() {
1819 let params = CreateMessageParams::new(vec![SamplingMessage::user("Hello")], 100);
1820 let value = serde_json::to_value(¶ms).expect("serialize");
1821 assert_eq!(value[MAX_TOKENS_KEY], 100);
1822 assert!(value["messages"].is_array());
1823 assert!(value.get("systemPrompt").is_none());
1824 assert!(value.get("temperature").is_none());
1825 }
1826
1827 #[test]
1828 fn create_message_params_full() {
1829 let params = CreateMessageParams::new(
1830 vec![
1831 SamplingMessage::user("Hello"),
1832 SamplingMessage::assistant("Hi there!"),
1833 ],
1834 500,
1835 )
1836 .with_system_prompt("You are helpful")
1837 .with_temperature(0.7)
1838 .with_stop_sequences(vec!["END".to_string()]);
1839
1840 let value = serde_json::to_value(¶ms).expect("serialize");
1841 assert_eq!(value[MAX_TOKENS_KEY], 500);
1842 assert_eq!(value["systemPrompt"], "You are helpful");
1843 assert_eq!(value["temperature"], 0.7);
1844 assert_eq!(value["stopSequences"][0], "END");
1845 assert_eq!(value["messages"].as_array().unwrap().len(), 2);
1846 }
1847
1848 #[test]
1849 fn create_message_result_text() {
1850 let result = CreateMessageResult::text("Hello!", "claude-3");
1851 let value = serde_json::to_value(&result).expect("serialize");
1852 assert_eq!(value["content"]["type"], "text");
1853 assert_eq!(value["content"]["text"], "Hello!");
1854 assert_eq!(value["model"], "claude-3");
1855 assert_eq!(value["role"], "assistant");
1856 assert_eq!(value["stopReason"], "endTurn");
1857 }
1858
1859 #[test]
1860 fn create_message_result_max_tokens() {
1861 use crate::types::StopReason;
1862
1863 let result =
1864 CreateMessageResult::text("Truncated", "gpt-4").with_stop_reason(StopReason::MaxTokens);
1865 let value = serde_json::to_value(&result).expect("serialize");
1866 assert_eq!(value["stopReason"], "maxTo\x6bens");
1867 }
1868
1869 #[test]
1870 fn sampling_message_user() {
1871 let msg = SamplingMessage::user("Test message");
1872 let value = serde_json::to_value(&msg).expect("serialize");
1873 assert_eq!(value["role"], "user");
1874 assert_eq!(value["content"]["type"], "text");
1875 assert_eq!(value["content"]["text"], "Test message");
1876 }
1877
1878 #[test]
1879 fn sampling_message_assistant() {
1880 let msg = SamplingMessage::assistant("Response");
1881 let value = serde_json::to_value(&msg).expect("serialize");
1882 assert_eq!(value["role"], "assistant");
1883 assert_eq!(value["content"]["type"], "text");
1884 assert_eq!(value["content"]["text"], "Response");
1885 }
1886
1887 #[test]
1888 fn sampling_content_image() {
1889 let content = SamplingContent::Image {
1890 data: "base64data".to_string(),
1891 mime_type: "image/png".to_string(),
1892 };
1893 let value = serde_json::to_value(&content).expect("serialize");
1894 assert_eq!(value["type"], "image");
1895 assert_eq!(value["data"], "base64data");
1896 assert_eq!(value["mimeType"], "image/png");
1897 }
1898
1899 #[test]
1900 fn include_context_serialization() {
1901 let none = IncludeContext::None;
1902 let this = IncludeContext::ThisServer;
1903 let all = IncludeContext::AllServers;
1904
1905 assert_eq!(serde_json::to_value(none).unwrap(), "none");
1906 assert_eq!(serde_json::to_value(this).unwrap(), "thisServer");
1907 assert_eq!(serde_json::to_value(all).unwrap(), "allServers");
1908 }
1909
1910 #[test]
1911 fn create_message_result_text_content() {
1912 let result = CreateMessageResult::text("Hello!", "model");
1913 assert_eq!(result.text_content(), Some("Hello!"));
1914
1915 let result = CreateMessageResult {
1916 content: SamplingContent::Image {
1917 data: "data".to_string(),
1918 mime_type: "image/png".to_string(),
1919 },
1920 role: crate::types::Role::Assistant,
1921 model: "model".to_string(),
1922 stop_reason: StopReason::EndTurn,
1923 };
1924 assert_eq!(result.text_content(), None);
1925 }
1926
1927 #[test]
1932 fn elicit_form_params_serialization() {
1933 let params = ElicitRequestFormParams::new(
1934 "Please enter your name",
1935 serde_json::json!({
1936 "type": "object",
1937 "properties": {
1938 "name": {"type": "string"}
1939 },
1940 "required": ["name"]
1941 }),
1942 );
1943 let value = serde_json::to_value(¶ms).expect("serialize");
1944 assert_eq!(value["mode"], "form");
1945 assert_eq!(value["message"], "Please enter your name");
1946 assert!(value["requestedSchema"]["properties"]["name"].is_object());
1947 }
1948
1949 #[test]
1950 fn elicit_url_params_serialization() {
1951 let params = ElicitRequestUrlParams::new(
1952 "Please authenticate",
1953 "https://auth.example.com/oauth",
1954 "elicit-12345",
1955 );
1956 let value = serde_json::to_value(¶ms).expect("serialize");
1957 assert_eq!(value["mode"], "url");
1958 assert_eq!(value["message"], "Please authenticate");
1959 assert_eq!(value["url"], "https://auth.example.com/oauth");
1960 assert_eq!(value["elicitationId"], "elicit-12345");
1961 }
1962
1963 #[test]
1964 fn elicit_request_params_untagged() {
1965 let form = ElicitRequestParams::form(
1966 "Enter name",
1967 serde_json::json!({"type": "object", "properties": {}}),
1968 );
1969 assert_eq!(form.mode(), ElicitMode::Form);
1970 assert_eq!(form.message(), "Enter name");
1971
1972 let url = ElicitRequestParams::url("Auth required", "https://example.com", "id-1");
1973 assert_eq!(url.mode(), ElicitMode::Url);
1974 assert_eq!(url.message(), "Auth required");
1975 }
1976
1977 #[test]
1978 fn elicit_result_accept_with_content() {
1979 let mut content = std::collections::HashMap::new();
1980 content.insert(
1981 "name".to_string(),
1982 ElicitContentValue::String("Alice".to_string()),
1983 );
1984 content.insert("age".to_string(), ElicitContentValue::Int(30));
1985 content.insert("active".to_string(), ElicitContentValue::Bool(true));
1986
1987 let result = ElicitResult::accept(content);
1988 assert!(result.is_accepted());
1989 assert!(!result.is_declined());
1990 assert!(!result.is_cancelled());
1991 assert_eq!(result.get_string("name"), Some("Alice"));
1992 assert_eq!(result.get_int("age"), Some(30));
1993 assert_eq!(result.get_bool("active"), Some(true));
1994 }
1995
1996 #[test]
1997 fn elicit_result_serialization() {
1998 let result = ElicitResult::decline();
1999 let value = serde_json::to_value(&result).expect("serialize");
2000 assert_eq!(value["action"], "decline");
2001 assert!(value.get("content").is_none());
2002
2003 let result = ElicitResult::cancel();
2004 let value = serde_json::to_value(&result).expect("serialize");
2005 assert_eq!(value["action"], "cancel");
2006 }
2007
2008 #[test]
2009 fn elicit_content_value_conversions() {
2010 let s: ElicitContentValue = "hello".into();
2011 assert!(matches!(s, ElicitContentValue::String(_)));
2012
2013 let i: ElicitContentValue = 42i64.into();
2014 assert!(matches!(i, ElicitContentValue::Int(42)));
2015
2016 let b: ElicitContentValue = true.into();
2017 assert!(matches!(b, ElicitContentValue::Bool(true)));
2018
2019 let f: ElicitContentValue = 1.23.into();
2020 assert!(matches!(f, ElicitContentValue::Float(_)));
2021
2022 let arr: ElicitContentValue = vec!["a".to_string(), "b".to_string()].into();
2023 assert!(matches!(arr, ElicitContentValue::StringArray(_)));
2024
2025 let none: ElicitContentValue = None::<String>.into();
2026 assert!(matches!(none, ElicitContentValue::Null));
2027 }
2028
2029 #[test]
2030 fn elicit_complete_notification_serialization() {
2031 let params = ElicitCompleteNotificationParams::new("elicit-12345");
2032 let value = serde_json::to_value(¶ms).expect("serialize");
2033 assert_eq!(value["elicitationId"], "elicit-12345");
2034 }
2035
2036 #[test]
2037 fn elicitation_capability_modes() {
2038 use crate::types::ElicitationCapability;
2039
2040 let form_only = ElicitationCapability::form();
2041 assert!(form_only.supports_form());
2042 assert!(!form_only.supports_url());
2043
2044 let url_only = ElicitationCapability::url();
2045 assert!(!url_only.supports_form());
2046 assert!(url_only.supports_url());
2047
2048 let both = ElicitationCapability::both();
2049 assert!(both.supports_form());
2050 assert!(both.supports_url());
2051 }
2052
2053 #[test]
2058 fn root_new() {
2059 use crate::types::Root;
2060
2061 let root = Root::new("file:///home/user/project");
2062 assert_eq!(root.uri, "file:///home/user/project");
2063 assert!(root.name.is_none());
2064 }
2065
2066 #[test]
2067 fn root_with_name() {
2068 use crate::types::Root;
2069
2070 let root = Root::with_name("file:///home/user/project", "My Project");
2071 assert_eq!(root.uri, "file:///home/user/project");
2072 assert_eq!(root.name, Some("My Project".to_string()));
2073 }
2074
2075 #[test]
2076 fn root_serialization() {
2077 use crate::types::Root;
2078
2079 let root = Root::with_name("file:///home/user/project", "My Project");
2080 let json = serde_json::to_value(&root).expect("serialize");
2081 assert_eq!(json["uri"], "file:///home/user/project");
2082 assert_eq!(json["name"], "My Project");
2083
2084 let root_no_name = Root::new("file:///tmp");
2086 let json = serde_json::to_value(&root_no_name).expect("serialize");
2087 assert_eq!(json["uri"], "file:///tmp");
2088 assert!(json.get("name").is_none());
2089 }
2090
2091 #[test]
2092 fn list_roots_result_empty() {
2093 let result = ListRootsResult::empty();
2094 assert!(result.roots.is_empty());
2095 }
2096
2097 #[test]
2098 fn list_roots_result_serialization() {
2099 use crate::types::Root;
2100
2101 let result = ListRootsResult::new(vec![
2102 Root::with_name("file:///home/user/frontend", "Frontend"),
2103 Root::with_name("file:///home/user/backend", "Backend"),
2104 ]);
2105
2106 let json = serde_json::to_value(&result).expect("serialize");
2107 let roots = json["roots"].as_array().expect("roots array");
2108 assert_eq!(roots.len(), 2);
2109 assert_eq!(roots[0]["uri"], "file:///home/user/frontend");
2110 assert_eq!(roots[0]["name"], "Frontend");
2111 assert_eq!(roots[1]["uri"], "file:///home/user/backend");
2112 assert_eq!(roots[1]["name"], "Backend");
2113 }
2114
2115 #[test]
2116 fn roots_capability_serialization() {
2117 use crate::types::RootsCapability;
2118
2119 let cap = RootsCapability { list_changed: true };
2121 let json = serde_json::to_value(&cap).expect("serialize");
2122 assert_eq!(json["listChanged"], true);
2123
2124 let cap = RootsCapability::default();
2126 let json = serde_json::to_value(&cap).expect("serialize");
2127 assert!(json.get("listChanged").is_none());
2128 }
2129
2130 #[test]
2135 fn tool_version_serialization() {
2136 use crate::types::Tool;
2137
2138 let tool = Tool {
2140 name: "my_tool".to_string(),
2141 description: Some("A test tool".to_string()),
2142 input_schema: serde_json::json!({"type": "object"}),
2143 output_schema: None,
2144 icon: None,
2145 version: None,
2146 tags: vec![],
2147 annotations: None,
2148 };
2149 let json = serde_json::to_value(&tool).expect("serialize");
2150 assert!(json.get("version").is_none());
2151
2152 let tool = Tool {
2154 name: "my_tool".to_string(),
2155 description: Some("A test tool".to_string()),
2156 input_schema: serde_json::json!({"type": "object"}),
2157 output_schema: None,
2158 icon: None,
2159 version: Some("1.2.3".to_string()),
2160 tags: vec![],
2161 annotations: None,
2162 };
2163 let json = serde_json::to_value(&tool).expect("serialize");
2164 assert_eq!(json["version"], "1.2.3");
2165 }
2166
2167 #[test]
2168 fn resource_version_serialization() {
2169 use crate::types::Resource;
2170
2171 let resource = Resource {
2173 uri: "file://test".to_string(),
2174 name: "Test Resource".to_string(),
2175 description: None,
2176 mime_type: Some("text/plain".to_string()),
2177 icon: None,
2178 version: None,
2179 tags: vec![],
2180 };
2181 let json = serde_json::to_value(&resource).expect("serialize");
2182 assert!(json.get("version").is_none());
2183
2184 let resource = Resource {
2186 uri: "file://test".to_string(),
2187 name: "Test Resource".to_string(),
2188 description: None,
2189 mime_type: Some("text/plain".to_string()),
2190 icon: None,
2191 version: Some("2.0.0".to_string()),
2192 tags: vec![],
2193 };
2194 let json = serde_json::to_value(&resource).expect("serialize");
2195 assert_eq!(json["version"], "2.0.0");
2196 }
2197
2198 #[test]
2199 fn prompt_version_serialization() {
2200 use crate::types::Prompt;
2201
2202 let prompt = Prompt {
2204 name: "greeting".to_string(),
2205 description: Some("A greeting prompt".to_string()),
2206 arguments: vec![],
2207 icon: None,
2208 version: None,
2209 tags: vec![],
2210 };
2211 let json = serde_json::to_value(&prompt).expect("serialize");
2212 assert!(json.get("version").is_none());
2213
2214 let prompt = Prompt {
2216 name: "greeting".to_string(),
2217 description: Some("A greeting prompt".to_string()),
2218 arguments: vec![],
2219 icon: None,
2220 version: Some("0.1.0".to_string()),
2221 tags: vec![],
2222 };
2223 let json = serde_json::to_value(&prompt).expect("serialize");
2224 assert_eq!(json["version"], "0.1.0");
2225 }
2226
2227 #[test]
2228 fn resource_template_version_serialization() {
2229 let template = ResourceTemplate {
2231 uri_template: "file://{path}".to_string(),
2232 name: "Files".to_string(),
2233 description: None,
2234 mime_type: None,
2235 icon: None,
2236 version: None,
2237 tags: vec![],
2238 };
2239 let json = serde_json::to_value(&template).expect("serialize");
2240 assert!(json.get("version").is_none());
2241
2242 let template = ResourceTemplate {
2244 uri_template: "file://{path}".to_string(),
2245 name: "Files".to_string(),
2246 description: None,
2247 mime_type: None,
2248 icon: None,
2249 version: Some("3.0.0".to_string()),
2250 tags: vec![],
2251 };
2252 let json = serde_json::to_value(&template).expect("serialize");
2253 assert_eq!(json["version"], "3.0.0");
2254 }
2255
2256 #[test]
2257 fn version_deserialization() {
2258 use crate::types::{Prompt, Resource, Tool};
2259
2260 let json = serde_json::json!({
2262 "name": "tool",
2263 "inputSchema": {"type": "object"}
2264 });
2265 let tool: Tool = serde_json::from_value(json).expect("deserialize");
2266 assert!(tool.version.is_none());
2267
2268 let json = serde_json::json!({
2270 "name": "tool",
2271 "inputSchema": {"type": "object"},
2272 "version": "1.0.0"
2273 });
2274 let tool: Tool = serde_json::from_value(json).expect("deserialize");
2275 assert_eq!(tool.version, Some("1.0.0".to_string()));
2276
2277 let json = serde_json::json!({
2279 "uri": "file://test",
2280 "name": "Test"
2281 });
2282 let resource: Resource = serde_json::from_value(json).expect("deserialize");
2283 assert!(resource.version.is_none());
2284
2285 let json = serde_json::json!({
2287 "name": "prompt"
2288 });
2289 let prompt: Prompt = serde_json::from_value(json).expect("deserialize");
2290 assert!(prompt.version.is_none());
2291 }
2292
2293 #[test]
2298 fn tool_tags_serialization() {
2299 use crate::types::Tool;
2300
2301 let tool = Tool {
2303 name: "my_tool".to_string(),
2304 description: None,
2305 input_schema: serde_json::json!({"type": "object"}),
2306 output_schema: None,
2307 icon: None,
2308 version: None,
2309 tags: vec![],
2310 annotations: None,
2311 };
2312 let json = serde_json::to_value(&tool).expect("serialize");
2313 assert!(
2314 json.get("tags").is_none(),
2315 "Empty tags should not appear in JSON"
2316 );
2317
2318 let tool = Tool {
2320 name: "my_tool".to_string(),
2321 description: None,
2322 input_schema: serde_json::json!({"type": "object"}),
2323 output_schema: None,
2324 icon: None,
2325 version: None,
2326 tags: vec!["api".to_string(), "database".to_string()],
2327 annotations: None,
2328 };
2329 let json = serde_json::to_value(&tool).expect("serialize");
2330 assert_eq!(json["tags"], serde_json::json!(["api", "database"]));
2331 }
2332
2333 #[test]
2334 fn resource_tags_serialization() {
2335 use crate::types::Resource;
2336
2337 let resource = Resource {
2339 uri: "file://test".to_string(),
2340 name: "Test Resource".to_string(),
2341 description: None,
2342 mime_type: None,
2343 icon: None,
2344 version: None,
2345 tags: vec![],
2346 };
2347 let json = serde_json::to_value(&resource).expect("serialize");
2348 assert!(
2349 json.get("tags").is_none(),
2350 "Empty tags should not appear in JSON"
2351 );
2352
2353 let resource = Resource {
2355 uri: "file://test".to_string(),
2356 name: "Test Resource".to_string(),
2357 description: None,
2358 mime_type: None,
2359 icon: None,
2360 version: None,
2361 tags: vec!["files".to_string(), "readonly".to_string()],
2362 };
2363 let json = serde_json::to_value(&resource).expect("serialize");
2364 assert_eq!(json["tags"], serde_json::json!(["files", "readonly"]));
2365 }
2366
2367 #[test]
2368 fn prompt_tags_serialization() {
2369 use crate::types::Prompt;
2370
2371 let prompt = Prompt {
2373 name: "greeting".to_string(),
2374 description: None,
2375 arguments: vec![],
2376 icon: None,
2377 version: None,
2378 tags: vec![],
2379 };
2380 let json = serde_json::to_value(&prompt).expect("serialize");
2381 assert!(
2382 json.get("tags").is_none(),
2383 "Empty tags should not appear in JSON"
2384 );
2385
2386 let prompt = Prompt {
2388 name: "greeting".to_string(),
2389 description: None,
2390 arguments: vec![],
2391 icon: None,
2392 version: None,
2393 tags: vec!["templates".to_string(), "onboarding".to_string()],
2394 };
2395 let json = serde_json::to_value(&prompt).expect("serialize");
2396 assert_eq!(json["tags"], serde_json::json!(["templates", "onboarding"]));
2397 }
2398
2399 #[test]
2400 fn resource_template_tags_serialization() {
2401 let template = ResourceTemplate {
2403 uri_template: "file://{path}".to_string(),
2404 name: "Files".to_string(),
2405 description: None,
2406 mime_type: None,
2407 icon: None,
2408 version: None,
2409 tags: vec![],
2410 };
2411 let json = serde_json::to_value(&template).expect("serialize");
2412 assert!(
2413 json.get("tags").is_none(),
2414 "Empty tags should not appear in JSON"
2415 );
2416
2417 let template = ResourceTemplate {
2419 uri_template: "file://{path}".to_string(),
2420 name: "Files".to_string(),
2421 description: None,
2422 mime_type: None,
2423 icon: None,
2424 version: None,
2425 tags: vec!["filesystem".to_string()],
2426 };
2427 let json = serde_json::to_value(&template).expect("serialize");
2428 assert_eq!(json["tags"], serde_json::json!(["filesystem"]));
2429 }
2430
2431 #[test]
2432 fn tags_deserialization() {
2433 use crate::types::{Prompt, Resource, Tool};
2434
2435 let json = serde_json::json!({
2437 "name": "tool",
2438 "inputSchema": {"type": "object"}
2439 });
2440 let tool: Tool = serde_json::from_value(json).expect("deserialize");
2441 assert!(tool.tags.is_empty());
2442
2443 let json = serde_json::json!({
2445 "name": "tool",
2446 "inputSchema": {"type": "object"},
2447 "tags": ["compute", "heavy"]
2448 });
2449 let tool: Tool = serde_json::from_value(json).expect("deserialize");
2450 assert_eq!(tool.tags, vec!["compute", "heavy"]);
2451
2452 let json = serde_json::json!({
2454 "uri": "file://test",
2455 "name": "Test"
2456 });
2457 let resource: Resource = serde_json::from_value(json).expect("deserialize");
2458 assert!(resource.tags.is_empty());
2459
2460 let json = serde_json::json!({
2462 "uri": "file://test",
2463 "name": "Test",
2464 "tags": ["data"]
2465 });
2466 let resource: Resource = serde_json::from_value(json).expect("deserialize");
2467 assert_eq!(resource.tags, vec!["data"]);
2468
2469 let json = serde_json::json!({
2471 "name": "prompt"
2472 });
2473 let prompt: Prompt = serde_json::from_value(json).expect("deserialize");
2474 assert!(prompt.tags.is_empty());
2475
2476 let json = serde_json::json!({
2478 "name": "prompt",
2479 "tags": ["greeting", "onboarding"]
2480 });
2481 let prompt: Prompt = serde_json::from_value(json).expect("deserialize");
2482 assert_eq!(prompt.tags, vec!["greeting", "onboarding"]);
2483 }
2484
2485 #[test]
2490 fn tool_annotations_serialization() {
2491 use crate::types::{Tool, ToolAnnotations};
2492
2493 let tool = Tool {
2495 name: "my_tool".to_string(),
2496 description: None,
2497 input_schema: serde_json::json!({"type": "object"}),
2498 output_schema: None,
2499 icon: None,
2500 version: None,
2501 tags: vec![],
2502 annotations: None,
2503 };
2504 let json = serde_json::to_value(&tool).expect("serialize");
2505 assert!(
2506 json.get("annotations").is_none(),
2507 "None annotations should not appear in JSON"
2508 );
2509
2510 let tool = Tool {
2512 name: "delete_file".to_string(),
2513 description: Some("Deletes a file".to_string()),
2514 input_schema: serde_json::json!({"type": "object"}),
2515 output_schema: None,
2516 icon: None,
2517 version: None,
2518 tags: vec![],
2519 annotations: Some(
2520 ToolAnnotations::new()
2521 .destructive(true)
2522 .idempotent(false)
2523 .read_only(false),
2524 ),
2525 };
2526 let json = serde_json::to_value(&tool).expect("serialize");
2527 let annotations = json.get("annotations").expect("annotations field");
2528 assert_eq!(annotations["destructive"], true);
2529 assert_eq!(annotations["idempotent"], false);
2530 assert_eq!(annotations["readOnly"], false);
2531 assert!(annotations.get("openWorldHint").is_none());
2532
2533 let tool = Tool {
2535 name: "get_status".to_string(),
2536 description: Some("Gets status".to_string()),
2537 input_schema: serde_json::json!({"type": "object"}),
2538 output_schema: None,
2539 icon: None,
2540 version: None,
2541 tags: vec![],
2542 annotations: Some(ToolAnnotations::new().read_only(true)),
2543 };
2544 let json = serde_json::to_value(&tool).expect("serialize");
2545 let annotations = json.get("annotations").expect("annotations field");
2546 assert_eq!(annotations["readOnly"], true);
2547 assert!(annotations.get("destructive").is_none());
2548 }
2549
2550 #[test]
2551 fn tool_annotations_deserialization() {
2552 use crate::types::Tool;
2553
2554 let json = serde_json::json!({
2556 "name": "tool",
2557 "inputSchema": {"type": "object"}
2558 });
2559 let tool: Tool = serde_json::from_value(json).expect("deserialize");
2560 assert!(tool.annotations.is_none());
2561
2562 let json = serde_json::json!({
2564 "name": "delete_tool",
2565 "inputSchema": {"type": "object"},
2566 "annotations": {
2567 "destructive": true,
2568 "idempotent": false,
2569 "readOnly": false,
2570 "openWorldHint": "May delete any file"
2571 }
2572 });
2573 let tool: Tool = serde_json::from_value(json).expect("deserialize");
2574 let annotations = tool.annotations.expect("annotations present");
2575 assert_eq!(annotations.destructive, Some(true));
2576 assert_eq!(annotations.idempotent, Some(false));
2577 assert_eq!(annotations.read_only, Some(false));
2578 assert_eq!(
2579 annotations.open_world_hint,
2580 Some("May delete any file".to_string())
2581 );
2582 }
2583
2584 #[test]
2585 fn tool_annotations_builder() {
2586 use crate::types::ToolAnnotations;
2587
2588 let annotations = ToolAnnotations::new()
2589 .destructive(true)
2590 .idempotent(true)
2591 .read_only(false)
2592 .open_world_hint("Handles unknown inputs gracefully");
2593
2594 assert_eq!(annotations.destructive, Some(true));
2595 assert_eq!(annotations.idempotent, Some(true));
2596 assert_eq!(annotations.read_only, Some(false));
2597 assert_eq!(
2598 annotations.open_world_hint,
2599 Some("Handles unknown inputs gracefully".to_string())
2600 );
2601 assert!(!annotations.is_empty());
2602
2603 let empty = ToolAnnotations::new();
2605 assert!(empty.is_empty());
2606 }
2607
2608 #[test]
2613 fn tool_output_schema_serialization() {
2614 use crate::types::Tool;
2615
2616 let tool = Tool {
2618 name: "my_tool".to_string(),
2619 description: None,
2620 input_schema: serde_json::json!({"type": "object"}),
2621 output_schema: None,
2622 icon: None,
2623 version: None,
2624 tags: vec![],
2625 annotations: None,
2626 };
2627 let json = serde_json::to_value(&tool).expect("serialize");
2628 assert!(
2629 json.get("outputSchema").is_none(),
2630 "None output_schema should not appear in JSON"
2631 );
2632
2633 let tool = Tool {
2635 name: "compute".to_string(),
2636 description: Some("Computes a result".to_string()),
2637 input_schema: serde_json::json!({"type": "object"}),
2638 output_schema: Some(serde_json::json!({
2639 "type": "object",
2640 "properties": {
2641 "result": {"type": "number"},
2642 "success": {"type": "boolean"}
2643 }
2644 })),
2645 icon: None,
2646 version: None,
2647 tags: vec![],
2648 annotations: None,
2649 };
2650 let json = serde_json::to_value(&tool).expect("serialize");
2651 let output_schema = json.get("outputSchema").expect("outputSchema field");
2652 assert_eq!(output_schema["type"], "object");
2653 assert!(output_schema["properties"]["result"]["type"] == "number");
2654 assert!(output_schema["properties"]["success"]["type"] == "boolean");
2655 }
2656
2657 #[test]
2658 fn tool_output_schema_deserialization() {
2659 use crate::types::Tool;
2660
2661 let json = serde_json::json!({
2663 "name": "tool",
2664 "inputSchema": {"type": "object"}
2665 });
2666 let tool: Tool = serde_json::from_value(json).expect("deserialize");
2667 assert!(tool.output_schema.is_none());
2668
2669 let json = serde_json::json!({
2671 "name": "compute",
2672 "inputSchema": {"type": "object"},
2673 "outputSchema": {
2674 "type": "object",
2675 "properties": {
2676 "value": {"type": "integer"}
2677 }
2678 }
2679 });
2680 let tool: Tool = serde_json::from_value(json).expect("deserialize");
2681 assert!(tool.output_schema.is_some());
2682 let schema = tool.output_schema.unwrap();
2683 assert_eq!(schema["type"], "object");
2684 assert_eq!(schema["properties"]["value"]["type"], "integer");
2685 }
2686}