1use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9
10pub const LATEST_PROTOCOL_VERSION: &str = "2025-06-18";
16pub const JSONRPC_VERSION: &str = "2.0";
17
18pub const PROTOCOL_VERSION: &str = LATEST_PROTOCOL_VERSION;
20
21pub type ProgressToken = serde_json::Value; pub type Cursor = String;
30
31pub type RequestId = serde_json::Value; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
36#[serde(untagged)]
37pub enum JsonRpcId {
38 String(String),
39 Number(i64),
40 Null,
41}
42
43impl From<i64> for JsonRpcId {
44 fn from(value: i64) -> Self {
45 JsonRpcId::Number(value)
46 }
47}
48
49impl From<String> for JsonRpcId {
50 fn from(value: String) -> Self {
51 JsonRpcId::String(value)
52 }
53}
54
55impl From<&str> for JsonRpcId {
56 fn from(value: &str) -> Self {
57 JsonRpcId::String(value.to_string())
58 }
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
67pub struct BaseMetadata {
68 pub name: String,
70 #[serde(skip_serializing_if = "Option::is_none")]
76 pub title: Option<String>,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
85pub struct Implementation {
86 pub name: String,
88 pub version: String,
90 #[serde(skip_serializing_if = "Option::is_none")]
93 pub title: Option<String>,
94}
95
96impl Implementation {
97 pub fn new<S: Into<String>>(name: S, version: S) -> Self {
99 Self {
100 name: name.into(),
101 version: version.into(),
102 title: None,
103 }
104 }
105
106 pub fn with_title<S: Into<String>>(name: S, version: S, title: S) -> Self {
108 Self {
109 name: name.into(),
110 version: version.into(),
111 title: Some(title.into()),
112 }
113 }
114}
115
116pub type ServerInfo = Implementation;
118pub type ClientInfo = Implementation;
119
120#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
126pub struct ServerCapabilities {
127 #[serde(skip_serializing_if = "Option::is_none")]
129 pub prompts: Option<PromptsCapability>,
130 #[serde(skip_serializing_if = "Option::is_none")]
132 pub resources: Option<ResourcesCapability>,
133 #[serde(skip_serializing_if = "Option::is_none")]
135 pub tools: Option<ToolsCapability>,
136 #[serde(skip_serializing_if = "Option::is_none")]
138 pub sampling: Option<SamplingCapability>,
139 #[serde(skip_serializing_if = "Option::is_none")]
141 pub logging: Option<LoggingCapability>,
142 #[serde(skip_serializing_if = "Option::is_none")]
144 pub completions: Option<CompletionsCapability>,
145 #[serde(skip_serializing_if = "Option::is_none")]
147 pub experimental: Option<HashMap<String, serde_json::Value>>,
148}
149
150#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
152pub struct ClientCapabilities {
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub sampling: Option<SamplingCapability>,
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub roots: Option<RootsCapability>,
159 #[serde(skip_serializing_if = "Option::is_none")]
161 pub elicitation: Option<ElicitationCapability>,
162 #[serde(skip_serializing_if = "Option::is_none")]
164 pub experimental: Option<HashMap<String, serde_json::Value>>,
165}
166
167#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
169pub struct PromptsCapability {
170 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
172 pub list_changed: Option<bool>,
173}
174
175#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
177pub struct ResourcesCapability {
178 #[serde(skip_serializing_if = "Option::is_none")]
180 pub subscribe: Option<bool>,
181 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
183 pub list_changed: Option<bool>,
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
188pub struct ToolsCapability {
189 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
191 pub list_changed: Option<bool>,
192}
193
194#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
196pub struct SamplingCapability {
197 #[serde(flatten)]
199 pub additional_properties: HashMap<String, serde_json::Value>,
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
204pub struct LoggingCapability {
205 #[serde(flatten)]
207 pub additional_properties: HashMap<String, serde_json::Value>,
208}
209
210#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
212pub struct CompletionsCapability {
213 #[serde(flatten)]
215 pub additional_properties: HashMap<String, serde_json::Value>,
216}
217
218#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
220pub struct RootsCapability {
221 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
223 pub list_changed: Option<bool>,
224}
225
226#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
228pub struct ElicitationCapability {
229 #[serde(flatten)]
231 pub additional_properties: HashMap<String, serde_json::Value>,
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
240pub struct Annotations {
241 #[serde(skip_serializing_if = "Option::is_none")]
245 pub audience: Option<Vec<Role>>,
246 #[serde(skip_serializing_if = "Option::is_none")]
252 pub priority: Option<f64>,
253 #[serde(rename = "lastModified", skip_serializing_if = "Option::is_none")]
260 pub last_modified: Option<String>,
261 #[serde(skip_serializing_if = "Option::is_none")]
263 pub danger: Option<DangerLevel>,
264 #[serde(skip_serializing_if = "Option::is_none")]
266 pub destructive: Option<bool>,
267 #[serde(skip_serializing_if = "Option::is_none")]
269 pub read_only: Option<bool>,
270}
271
272#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
278pub struct TextContent {
279 #[serde(rename = "type")]
281 pub content_type: String, pub text: String,
284 #[serde(skip_serializing_if = "Option::is_none")]
286 pub annotations: Option<Annotations>,
287 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
289 pub meta: Option<HashMap<String, serde_json::Value>>,
290}
291
292#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
294pub struct ImageContent {
295 #[serde(rename = "type")]
297 pub content_type: String, pub data: String,
300 #[serde(rename = "mimeType")]
302 pub mime_type: String,
303 #[serde(skip_serializing_if = "Option::is_none")]
305 pub annotations: Option<Annotations>,
306 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
308 pub meta: Option<HashMap<String, serde_json::Value>>,
309}
310
311#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
313pub struct AudioContent {
314 #[serde(rename = "type")]
316 pub content_type: String, pub data: String,
319 #[serde(rename = "mimeType")]
321 pub mime_type: String,
322 #[serde(skip_serializing_if = "Option::is_none")]
324 pub annotations: Option<Annotations>,
325 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
327 pub meta: Option<HashMap<String, serde_json::Value>>,
328}
329
330#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
332pub struct ResourceLink {
333 #[serde(rename = "type")]
335 pub content_type: String, pub uri: String,
338 pub name: String,
340 #[serde(skip_serializing_if = "Option::is_none")]
342 pub description: Option<String>,
343 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
345 pub mime_type: Option<String>,
346 #[serde(skip_serializing_if = "Option::is_none")]
348 pub size: Option<u64>,
349 #[serde(skip_serializing_if = "Option::is_none")]
351 pub title: Option<String>,
352 #[serde(skip_serializing_if = "Option::is_none")]
354 pub annotations: Option<Annotations>,
355 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
357 pub meta: Option<HashMap<String, serde_json::Value>>,
358}
359
360#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
362pub struct EmbeddedResource {
363 #[serde(rename = "type")]
365 pub content_type: String, pub resource: ResourceContents,
368 #[serde(skip_serializing_if = "Option::is_none")]
370 pub annotations: Option<Annotations>,
371 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
373 pub meta: Option<HashMap<String, serde_json::Value>>,
374}
375
376#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
378#[serde(tag = "type")]
379pub enum ContentBlock {
380 #[serde(rename = "text")]
382 Text {
383 text: String,
385 #[serde(skip_serializing_if = "Option::is_none")]
387 annotations: Option<Annotations>,
388 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
390 meta: Option<HashMap<String, serde_json::Value>>,
391 },
392 #[serde(rename = "image")]
394 Image {
395 data: String,
397 #[serde(rename = "mimeType")]
399 mime_type: String,
400 #[serde(skip_serializing_if = "Option::is_none")]
402 annotations: Option<Annotations>,
403 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
405 meta: Option<HashMap<String, serde_json::Value>>,
406 },
407 #[serde(rename = "audio")]
409 Audio {
410 data: String,
412 #[serde(rename = "mimeType")]
414 mime_type: String,
415 #[serde(skip_serializing_if = "Option::is_none")]
417 annotations: Option<Annotations>,
418 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
420 meta: Option<HashMap<String, serde_json::Value>>,
421 },
422 #[serde(rename = "resource_link")]
424 ResourceLink {
425 uri: String,
427 name: String,
429 #[serde(skip_serializing_if = "Option::is_none")]
431 description: Option<String>,
432 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
434 mime_type: Option<String>,
435 #[serde(skip_serializing_if = "Option::is_none")]
437 size: Option<u64>,
438 #[serde(skip_serializing_if = "Option::is_none")]
440 title: Option<String>,
441 #[serde(skip_serializing_if = "Option::is_none")]
443 annotations: Option<Annotations>,
444 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
446 meta: Option<HashMap<String, serde_json::Value>>,
447 },
448 #[serde(rename = "resource")]
450 Resource {
451 resource: ResourceContents,
453 #[serde(skip_serializing_if = "Option::is_none")]
455 annotations: Option<Annotations>,
456 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
458 meta: Option<HashMap<String, serde_json::Value>>,
459 },
460}
461
462pub type Content = ContentBlock;
464
465impl ContentBlock {
470 pub fn text<S: Into<String>>(text: S) -> Self {
472 ContentBlock::Text {
473 text: text.into(),
474 annotations: None,
475 meta: None,
476 }
477 }
478
479 pub fn text_with_annotations<S: Into<String>>(text: S, annotations: Annotations) -> Self {
481 ContentBlock::Text {
482 text: text.into(),
483 annotations: Some(annotations),
484 meta: None,
485 }
486 }
487
488 pub fn image<S: Into<String>>(data: S, mime_type: S) -> Self {
490 ContentBlock::Image {
491 data: data.into(),
492 mime_type: mime_type.into(),
493 annotations: None,
494 meta: None,
495 }
496 }
497
498 pub fn audio<S: Into<String>>(data: S, mime_type: S) -> Self {
500 ContentBlock::Audio {
501 data: data.into(),
502 mime_type: mime_type.into(),
503 annotations: None,
504 meta: None,
505 }
506 }
507
508 pub fn resource_link<S: Into<String>>(uri: S, name: S) -> Self {
510 ContentBlock::ResourceLink {
511 uri: uri.into(),
512 name: name.into(),
513 description: None,
514 mime_type: None,
515 size: None,
516 title: None,
517 annotations: None,
518 meta: None,
519 }
520 }
521
522 pub fn embedded_resource(resource: ResourceContents) -> Self {
524 ContentBlock::Resource {
525 resource,
526 annotations: None,
527 meta: None,
528 }
529 }
530
531 pub fn resource<S: Into<String>>(uri: S) -> Self {
533 let uri_str = uri.into();
536 ContentBlock::ResourceLink {
537 uri: uri_str.clone(),
538 name: uri_str,
539 description: None,
540 mime_type: None,
541 size: None,
542 title: None,
543 annotations: None,
544 meta: None,
545 }
546 }
547}
548
549#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
562pub struct ToolAnnotations {
563 #[serde(skip_serializing_if = "Option::is_none")]
565 pub title: Option<String>,
566
567 #[serde(rename = "readOnlyHint", skip_serializing_if = "Option::is_none")]
570 pub read_only_hint: Option<bool>,
571
572 #[serde(rename = "destructiveHint", skip_serializing_if = "Option::is_none")]
577 pub destructive_hint: Option<bool>,
578
579 #[serde(rename = "idempotentHint", skip_serializing_if = "Option::is_none")]
584 pub idempotent_hint: Option<bool>,
585
586 #[serde(rename = "openWorldHint", skip_serializing_if = "Option::is_none")]
592 pub open_world_hint: Option<bool>,
593}
594
595impl ToolAnnotations {
596 pub fn new() -> Self {
598 Self::default()
599 }
600
601 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
603 self.title = Some(title.into());
604 self
605 }
606
607 pub fn read_only(mut self) -> Self {
609 self.read_only_hint = Some(true);
610 self
611 }
612
613 pub fn destructive(mut self) -> Self {
615 self.destructive_hint = Some(true);
616 self
617 }
618
619 pub fn idempotent(mut self) -> Self {
621 self.idempotent_hint = Some(true);
622 self
623 }
624
625 pub fn open_world(mut self) -> Self {
627 self.open_world_hint = Some(true);
628 self
629 }
630
631 pub fn closed_world(mut self) -> Self {
633 self.open_world_hint = Some(false);
634 self
635 }
636}
637
638impl From<&crate::core::tool_metadata::ToolBehaviorHints> for ToolAnnotations {
643 fn from(hints: &crate::core::tool_metadata::ToolBehaviorHints) -> Self {
644 Self {
645 title: None, read_only_hint: hints.read_only,
647 destructive_hint: hints.destructive,
648 idempotent_hint: hints.idempotent,
649 open_world_hint: if hints.requires_auth.unwrap_or(false)
651 || hints.resource_intensive.unwrap_or(false)
652 {
653 Some(true)
654 } else {
655 None
656 },
657 }
658 }
659}
660
661impl From<&crate::core::tool_metadata::ImprovedToolMetadata> for ToolAnnotations {
662 fn from(metadata: &crate::core::tool_metadata::ImprovedToolMetadata) -> Self {
663 ToolAnnotations::from(&metadata.behavior_hints)
664 }
665}
666
667impl ToolAnnotations {
668 pub fn from_improved_metadata(
670 metadata: &crate::core::tool_metadata::ImprovedToolMetadata,
671 title_override: Option<String>,
672 ) -> Self {
673 let mut annotations = Self::from(metadata);
674 if let Some(title) = title_override {
675 annotations.title = Some(title);
676 }
677 annotations
678 }
679
680 pub fn from_behavior_hints(hints: &crate::core::tool_metadata::ToolBehaviorHints) -> Self {
682 Self::from(hints)
683 }
684}
685
686#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
688pub struct Tool {
689 pub name: String,
691 #[serde(skip_serializing_if = "Option::is_none")]
693 pub description: Option<String>,
694 #[serde(rename = "inputSchema")]
696 pub input_schema: ToolInputSchema,
697 #[serde(rename = "outputSchema", skip_serializing_if = "Option::is_none")]
700 pub output_schema: Option<ToolOutputSchema>,
701 #[serde(skip_serializing_if = "Option::is_none")]
703 pub annotations: Option<ToolAnnotations>,
704 #[serde(skip_serializing_if = "Option::is_none")]
706 pub title: Option<String>,
707 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
709 pub meta: Option<HashMap<String, serde_json::Value>>,
710}
711
712#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
714pub struct ToolInputSchema {
715 #[serde(rename = "type")]
717 pub schema_type: String,
718 #[serde(skip_serializing_if = "Option::is_none")]
720 pub properties: Option<HashMap<String, serde_json::Value>>,
721 #[serde(skip_serializing_if = "Option::is_none")]
723 pub required: Option<Vec<String>>,
724 #[serde(flatten)]
726 pub additional_properties: HashMap<String, serde_json::Value>,
727}
728
729#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
731pub struct ToolOutputSchema {
732 #[serde(rename = "type")]
734 pub schema_type: String,
735 #[serde(skip_serializing_if = "Option::is_none")]
737 pub properties: Option<HashMap<String, serde_json::Value>>,
738 #[serde(skip_serializing_if = "Option::is_none")]
740 pub required: Option<Vec<String>>,
741}
742
743impl ToolOutputSchema {
744 pub fn new() -> Self {
746 Self {
747 schema_type: "object".to_string(),
748 properties: None,
749 required: None,
750 }
751 }
752
753 pub fn with_properties(properties: HashMap<String, serde_json::Value>) -> Self {
755 Self {
756 schema_type: "object".to_string(),
757 properties: Some(properties),
758 required: None,
759 }
760 }
761
762 pub fn with_required(mut self, required: Vec<String>) -> Self {
764 self.required = Some(required);
765 self
766 }
767
768 pub fn with_properties_map(mut self, properties: HashMap<String, serde_json::Value>) -> Self {
770 self.properties = Some(properties);
771 self
772 }
773}
774
775impl Default for ToolOutputSchema {
776 fn default() -> Self {
777 Self::new()
778 }
779}
780
781#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
783pub struct CallToolResult {
784 pub content: Vec<ContentBlock>,
786 #[serde(rename = "isError", skip_serializing_if = "Option::is_none")]
788 pub is_error: Option<bool>,
789 #[serde(rename = "structuredContent", skip_serializing_if = "Option::is_none")]
791 pub structured_content: Option<serde_json::Value>,
792 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
794 pub meta: Option<HashMap<String, serde_json::Value>>,
795}
796
797impl CallToolResult {
802 pub fn text<S: Into<String>>(text: S) -> Self {
804 Self {
805 content: vec![ContentBlock::text(text)],
806 is_error: Some(false),
807 structured_content: None,
808 meta: None,
809 }
810 }
811
812 pub fn error<S: Into<String>>(message: S) -> Self {
814 Self {
815 content: vec![ContentBlock::text(message)],
816 is_error: Some(true),
817 structured_content: None,
818 meta: None,
819 }
820 }
821
822 pub fn with_content(content: Vec<ContentBlock>) -> Self {
824 Self {
825 content,
826 is_error: Some(false),
827 structured_content: None,
828 meta: None,
829 }
830 }
831
832 pub fn with_structured(content: Vec<ContentBlock>, structured: serde_json::Value) -> Self {
834 Self {
835 content,
836 is_error: Some(false),
837 structured_content: Some(structured),
838 meta: None,
839 }
840 }
841}
842
843pub type ToolInfo = Tool;
845pub type ToolResult = CallToolResult;
846
847#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
856pub struct Resource {
857 pub uri: String,
859 pub name: String,
861 #[serde(skip_serializing_if = "Option::is_none")]
863 pub description: Option<String>,
864 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
866 pub mime_type: Option<String>,
867 #[serde(skip_serializing_if = "Option::is_none")]
869 pub annotations: Option<Annotations>,
870 #[serde(skip_serializing_if = "Option::is_none")]
872 pub size: Option<u64>,
873 #[serde(skip_serializing_if = "Option::is_none")]
875 pub title: Option<String>,
876 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
878 pub meta: Option<HashMap<String, serde_json::Value>>,
879}
880
881#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
883pub struct ResourceTemplate {
884 #[serde(rename = "uriTemplate")]
886 pub uri_template: String,
887 pub name: String,
889 #[serde(skip_serializing_if = "Option::is_none")]
891 pub description: Option<String>,
892 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
894 pub mime_type: Option<String>,
895 #[serde(skip_serializing_if = "Option::is_none")]
897 pub annotations: Option<Annotations>,
898 #[serde(skip_serializing_if = "Option::is_none")]
900 pub title: Option<String>,
901 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
903 pub meta: Option<HashMap<String, serde_json::Value>>,
904}
905
906#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
908#[serde(untagged)]
909pub enum ResourceContents {
910 Text {
912 uri: String,
914 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
916 mime_type: Option<String>,
917 text: String,
919 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
921 meta: Option<HashMap<String, serde_json::Value>>,
922 },
923 Blob {
925 uri: String,
927 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
929 mime_type: Option<String>,
930 blob: String,
932 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
934 meta: Option<HashMap<String, serde_json::Value>>,
935 },
936}
937
938impl ResourceContents {
939 pub fn uri(&self) -> &str {
941 match self {
942 ResourceContents::Text { uri, .. } => uri,
943 ResourceContents::Blob { uri, .. } => uri,
944 }
945 }
946}
947
948pub type ResourceInfo = Resource;
950
951#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
957pub struct Prompt {
958 pub name: String,
960 #[serde(skip_serializing_if = "Option::is_none")]
962 pub description: Option<String>,
963 #[serde(skip_serializing_if = "Option::is_none")]
965 pub arguments: Option<Vec<PromptArgument>>,
966 #[serde(skip_serializing_if = "Option::is_none")]
968 pub title: Option<String>,
969 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
971 pub meta: Option<HashMap<String, serde_json::Value>>,
972}
973
974#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
976pub struct PromptArgument {
977 pub name: String,
979 #[serde(skip_serializing_if = "Option::is_none")]
981 pub description: Option<String>,
982 #[serde(skip_serializing_if = "Option::is_none")]
984 pub required: Option<bool>,
985 #[serde(skip_serializing_if = "Option::is_none")]
987 pub title: Option<String>,
988}
989
990#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
992#[serde(rename_all = "lowercase")]
993pub enum Role {
994 User,
995 Assistant,
996}
997
998#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1000pub struct PromptMessage {
1001 pub role: Role,
1003 pub content: ContentBlock,
1005}
1006
1007#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1009pub struct GetPromptResult {
1010 #[serde(skip_serializing_if = "Option::is_none")]
1012 pub description: Option<String>,
1013 pub messages: Vec<PromptMessage>,
1015 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1017 pub meta: Option<HashMap<String, serde_json::Value>>,
1018}
1019
1020pub type PromptInfo = Prompt;
1022pub type PromptResult = GetPromptResult;
1023
1024#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1030pub struct SamplingMessage {
1031 pub role: Role,
1033 pub content: SamplingContent,
1035}
1036
1037#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1039#[serde(tag = "type")]
1040pub enum SamplingContent {
1041 #[serde(rename = "text")]
1043 Text {
1044 text: String,
1046 #[serde(skip_serializing_if = "Option::is_none")]
1048 annotations: Option<Annotations>,
1049 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1051 meta: Option<HashMap<String, serde_json::Value>>,
1052 },
1053 #[serde(rename = "image")]
1055 Image {
1056 data: String,
1058 #[serde(rename = "mimeType")]
1060 mime_type: String,
1061 #[serde(skip_serializing_if = "Option::is_none")]
1063 annotations: Option<Annotations>,
1064 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1066 meta: Option<HashMap<String, serde_json::Value>>,
1067 },
1068 #[serde(rename = "audio")]
1070 Audio {
1071 data: String,
1073 #[serde(rename = "mimeType")]
1075 mime_type: String,
1076 #[serde(skip_serializing_if = "Option::is_none")]
1078 annotations: Option<Annotations>,
1079 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1081 meta: Option<HashMap<String, serde_json::Value>>,
1082 },
1083}
1084
1085#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1087pub struct ModelHint {
1088 #[serde(skip_serializing_if = "Option::is_none")]
1095 pub name: Option<String>,
1096
1097 #[serde(flatten)]
1101 pub additional_hints: Option<HashMap<String, serde_json::Value>>,
1102}
1103
1104#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
1106pub struct ModelPreferences {
1107 #[serde(rename = "costPriority", skip_serializing_if = "Option::is_none")]
1109 pub cost_priority: Option<f64>,
1110 #[serde(rename = "speedPriority", skip_serializing_if = "Option::is_none")]
1112 pub speed_priority: Option<f64>,
1113 #[serde(
1115 rename = "intelligencePriority",
1116 skip_serializing_if = "Option::is_none"
1117 )]
1118 pub intelligence_priority: Option<f64>,
1119 #[serde(skip_serializing_if = "Option::is_none")]
1121 pub hints: Option<Vec<ModelHint>>,
1122}
1123
1124#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1126pub struct CreateMessageResult {
1127 pub role: Role,
1129 pub content: SamplingContent,
1131 pub model: String,
1133 #[serde(rename = "stopReason", skip_serializing_if = "Option::is_none")]
1135 pub stop_reason: Option<StopReason>,
1136 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1138 pub meta: Option<HashMap<String, serde_json::Value>>,
1139}
1140
1141#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1143#[serde(rename_all = "camelCase")]
1144pub enum StopReason {
1145 EndTurn,
1146 StopSequence,
1147 MaxTokens,
1148 #[serde(untagged)]
1149 Other(String),
1150}
1151
1152#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1158#[serde(tag = "type")]
1159pub enum PrimitiveSchemaDefinition {
1160 #[serde(rename = "string")]
1161 String {
1162 #[serde(skip_serializing_if = "Option::is_none")]
1163 title: Option<String>,
1164 #[serde(skip_serializing_if = "Option::is_none")]
1165 description: Option<String>,
1166 #[serde(rename = "minLength", skip_serializing_if = "Option::is_none")]
1167 min_length: Option<u32>,
1168 #[serde(rename = "maxLength", skip_serializing_if = "Option::is_none")]
1169 max_length: Option<u32>,
1170 #[serde(skip_serializing_if = "Option::is_none")]
1171 format: Option<String>,
1172 #[serde(rename = "enum", skip_serializing_if = "Option::is_none")]
1173 enum_values: Option<Vec<String>>,
1174 #[serde(rename = "enumNames", skip_serializing_if = "Option::is_none")]
1175 enum_names: Option<Vec<String>>,
1176 },
1177 #[serde(rename = "number")]
1178 Number {
1179 #[serde(skip_serializing_if = "Option::is_none")]
1180 title: Option<String>,
1181 #[serde(skip_serializing_if = "Option::is_none")]
1182 description: Option<String>,
1183 #[serde(skip_serializing_if = "Option::is_none")]
1184 minimum: Option<i32>,
1185 #[serde(skip_serializing_if = "Option::is_none")]
1186 maximum: Option<i32>,
1187 },
1188 #[serde(rename = "integer")]
1189 Integer {
1190 #[serde(skip_serializing_if = "Option::is_none")]
1191 title: Option<String>,
1192 #[serde(skip_serializing_if = "Option::is_none")]
1193 description: Option<String>,
1194 #[serde(skip_serializing_if = "Option::is_none")]
1195 minimum: Option<i32>,
1196 #[serde(skip_serializing_if = "Option::is_none")]
1197 maximum: Option<i32>,
1198 },
1199 #[serde(rename = "boolean")]
1200 Boolean {
1201 #[serde(skip_serializing_if = "Option::is_none")]
1202 title: Option<String>,
1203 #[serde(skip_serializing_if = "Option::is_none")]
1204 description: Option<String>,
1205 #[serde(skip_serializing_if = "Option::is_none")]
1206 default: Option<bool>,
1207 },
1208}
1209
1210#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1212pub struct ElicitationSchema {
1213 #[serde(rename = "type")]
1215 pub schema_type: String,
1216 pub properties: HashMap<String, PrimitiveSchemaDefinition>,
1218 #[serde(skip_serializing_if = "Option::is_none")]
1220 pub required: Option<Vec<String>>,
1221}
1222
1223#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1225#[serde(rename_all = "lowercase")]
1226pub enum ElicitationAction {
1227 Accept,
1229 Decline,
1231 Cancel,
1233}
1234
1235#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1241#[serde(rename_all = "lowercase")]
1242pub enum LoggingLevel {
1243 Debug,
1244 Info,
1245 Notice,
1246 Warning,
1247 Error,
1248 Critical,
1249 Alert,
1250 Emergency,
1251}
1252
1253#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1259pub struct JsonRpcRequest {
1260 pub jsonrpc: String,
1262 pub id: RequestId,
1264 pub method: String,
1266 #[serde(skip_serializing_if = "Option::is_none")]
1268 pub params: Option<serde_json::Value>,
1269}
1270
1271#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1273pub struct JsonRpcResponse {
1274 pub jsonrpc: String,
1276 pub id: RequestId,
1278 #[serde(skip_serializing_if = "Option::is_none")]
1280 pub result: Option<serde_json::Value>,
1281}
1282
1283#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1285pub struct JsonRpcError {
1286 pub jsonrpc: String,
1288 pub id: RequestId,
1290 pub error: ErrorObject,
1292}
1293
1294#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1296pub struct ErrorObject {
1297 pub code: i32,
1299 pub message: String,
1301 #[serde(skip_serializing_if = "Option::is_none")]
1303 pub data: Option<serde_json::Value>,
1304}
1305
1306#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1308pub struct JsonRpcNotification {
1309 pub jsonrpc: String,
1311 pub method: String,
1313 #[serde(skip_serializing_if = "Option::is_none")]
1315 pub params: Option<serde_json::Value>,
1316}
1317
1318#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1320#[serde(untagged)]
1321pub enum JsonRpcMessage {
1322 Request(JsonRpcRequest),
1323 Response(JsonRpcResponse),
1324 Error(JsonRpcError),
1325 Notification(JsonRpcNotification),
1326}
1327
1328#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1334pub struct Request {
1335 pub method: String,
1337 #[serde(skip_serializing_if = "Option::is_none")]
1339 pub params: Option<RequestParams>,
1340}
1341
1342#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1344pub struct RequestParams {
1345 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1347 pub meta: Option<RequestMeta>,
1348 #[serde(flatten)]
1350 pub params: HashMap<String, serde_json::Value>,
1351}
1352
1353#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1355pub struct RequestMeta {
1356 #[serde(rename = "progressToken", skip_serializing_if = "Option::is_none")]
1358 pub progress_token: Option<ProgressToken>,
1359}
1360
1361#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1363pub struct Notification {
1364 pub method: String,
1366 #[serde(skip_serializing_if = "Option::is_none")]
1368 pub params: Option<NotificationParams>,
1369}
1370
1371#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1373pub struct NotificationParams {
1374 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1376 pub meta: Option<HashMap<String, serde_json::Value>>,
1377 #[serde(flatten)]
1379 pub params: HashMap<String, serde_json::Value>,
1380}
1381
1382#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1388pub struct PaginatedRequest {
1389 #[serde(skip_serializing_if = "Option::is_none")]
1391 pub cursor: Option<Cursor>,
1392}
1393
1394#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1396pub struct PaginatedResult {
1397 #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
1399 pub next_cursor: Option<Cursor>,
1400}
1401
1402impl SamplingContent {
1405 pub fn text<S: Into<String>>(text: S) -> Self {
1407 Self::Text {
1408 text: text.into(),
1409 annotations: None,
1410 meta: None,
1411 }
1412 }
1413
1414 pub fn image<S: Into<String>>(data: S, mime_type: S) -> Self {
1416 Self::Image {
1417 data: data.into(),
1418 mime_type: mime_type.into(),
1419 annotations: None,
1420 meta: None,
1421 }
1422 }
1423
1424 pub fn audio<S: Into<String>>(data: S, mime_type: S) -> Self {
1426 Self::Audio {
1427 data: data.into(),
1428 mime_type: mime_type.into(),
1429 annotations: None,
1430 meta: None,
1431 }
1432 }
1433}
1434
1435impl Annotations {
1436 pub fn new() -> Self {
1438 Self {
1439 audience: None,
1440 priority: None,
1441 last_modified: None,
1442 danger: None,
1443 destructive: None,
1444 read_only: None,
1445 }
1446 }
1447
1448 pub fn with_priority(mut self, priority: f64) -> Self {
1450 self.priority = Some(priority.clamp(0.0, 1.0));
1451 self
1452 }
1453
1454 pub fn for_audience(mut self, audience: Vec<Role>) -> Self {
1456 self.audience = Some(audience);
1457 self
1458 }
1459
1460 pub fn with_last_modified<S: Into<String>>(mut self, timestamp: S) -> Self {
1462 self.last_modified = Some(timestamp.into());
1463 self
1464 }
1465
1466 pub fn for_audience_legacy(self, _audience: Vec<AnnotationAudience>) -> Self {
1468 self
1470 }
1471
1472 pub fn with_danger_level(mut self, level: DangerLevel) -> Self {
1474 self.danger = Some(level);
1476 self
1477 }
1478
1479 pub fn danger(&self) -> Option<DangerLevel> {
1481 None
1482 }
1483
1484 pub fn audience(&self) -> Option<Vec<AnnotationAudience>> {
1486 None
1487 }
1488
1489 pub fn read_only(mut self) -> Self {
1491 self.read_only = Some(true);
1492 self.destructive = Some(false);
1493 self
1494 }
1495
1496 pub fn destructive(mut self, level: DangerLevel) -> Self {
1498 self.destructive = Some(true);
1499 self.read_only = Some(false);
1500 self.danger = Some(level);
1501 self
1502 }
1503}
1504
1505impl Tool {
1506 pub fn new<S: Into<String>>(name: S, description: S) -> Self {
1508 Self {
1509 name: name.into(),
1510 description: Some(description.into()),
1511 input_schema: ToolInputSchema {
1512 schema_type: "object".to_string(),
1513 properties: None,
1514 required: None,
1515 additional_properties: HashMap::new(),
1516 },
1517 output_schema: None,
1518 annotations: None,
1519 title: None,
1520 meta: None,
1521 }
1522 }
1523
1524 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1526 self.title = Some(title.into());
1527 self
1528 }
1529
1530 pub fn with_annotations(mut self, annotations: ToolAnnotations) -> Self {
1532 self.annotations = Some(annotations);
1533 self
1534 }
1535
1536 pub fn with_output_schema(mut self, output_schema: ToolOutputSchema) -> Self {
1538 self.output_schema = Some(output_schema);
1539 self
1540 }
1541}
1542
1543impl Resource {
1544 pub fn new<S: Into<String>>(uri: S, name: S) -> Self {
1546 Self {
1547 uri: uri.into(),
1548 name: name.into(),
1549 description: None,
1550 mime_type: None,
1551 annotations: None,
1552 size: None,
1553 title: None,
1554 meta: None,
1555 }
1556 }
1557
1558 pub fn from_legacy<S: Into<String>>(uri: S, name: Option<S>) -> Self {
1560 Self {
1561 uri: uri.into(),
1562 name: name
1563 .map(|n| n.into())
1564 .unwrap_or_else(|| "Unnamed Resource".to_string()),
1565 description: None,
1566 mime_type: None,
1567 annotations: None,
1568 size: None,
1569 title: None,
1570 meta: None,
1571 }
1572 }
1573
1574 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1576 self.title = Some(title.into());
1577 self
1578 }
1579
1580 pub fn with_description<S: Into<String>>(mut self, description: S) -> Self {
1582 self.description = Some(description.into());
1583 self
1584 }
1585}
1586
1587impl ResourceTemplate {
1588 pub fn new<S: Into<String>>(uri_template: S, name: S) -> Self {
1590 Self {
1591 uri_template: uri_template.into(),
1592 name: name.into(),
1593 description: None,
1594 mime_type: None,
1595 annotations: None,
1596 title: None,
1597 meta: None,
1598 }
1599 }
1600
1601 pub fn from_legacy<S: Into<String>>(uri_template: S, name: Option<S>) -> Self {
1603 Self {
1604 uri_template: uri_template.into(),
1605 name: name
1606 .map(|n| n.into())
1607 .unwrap_or_else(|| "Unnamed Template".to_string()),
1608 description: None,
1609 mime_type: None,
1610 annotations: None,
1611 title: None,
1612 meta: None,
1613 }
1614 }
1615
1616 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1618 self.title = Some(title.into());
1619 self
1620 }
1621}
1622
1623impl Prompt {
1624 pub fn new<S: Into<String>>(name: S) -> Self {
1626 Self {
1627 name: name.into(),
1628 description: None,
1629 arguments: None,
1630 title: None,
1631 meta: None,
1632 }
1633 }
1634
1635 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1637 self.title = Some(title.into());
1638 self
1639 }
1640
1641 pub fn with_description<S: Into<String>>(mut self, description: S) -> Self {
1643 self.description = Some(description.into());
1644 self
1645 }
1646}
1647
1648impl PromptArgument {
1649 pub fn new<S: Into<String>>(name: S) -> Self {
1651 Self {
1652 name: name.into(),
1653 description: None,
1654 required: None,
1655 title: None,
1656 }
1657 }
1658
1659 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1661 self.title = Some(title.into());
1662 self
1663 }
1664
1665 pub fn required(mut self, required: bool) -> Self {
1667 self.required = Some(required);
1668 self
1669 }
1670}
1671
1672impl JsonRpcRequest {
1673 pub fn new<T: Serialize>(
1675 id: RequestId,
1676 method: String,
1677 params: Option<T>,
1678 ) -> std::result::Result<Self, serde_json::Error> {
1679 let params = match params {
1680 Some(p) => Some(serde_json::to_value(p)?),
1681 None => None,
1682 };
1683
1684 Ok(Self {
1685 jsonrpc: JSONRPC_VERSION.to_string(),
1686 id,
1687 method,
1688 params,
1689 })
1690 }
1691}
1692
1693impl JsonRpcResponse {
1694 pub fn success<T: Serialize>(
1696 id: RequestId,
1697 result: T,
1698 ) -> std::result::Result<Self, serde_json::Error> {
1699 Ok(Self {
1700 jsonrpc: JSONRPC_VERSION.to_string(),
1701 id,
1702 result: Some(serde_json::to_value(result)?),
1703 })
1704 }
1705
1706 pub fn success_unchecked(id: RequestId, result: serde_json::Value) -> Self {
1709 Self {
1710 jsonrpc: JSONRPC_VERSION.to_string(),
1711 id,
1712 result: Some(result),
1713 }
1714 }
1715}
1716
1717impl JsonRpcError {
1718 pub fn error(
1720 id: RequestId,
1721 code: i32,
1722 message: String,
1723 data: Option<serde_json::Value>,
1724 ) -> Self {
1725 Self {
1726 jsonrpc: JSONRPC_VERSION.to_string(),
1727 id,
1728 error: ErrorObject {
1729 code,
1730 message,
1731 data,
1732 },
1733 }
1734 }
1735}
1736
1737impl JsonRpcNotification {
1738 pub fn new<T: Serialize>(
1740 method: String,
1741 params: Option<T>,
1742 ) -> std::result::Result<Self, serde_json::Error> {
1743 let params = match params {
1744 Some(p) => Some(serde_json::to_value(p)?),
1745 None => None,
1746 };
1747
1748 Ok(Self {
1749 jsonrpc: JSONRPC_VERSION.to_string(),
1750 method,
1751 params,
1752 })
1753 }
1754}
1755
1756impl SamplingMessage {
1757 pub fn user_text<S: Into<String>>(text: S) -> Self {
1759 Self {
1760 role: Role::User,
1761 content: SamplingContent::text(text),
1762 }
1763 }
1764
1765 pub fn assistant_text<S: Into<String>>(text: S) -> Self {
1767 Self {
1768 role: Role::Assistant,
1769 content: SamplingContent::text(text),
1770 }
1771 }
1772
1773 pub fn user_image<S: Into<String>>(data: S, mime_type: S) -> Self {
1775 Self {
1776 role: Role::User,
1777 content: SamplingContent::image(data, mime_type),
1778 }
1779 }
1780
1781 pub fn user_audio<S: Into<String>>(data: S, mime_type: S) -> Self {
1783 Self {
1784 role: Role::User,
1785 content: SamplingContent::audio(data, mime_type),
1786 }
1787 }
1788}
1789
1790pub mod error_codes {
1796 pub const PARSE_ERROR: i32 = -32700;
1798 pub const INVALID_REQUEST: i32 = -32600;
1800 pub const METHOD_NOT_FOUND: i32 = -32601;
1802 pub const INVALID_PARAMS: i32 = -32602;
1804 pub const INTERNAL_ERROR: i32 = -32603;
1806
1807 pub const TOOL_NOT_FOUND: i32 = -32000;
1809 pub const RESOURCE_NOT_FOUND: i32 = -32001;
1810 pub const PROMPT_NOT_FOUND: i32 = -32002;
1811}
1812
1813#[cfg(test)]
1814mod tests {
1815 use super::*;
1816 use serde_json::json;
1817
1818 #[test]
1819 fn test_protocol_version() {
1820 assert_eq!(LATEST_PROTOCOL_VERSION, "2025-06-18");
1821 assert_eq!(JSONRPC_VERSION, "2.0");
1822 }
1823
1824 #[test]
1825 fn test_content_block_types() {
1826 let text = ContentBlock::text("Hello, world!");
1828 let json = serde_json::to_value(&text).unwrap();
1829 assert_eq!(json["type"], "text");
1830 assert_eq!(json["text"], "Hello, world!");
1831
1832 let audio = ContentBlock::audio("base64data", "audio/wav");
1834 let json = serde_json::to_value(&audio).unwrap();
1835 assert_eq!(json["type"], "audio");
1836 assert_eq!(json["data"], "base64data");
1837 assert_eq!(json["mimeType"], "audio/wav");
1838
1839 let resource_link = ContentBlock::resource_link("file:///test.txt", "test file");
1841 let json = serde_json::to_value(&resource_link).unwrap();
1842 assert_eq!(json["type"], "resource_link");
1843 assert_eq!(json["uri"], "file:///test.txt");
1844 assert_eq!(json["name"], "test file");
1845 }
1846
1847 #[test]
1848 fn test_annotations() {
1849 let annotations = Annotations::new()
1850 .with_priority(0.8)
1851 .for_audience(vec![Role::User, Role::Assistant])
1852 .with_last_modified("2025-01-12T15:00:58Z");
1853
1854 assert_eq!(annotations.priority, Some(0.8));
1855 assert_eq!(
1856 annotations.audience,
1857 Some(vec![Role::User, Role::Assistant])
1858 );
1859 assert_eq!(
1860 annotations.last_modified,
1861 Some("2025-01-12T15:00:58Z".to_string())
1862 );
1863 }
1864
1865 #[test]
1866 fn test_tool_with_title() {
1867 let tool = Tool::new("file_reader", "Read files safely")
1868 .with_title("File Reader Tool")
1869 .with_annotations(ToolAnnotations::new().with_title("File Reader"));
1870
1871 assert_eq!(tool.name, "file_reader");
1872 assert_eq!(tool.title, Some("File Reader Tool".to_string()));
1873 assert!(tool.annotations.is_some());
1874 assert_eq!(
1875 tool.annotations.unwrap().title,
1876 Some("File Reader".to_string())
1877 );
1878 }
1879
1880 #[test]
1881 fn test_tool_with_output_schema() {
1882 use serde_json::json;
1883
1884 let output_schema = ToolOutputSchema::with_properties(HashMap::from([
1886 ("result".to_string(), json!({"type": "string"})),
1887 ("count".to_string(), json!({"type": "number"})),
1888 ]))
1889 .with_required(vec!["result".to_string()]);
1890
1891 let tool = Tool::new(
1893 "data_processor",
1894 "Processes data and returns structured output",
1895 )
1896 .with_title("Data Processor")
1897 .with_output_schema(output_schema);
1898
1899 assert_eq!(tool.name, "data_processor");
1901 assert_eq!(tool.title, Some("Data Processor".to_string()));
1902 assert!(tool.output_schema.is_some());
1903
1904 let schema = tool.output_schema.as_ref().unwrap();
1905 assert_eq!(schema.schema_type, "object");
1906 assert!(schema.properties.is_some());
1907 assert_eq!(schema.required, Some(vec!["result".to_string()]));
1908
1909 let json = serde_json::to_value(&tool).unwrap();
1911 assert_eq!(json["name"], "data_processor");
1912 assert!(json["inputSchema"].is_object());
1913 assert!(json["outputSchema"].is_object());
1914 assert_eq!(json["outputSchema"]["type"], "object");
1915 assert!(json["outputSchema"]["properties"].is_object());
1916 assert!(json["outputSchema"]["required"].is_array());
1917 }
1918
1919 #[test]
1920 fn test_server_capabilities_2025_06_18() {
1921 let caps = ServerCapabilities {
1922 tools: Some(ToolsCapability {
1923 list_changed: Some(true),
1924 }),
1925 completions: Some(CompletionsCapability::default()),
1926 logging: Some(LoggingCapability::default()),
1927 experimental: Some(HashMap::new()),
1928 ..Default::default()
1929 };
1930
1931 let json = serde_json::to_value(&caps).unwrap();
1932 assert!(json["tools"]["listChanged"].as_bool().unwrap());
1933 assert!(json["completions"].is_object());
1934 assert!(json["logging"].is_object());
1935 assert!(json["experimental"].is_object());
1936 }
1937
1938 #[test]
1939 fn test_client_capabilities_with_elicitation() {
1940 let caps = ClientCapabilities {
1941 elicitation: Some(ElicitationCapability::default()),
1942 roots: Some(RootsCapability {
1943 list_changed: Some(true),
1944 }),
1945 ..Default::default()
1946 };
1947
1948 let json = serde_json::to_value(&caps).unwrap();
1949 assert!(json["elicitation"].is_object());
1950 assert!(json["roots"]["listChanged"].as_bool().unwrap());
1951 }
1952
1953 #[test]
1954 fn test_implementation_with_title() {
1955 let impl_info = Implementation::with_title("my-server", "1.0.0", "My Awesome Server");
1956
1957 assert_eq!(impl_info.name, "my-server");
1958 assert_eq!(impl_info.version, "1.0.0");
1959 assert_eq!(impl_info.title, Some("My Awesome Server".to_string()));
1960 }
1961
1962 #[test]
1963 fn test_model_preferences_improved() {
1964 let prefs = ModelPreferences {
1965 cost_priority: Some(0.3),
1966 speed_priority: Some(0.7),
1967 intelligence_priority: Some(0.9),
1968 hints: Some(vec![ModelHint {
1969 name: Some("claude".to_string()),
1970 additional_hints: None,
1971 }]),
1972 };
1973
1974 let json = serde_json::to_value(&prefs).unwrap();
1975 assert_eq!(json["costPriority"], 0.3);
1976 assert_eq!(json["speedPriority"], 0.7);
1977 assert_eq!(json["intelligencePriority"], 0.9);
1978 assert!(json["hints"].is_array());
1979 }
1980
1981 #[test]
1982 fn test_call_tool_result_with_structured_content() {
1983 let result = CallToolResult {
1984 content: vec![ContentBlock::text("Operation completed")],
1985 is_error: Some(false),
1986 structured_content: Some(json!({"status": "success", "count": 42})),
1987 meta: None,
1988 };
1989
1990 let json = serde_json::to_value(&result).unwrap();
1991 assert!(json["content"].is_array());
1992 assert_eq!(json["isError"], false);
1993 assert_eq!(json["structuredContent"]["status"], "success");
1994 assert_eq!(json["structuredContent"]["count"], 42);
1995 }
1996
1997 #[test]
1998 fn test_sampling_content_types() {
1999 let text = SamplingContent::text("Hello");
2001 let image = SamplingContent::image("data", "image/png");
2002 let audio = SamplingContent::audio("data", "audio/wav");
2003
2004 let text_json = serde_json::to_value(&text).unwrap();
2005 let image_json = serde_json::to_value(&image).unwrap();
2006 let audio_json = serde_json::to_value(&audio).unwrap();
2007
2008 assert_eq!(text_json["type"], "text");
2009 assert_eq!(image_json["type"], "image");
2010 assert_eq!(audio_json["type"], "audio");
2011 }
2012}
2013
2014pub type JsonRpcBatchRequest = Vec<JsonRpcRequest>;
2020
2021pub type JsonRpcBatchResponse = Vec<JsonRpcResponse>;
2023
2024#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2026#[serde(untagged)]
2027pub enum JsonRpcRequestOrNotification {
2028 Request(JsonRpcRequest),
2029 Notification(JsonRpcNotification),
2030}
2031
2032#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2034#[serde(untagged)]
2035pub enum JsonRpcResponseOrError {
2036 Response(JsonRpcResponse),
2037 Error(JsonRpcError),
2038}
2039
2040#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2042pub enum AnnotationAudience {
2043 User,
2044 Developer,
2045 System,
2046}
2047
2048#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2050pub enum DangerLevel {
2051 Safe,
2052 Low,
2053 Medium,
2054 High,
2055}