1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9pub const LATEST_PROTOCOL_VERSION: &str = "2026-07-28";
15pub const JSONRPC_VERSION: &str = "2.0";
16
17pub const PROTOCOL_VERSION: &str = LATEST_PROTOCOL_VERSION;
19
20pub type ProgressToken = serde_json::Value; pub type Cursor = String;
29
30pub type RequestId = serde_json::Value; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
35#[serde(untagged)]
36pub enum JsonRpcId {
37 String(String),
38 Number(i64),
39 Null,
40}
41
42impl From<i64> for JsonRpcId {
43 fn from(value: i64) -> Self {
44 JsonRpcId::Number(value)
45 }
46}
47
48impl From<String> for JsonRpcId {
49 fn from(value: String) -> Self {
50 JsonRpcId::String(value)
51 }
52}
53
54impl From<&str> for JsonRpcId {
55 fn from(value: &str) -> Self {
56 JsonRpcId::String(value.to_string())
57 }
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
66pub struct BaseMetadata {
67 pub name: String,
69 #[serde(skip_serializing_if = "Option::is_none")]
75 pub title: Option<String>,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
80pub struct Icon {
81 pub src: String,
83 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
85 pub mime_type: Option<String>,
86 #[serde(skip_serializing_if = "Option::is_none")]
88 pub sizes: Option<Vec<String>>,
89 #[serde(skip_serializing_if = "Option::is_none")]
91 pub theme: Option<IconTheme>,
92}
93
94#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
96#[serde(rename_all = "lowercase")]
97pub enum IconTheme {
98 Light,
99 Dark,
100}
101
102#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
108pub struct Implementation {
109 pub name: String,
111 pub version: String,
113 #[serde(skip_serializing_if = "Option::is_none")]
116 pub title: Option<String>,
117 #[serde(skip_serializing_if = "Option::is_none")]
119 pub description: Option<String>,
120 #[serde(rename = "websiteUrl", skip_serializing_if = "Option::is_none")]
122 pub website_url: Option<String>,
123 #[serde(skip_serializing_if = "Option::is_none")]
125 pub icons: Option<Vec<Icon>>,
126}
127
128impl Implementation {
129 pub fn new<S: Into<String>>(name: S, version: S) -> Self {
131 Self {
132 name: name.into(),
133 version: version.into(),
134 title: None,
135 description: None,
136 website_url: None,
137 icons: None,
138 }
139 }
140
141 pub fn with_title<S: Into<String>>(name: S, version: S, title: S) -> Self {
143 Self {
144 name: name.into(),
145 version: version.into(),
146 title: Some(title.into()),
147 description: None,
148 website_url: None,
149 icons: None,
150 }
151 }
152
153 pub fn with_description<S: Into<String>>(mut self, description: S) -> Self {
155 self.description = Some(description.into());
156 self
157 }
158
159 pub fn with_website_url<S: Into<String>>(mut self, website_url: S) -> Self {
161 self.website_url = Some(website_url.into());
162 self
163 }
164
165 pub fn with_icons(mut self, icons: Vec<Icon>) -> Self {
167 self.icons = Some(icons);
168 self
169 }
170}
171
172pub type ServerInfo = Implementation;
174pub type ClientInfo = Implementation;
175
176#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
182pub struct ServerCapabilities {
183 #[serde(skip_serializing_if = "Option::is_none")]
185 pub extensions: Option<HashMap<String, serde_json::Value>>,
186 #[serde(skip_serializing_if = "Option::is_none")]
188 pub prompts: Option<PromptsCapability>,
189 #[serde(skip_serializing_if = "Option::is_none")]
191 pub resources: Option<ResourcesCapability>,
192 #[serde(skip_serializing_if = "Option::is_none")]
194 pub tools: Option<ToolsCapability>,
195 #[serde(skip_serializing_if = "Option::is_none")]
197 pub sampling: Option<SamplingCapability>,
198 #[serde(skip_serializing_if = "Option::is_none")]
200 pub logging: Option<LoggingCapability>,
201 #[serde(skip_serializing_if = "Option::is_none")]
203 pub completions: Option<CompletionsCapability>,
204 #[serde(skip_serializing_if = "Option::is_none")]
206 pub experimental: Option<HashMap<String, serde_json::Value>>,
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
211pub struct ClientCapabilities {
212 #[serde(skip_serializing_if = "Option::is_none")]
214 pub extensions: Option<HashMap<String, serde_json::Value>>,
215 #[serde(skip_serializing_if = "Option::is_none")]
217 pub sampling: Option<SamplingCapability>,
218 #[serde(skip_serializing_if = "Option::is_none")]
220 pub roots: Option<RootsCapability>,
221 #[serde(skip_serializing_if = "Option::is_none")]
223 pub elicitation: Option<ElicitationCapability>,
224 #[serde(skip_serializing_if = "Option::is_none")]
226 pub experimental: Option<HashMap<String, serde_json::Value>>,
227}
228
229#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
231pub struct PromptsCapability {
232 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
234 pub list_changed: Option<bool>,
235}
236
237#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
239pub struct ResourcesCapability {
240 #[serde(skip_serializing_if = "Option::is_none")]
242 pub subscribe: Option<bool>,
243 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
245 pub list_changed: Option<bool>,
246}
247
248#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
250pub struct ToolsCapability {
251 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
253 pub list_changed: Option<bool>,
254}
255
256#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
258pub struct SamplingCapability {
259 #[serde(flatten)]
261 pub additional_properties: HashMap<String, serde_json::Value>,
262}
263
264#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
266pub struct LoggingCapability {
267 #[serde(flatten)]
269 pub additional_properties: HashMap<String, serde_json::Value>,
270}
271
272#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
274pub struct CompletionsCapability {
275 #[serde(flatten)]
277 pub additional_properties: HashMap<String, serde_json::Value>,
278}
279
280#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
282pub struct RootsCapability {
283 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
285 pub list_changed: Option<bool>,
286}
287
288#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
290pub struct ElicitationCapability {
291 #[serde(flatten)]
293 pub additional_properties: HashMap<String, serde_json::Value>,
294}
295
296#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
302pub struct Annotations {
303 #[serde(skip_serializing_if = "Option::is_none")]
307 pub audience: Option<Vec<Role>>,
308 #[serde(skip_serializing_if = "Option::is_none")]
314 pub priority: Option<f64>,
315 #[serde(rename = "lastModified", skip_serializing_if = "Option::is_none")]
322 pub last_modified: Option<String>,
323 #[serde(skip_serializing_if = "Option::is_none")]
325 pub danger: Option<DangerLevel>,
326 #[serde(skip_serializing_if = "Option::is_none")]
328 pub destructive: Option<bool>,
329 #[serde(skip_serializing_if = "Option::is_none")]
331 pub read_only: Option<bool>,
332}
333
334#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
340pub struct TextContent {
341 #[serde(rename = "type")]
343 pub content_type: String, pub text: String,
346 #[serde(skip_serializing_if = "Option::is_none")]
348 pub annotations: Option<Annotations>,
349 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
351 pub meta: Option<HashMap<String, serde_json::Value>>,
352}
353
354#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
356pub struct ImageContent {
357 #[serde(rename = "type")]
359 pub content_type: String, pub data: String,
362 #[serde(rename = "mimeType")]
364 pub mime_type: String,
365 #[serde(skip_serializing_if = "Option::is_none")]
367 pub annotations: Option<Annotations>,
368 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
370 pub meta: Option<HashMap<String, serde_json::Value>>,
371}
372
373#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
375pub struct AudioContent {
376 #[serde(rename = "type")]
378 pub content_type: String, pub data: String,
381 #[serde(rename = "mimeType")]
383 pub mime_type: String,
384 #[serde(skip_serializing_if = "Option::is_none")]
386 pub annotations: Option<Annotations>,
387 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
389 pub meta: Option<HashMap<String, serde_json::Value>>,
390}
391
392#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
394pub struct ResourceLink {
395 #[serde(rename = "type")]
397 pub content_type: String, pub uri: String,
400 pub name: String,
402 #[serde(skip_serializing_if = "Option::is_none")]
404 pub description: Option<String>,
405 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
407 pub mime_type: Option<String>,
408 #[serde(skip_serializing_if = "Option::is_none")]
410 pub size: Option<u64>,
411 #[serde(skip_serializing_if = "Option::is_none")]
413 pub title: Option<String>,
414 #[serde(skip_serializing_if = "Option::is_none")]
416 pub annotations: Option<Annotations>,
417 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
419 pub meta: Option<HashMap<String, serde_json::Value>>,
420}
421
422#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
424pub struct EmbeddedResource {
425 #[serde(rename = "type")]
427 pub content_type: String, pub resource: ResourceContents,
430 #[serde(skip_serializing_if = "Option::is_none")]
432 pub annotations: Option<Annotations>,
433 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
435 pub meta: Option<HashMap<String, serde_json::Value>>,
436}
437
438#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
440#[serde(tag = "type")]
441pub enum ContentBlock {
442 #[serde(rename = "text")]
444 Text {
445 text: String,
447 #[serde(skip_serializing_if = "Option::is_none")]
449 annotations: Option<Annotations>,
450 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
452 meta: Option<HashMap<String, serde_json::Value>>,
453 },
454 #[serde(rename = "image")]
456 Image {
457 data: String,
459 #[serde(rename = "mimeType")]
461 mime_type: String,
462 #[serde(skip_serializing_if = "Option::is_none")]
464 annotations: Option<Annotations>,
465 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
467 meta: Option<HashMap<String, serde_json::Value>>,
468 },
469 #[serde(rename = "audio")]
471 Audio {
472 data: String,
474 #[serde(rename = "mimeType")]
476 mime_type: String,
477 #[serde(skip_serializing_if = "Option::is_none")]
479 annotations: Option<Annotations>,
480 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
482 meta: Option<HashMap<String, serde_json::Value>>,
483 },
484 #[serde(rename = "resource_link")]
486 ResourceLink {
487 uri: String,
489 name: String,
491 #[serde(skip_serializing_if = "Option::is_none")]
493 description: Option<String>,
494 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
496 mime_type: Option<String>,
497 #[serde(skip_serializing_if = "Option::is_none")]
499 size: Option<u64>,
500 #[serde(skip_serializing_if = "Option::is_none")]
502 title: Option<String>,
503 #[serde(skip_serializing_if = "Option::is_none")]
505 annotations: Option<Annotations>,
506 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
508 meta: Option<HashMap<String, serde_json::Value>>,
509 },
510 #[serde(rename = "resource")]
512 Resource {
513 resource: ResourceContents,
515 #[serde(skip_serializing_if = "Option::is_none")]
517 annotations: Option<Annotations>,
518 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
520 meta: Option<HashMap<String, serde_json::Value>>,
521 },
522}
523
524pub type Content = ContentBlock;
526
527impl ContentBlock {
532 pub fn text<S: Into<String>>(text: S) -> Self {
534 ContentBlock::Text {
535 text: text.into(),
536 annotations: None,
537 meta: None,
538 }
539 }
540
541 pub fn text_with_annotations<S: Into<String>>(text: S, annotations: Annotations) -> Self {
543 ContentBlock::Text {
544 text: text.into(),
545 annotations: Some(annotations),
546 meta: None,
547 }
548 }
549
550 pub fn image<S: Into<String>>(data: S, mime_type: S) -> Self {
552 ContentBlock::Image {
553 data: data.into(),
554 mime_type: mime_type.into(),
555 annotations: None,
556 meta: None,
557 }
558 }
559
560 pub fn audio<S: Into<String>>(data: S, mime_type: S) -> Self {
562 ContentBlock::Audio {
563 data: data.into(),
564 mime_type: mime_type.into(),
565 annotations: None,
566 meta: None,
567 }
568 }
569
570 pub fn resource_link<S: Into<String>>(uri: S, name: S) -> Self {
572 ContentBlock::ResourceLink {
573 uri: uri.into(),
574 name: name.into(),
575 description: None,
576 mime_type: None,
577 size: None,
578 title: None,
579 annotations: None,
580 meta: None,
581 }
582 }
583
584 pub fn embedded_resource(resource: ResourceContents) -> Self {
586 ContentBlock::Resource {
587 resource,
588 annotations: None,
589 meta: None,
590 }
591 }
592
593 pub fn resource<S: Into<String>>(uri: S) -> Self {
595 let uri_str = uri.into();
598 ContentBlock::ResourceLink {
599 uri: uri_str.clone(),
600 name: uri_str,
601 description: None,
602 mime_type: None,
603 size: None,
604 title: None,
605 annotations: None,
606 meta: None,
607 }
608 }
609}
610
611#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
624pub struct ToolAnnotations {
625 #[serde(skip_serializing_if = "Option::is_none")]
627 pub title: Option<String>,
628
629 #[serde(rename = "readOnlyHint", skip_serializing_if = "Option::is_none")]
632 pub read_only_hint: Option<bool>,
633
634 #[serde(rename = "destructiveHint", skip_serializing_if = "Option::is_none")]
639 pub destructive_hint: Option<bool>,
640
641 #[serde(rename = "idempotentHint", skip_serializing_if = "Option::is_none")]
646 pub idempotent_hint: Option<bool>,
647
648 #[serde(rename = "openWorldHint", skip_serializing_if = "Option::is_none")]
654 pub open_world_hint: Option<bool>,
655}
656
657impl ToolAnnotations {
658 pub fn new() -> Self {
660 Self::default()
661 }
662
663 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
665 self.title = Some(title.into());
666 self
667 }
668
669 pub fn read_only(mut self) -> Self {
671 self.read_only_hint = Some(true);
672 self
673 }
674
675 pub fn destructive(mut self) -> Self {
677 self.destructive_hint = Some(true);
678 self
679 }
680
681 pub fn idempotent(mut self) -> Self {
683 self.idempotent_hint = Some(true);
684 self
685 }
686
687 pub fn open_world(mut self) -> Self {
689 self.open_world_hint = Some(true);
690 self
691 }
692
693 pub fn closed_world(mut self) -> Self {
695 self.open_world_hint = Some(false);
696 self
697 }
698}
699
700impl From<&crate::core::tool_metadata::ToolBehaviorHints> for ToolAnnotations {
705 fn from(hints: &crate::core::tool_metadata::ToolBehaviorHints) -> Self {
706 Self {
707 title: None, read_only_hint: hints.read_only,
709 destructive_hint: hints.destructive,
710 idempotent_hint: hints.idempotent,
711 open_world_hint: if hints.requires_auth.unwrap_or(false)
713 || hints.resource_intensive.unwrap_or(false)
714 {
715 Some(true)
716 } else {
717 None
718 },
719 }
720 }
721}
722
723impl From<&crate::core::tool_metadata::ImprovedToolMetadata> for ToolAnnotations {
724 fn from(metadata: &crate::core::tool_metadata::ImprovedToolMetadata) -> Self {
725 ToolAnnotations::from(&metadata.behavior_hints)
726 }
727}
728
729impl ToolAnnotations {
730 pub fn from_improved_metadata(
732 metadata: &crate::core::tool_metadata::ImprovedToolMetadata,
733 title_override: Option<String>,
734 ) -> Self {
735 let mut annotations = Self::from(metadata);
736 if let Some(title) = title_override {
737 annotations.title = Some(title);
738 }
739 annotations
740 }
741
742 pub fn from_behavior_hints(hints: &crate::core::tool_metadata::ToolBehaviorHints) -> Self {
744 Self::from(hints)
745 }
746}
747
748#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
750pub struct Tool {
751 pub name: String,
753 #[serde(skip_serializing_if = "Option::is_none")]
755 pub description: Option<String>,
756 #[serde(rename = "inputSchema")]
758 pub input_schema: ToolInputSchema,
759 #[serde(rename = "outputSchema", skip_serializing_if = "Option::is_none")]
762 pub output_schema: Option<ToolOutputSchema>,
763 #[serde(skip_serializing_if = "Option::is_none")]
765 pub annotations: Option<ToolAnnotations>,
766 #[serde(skip_serializing_if = "Option::is_none")]
768 pub title: Option<String>,
769 #[serde(skip_serializing_if = "Option::is_none")]
771 pub icons: Option<Vec<Icon>>,
772 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
774 pub meta: Option<HashMap<String, serde_json::Value>>,
775}
776
777#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
779pub struct ToolInputSchema {
780 #[serde(rename = "type")]
782 pub schema_type: String,
783 #[serde(skip_serializing_if = "Option::is_none")]
785 pub properties: Option<HashMap<String, serde_json::Value>>,
786 #[serde(skip_serializing_if = "Option::is_none")]
788 pub required: Option<Vec<String>>,
789 #[serde(flatten)]
791 pub additional_properties: HashMap<String, serde_json::Value>,
792}
793
794#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
796pub struct ToolOutputSchema {
797 #[serde(rename = "type")]
799 pub schema_type: String,
800 #[serde(skip_serializing_if = "Option::is_none")]
802 pub properties: Option<HashMap<String, serde_json::Value>>,
803 #[serde(skip_serializing_if = "Option::is_none")]
805 pub required: Option<Vec<String>>,
806}
807
808impl ToolOutputSchema {
809 pub fn new() -> Self {
811 Self {
812 schema_type: "object".to_string(),
813 properties: None,
814 required: None,
815 }
816 }
817
818 pub fn with_properties(properties: HashMap<String, serde_json::Value>) -> Self {
820 Self {
821 schema_type: "object".to_string(),
822 properties: Some(properties),
823 required: None,
824 }
825 }
826
827 pub fn with_required(mut self, required: Vec<String>) -> Self {
829 self.required = Some(required);
830 self
831 }
832
833 pub fn with_properties_map(mut self, properties: HashMap<String, serde_json::Value>) -> Self {
835 self.properties = Some(properties);
836 self
837 }
838}
839
840impl Default for ToolOutputSchema {
841 fn default() -> Self {
842 Self::new()
843 }
844}
845
846#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
848pub struct CallToolResult {
849 pub content: Vec<ContentBlock>,
851 #[serde(rename = "isError", skip_serializing_if = "Option::is_none")]
853 pub is_error: Option<bool>,
854 #[serde(rename = "structuredContent", skip_serializing_if = "Option::is_none")]
856 pub structured_content: Option<serde_json::Value>,
857 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
859 pub meta: Option<HashMap<String, serde_json::Value>>,
860}
861
862impl CallToolResult {
867 pub fn text<S: Into<String>>(text: S) -> Self {
869 Self {
870 content: vec![ContentBlock::text(text)],
871 is_error: Some(false),
872 structured_content: None,
873 meta: None,
874 }
875 }
876
877 pub fn error<S: Into<String>>(message: S) -> Self {
879 Self {
880 content: vec![ContentBlock::text(message)],
881 is_error: Some(true),
882 structured_content: None,
883 meta: None,
884 }
885 }
886
887 pub fn with_content(content: Vec<ContentBlock>) -> Self {
889 Self {
890 content,
891 is_error: Some(false),
892 structured_content: None,
893 meta: None,
894 }
895 }
896
897 pub fn with_structured(content: Vec<ContentBlock>, structured: serde_json::Value) -> Self {
899 Self {
900 content,
901 is_error: Some(false),
902 structured_content: Some(structured),
903 meta: None,
904 }
905 }
906}
907
908pub type ToolInfo = Tool;
910pub type ToolResult = CallToolResult;
911
912#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
921pub struct Resource {
922 pub uri: String,
924 pub name: String,
926 #[serde(skip_serializing_if = "Option::is_none")]
928 pub description: Option<String>,
929 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
931 pub mime_type: Option<String>,
932 #[serde(skip_serializing_if = "Option::is_none")]
934 pub annotations: Option<Annotations>,
935 #[serde(skip_serializing_if = "Option::is_none")]
937 pub size: Option<u64>,
938 #[serde(skip_serializing_if = "Option::is_none")]
940 pub title: Option<String>,
941 #[serde(skip_serializing_if = "Option::is_none")]
943 pub icons: Option<Vec<Icon>>,
944 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
946 pub meta: Option<HashMap<String, serde_json::Value>>,
947}
948
949#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
951pub struct ResourceTemplate {
952 #[serde(rename = "uriTemplate")]
954 pub uri_template: String,
955 pub name: String,
957 #[serde(skip_serializing_if = "Option::is_none")]
959 pub description: Option<String>,
960 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
962 pub mime_type: Option<String>,
963 #[serde(skip_serializing_if = "Option::is_none")]
965 pub annotations: Option<Annotations>,
966 #[serde(skip_serializing_if = "Option::is_none")]
968 pub title: Option<String>,
969 #[serde(skip_serializing_if = "Option::is_none")]
971 pub icons: Option<Vec<Icon>>,
972 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
974 pub meta: Option<HashMap<String, serde_json::Value>>,
975}
976
977#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
979#[serde(untagged)]
980pub enum ResourceContents {
981 Text {
983 uri: String,
985 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
987 mime_type: Option<String>,
988 text: String,
990 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
992 meta: Option<HashMap<String, serde_json::Value>>,
993 },
994 Blob {
996 uri: String,
998 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
1000 mime_type: Option<String>,
1001 blob: String,
1003 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1005 meta: Option<HashMap<String, serde_json::Value>>,
1006 },
1007}
1008
1009impl ResourceContents {
1010 pub fn uri(&self) -> &str {
1012 match self {
1013 ResourceContents::Text { uri, .. } => uri,
1014 ResourceContents::Blob { uri, .. } => uri,
1015 }
1016 }
1017}
1018
1019pub type ResourceInfo = Resource;
1021
1022#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1028pub struct Prompt {
1029 pub name: String,
1031 #[serde(skip_serializing_if = "Option::is_none")]
1033 pub description: Option<String>,
1034 #[serde(skip_serializing_if = "Option::is_none")]
1036 pub arguments: Option<Vec<PromptArgument>>,
1037 #[serde(skip_serializing_if = "Option::is_none")]
1039 pub title: Option<String>,
1040 #[serde(skip_serializing_if = "Option::is_none")]
1042 pub icons: Option<Vec<Icon>>,
1043 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1045 pub meta: Option<HashMap<String, serde_json::Value>>,
1046}
1047
1048#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1050pub struct PromptArgument {
1051 pub name: String,
1053 #[serde(skip_serializing_if = "Option::is_none")]
1055 pub description: Option<String>,
1056 #[serde(skip_serializing_if = "Option::is_none")]
1058 pub required: Option<bool>,
1059 #[serde(skip_serializing_if = "Option::is_none")]
1061 pub title: Option<String>,
1062}
1063
1064#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1066#[serde(rename_all = "lowercase")]
1067pub enum Role {
1068 User,
1069 Assistant,
1070}
1071
1072#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1074pub struct PromptMessage {
1075 pub role: Role,
1077 pub content: ContentBlock,
1079}
1080
1081#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1083pub struct GetPromptResult {
1084 #[serde(skip_serializing_if = "Option::is_none")]
1086 pub description: Option<String>,
1087 pub messages: Vec<PromptMessage>,
1089 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1091 pub meta: Option<HashMap<String, serde_json::Value>>,
1092}
1093
1094pub type PromptInfo = Prompt;
1096pub type PromptResult = GetPromptResult;
1097
1098#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1104pub struct SamplingMessage {
1105 pub role: Role,
1107 pub content: SamplingContent,
1109}
1110
1111#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1113#[serde(tag = "type")]
1114pub enum SamplingContent {
1115 #[serde(rename = "text")]
1117 Text {
1118 text: String,
1120 #[serde(skip_serializing_if = "Option::is_none")]
1122 annotations: Option<Annotations>,
1123 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1125 meta: Option<HashMap<String, serde_json::Value>>,
1126 },
1127 #[serde(rename = "image")]
1129 Image {
1130 data: String,
1132 #[serde(rename = "mimeType")]
1134 mime_type: String,
1135 #[serde(skip_serializing_if = "Option::is_none")]
1137 annotations: Option<Annotations>,
1138 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1140 meta: Option<HashMap<String, serde_json::Value>>,
1141 },
1142 #[serde(rename = "audio")]
1144 Audio {
1145 data: String,
1147 #[serde(rename = "mimeType")]
1149 mime_type: String,
1150 #[serde(skip_serializing_if = "Option::is_none")]
1152 annotations: Option<Annotations>,
1153 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1155 meta: Option<HashMap<String, serde_json::Value>>,
1156 },
1157}
1158
1159#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1161pub struct ModelHint {
1162 #[serde(skip_serializing_if = "Option::is_none")]
1169 pub name: Option<String>,
1170
1171 #[serde(flatten)]
1175 pub additional_hints: Option<HashMap<String, serde_json::Value>>,
1176}
1177
1178#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
1180pub struct ModelPreferences {
1181 #[serde(rename = "costPriority", skip_serializing_if = "Option::is_none")]
1183 pub cost_priority: Option<f64>,
1184 #[serde(rename = "speedPriority", skip_serializing_if = "Option::is_none")]
1186 pub speed_priority: Option<f64>,
1187 #[serde(
1189 rename = "intelligencePriority",
1190 skip_serializing_if = "Option::is_none"
1191 )]
1192 pub intelligence_priority: Option<f64>,
1193 #[serde(skip_serializing_if = "Option::is_none")]
1195 pub hints: Option<Vec<ModelHint>>,
1196}
1197
1198#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1200#[serde(tag = "type", rename_all = "camelCase")]
1201pub enum SamplingToolChoice {
1202 None,
1203 Auto,
1204 Required,
1205 Tool { name: String },
1206}
1207
1208#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1210pub struct CreateMessageResult {
1211 pub role: Role,
1213 pub content: SamplingContent,
1215 pub model: String,
1217 #[serde(rename = "stopReason", skip_serializing_if = "Option::is_none")]
1219 pub stop_reason: Option<StopReason>,
1220 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1222 pub meta: Option<HashMap<String, serde_json::Value>>,
1223}
1224
1225#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1227#[serde(rename_all = "camelCase")]
1228pub enum StopReason {
1229 EndTurn,
1230 StopSequence,
1231 MaxTokens,
1232 ToolCall,
1233 #[serde(untagged)]
1234 Other(String),
1235}
1236
1237#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1243#[serde(tag = "type")]
1244pub enum PrimitiveSchemaDefinition {
1245 #[serde(rename = "string")]
1246 String {
1247 #[serde(skip_serializing_if = "Option::is_none")]
1248 title: Option<String>,
1249 #[serde(skip_serializing_if = "Option::is_none")]
1250 description: Option<String>,
1251 #[serde(rename = "minLength", skip_serializing_if = "Option::is_none")]
1252 min_length: Option<u32>,
1253 #[serde(rename = "maxLength", skip_serializing_if = "Option::is_none")]
1254 max_length: Option<u32>,
1255 #[serde(skip_serializing_if = "Option::is_none")]
1256 format: Option<String>,
1257 #[serde(rename = "enum", skip_serializing_if = "Option::is_none")]
1258 enum_values: Option<Vec<String>>,
1259 #[serde(rename = "enumNames", skip_serializing_if = "Option::is_none")]
1260 enum_names: Option<Vec<String>>,
1261 },
1262 #[serde(rename = "number")]
1263 Number {
1264 #[serde(skip_serializing_if = "Option::is_none")]
1265 title: Option<String>,
1266 #[serde(skip_serializing_if = "Option::is_none")]
1267 description: Option<String>,
1268 #[serde(skip_serializing_if = "Option::is_none")]
1269 minimum: Option<i32>,
1270 #[serde(skip_serializing_if = "Option::is_none")]
1271 maximum: Option<i32>,
1272 },
1273 #[serde(rename = "integer")]
1274 Integer {
1275 #[serde(skip_serializing_if = "Option::is_none")]
1276 title: Option<String>,
1277 #[serde(skip_serializing_if = "Option::is_none")]
1278 description: Option<String>,
1279 #[serde(skip_serializing_if = "Option::is_none")]
1280 minimum: Option<i32>,
1281 #[serde(skip_serializing_if = "Option::is_none")]
1282 maximum: Option<i32>,
1283 },
1284 #[serde(rename = "boolean")]
1285 Boolean {
1286 #[serde(skip_serializing_if = "Option::is_none")]
1287 title: Option<String>,
1288 #[serde(skip_serializing_if = "Option::is_none")]
1289 description: Option<String>,
1290 #[serde(skip_serializing_if = "Option::is_none")]
1291 default: Option<bool>,
1292 },
1293}
1294
1295#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1297pub struct ElicitationSchema {
1298 #[serde(rename = "type")]
1300 pub schema_type: String,
1301 pub properties: HashMap<String, PrimitiveSchemaDefinition>,
1303 #[serde(skip_serializing_if = "Option::is_none")]
1305 pub required: Option<Vec<String>>,
1306}
1307
1308#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1310#[serde(rename_all = "lowercase")]
1311pub enum ElicitationAction {
1312 Accept,
1314 Decline,
1316 Cancel,
1318}
1319
1320#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1326#[serde(rename_all = "lowercase")]
1327pub enum LoggingLevel {
1328 Debug,
1329 Info,
1330 Notice,
1331 Warning,
1332 Error,
1333 Critical,
1334 Alert,
1335 Emergency,
1336}
1337
1338#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1344pub struct JsonRpcRequest {
1345 pub jsonrpc: String,
1347 pub id: RequestId,
1349 pub method: String,
1351 #[serde(skip_serializing_if = "Option::is_none")]
1353 pub params: Option<serde_json::Value>,
1354}
1355
1356#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1358pub struct JsonRpcResponse {
1359 pub jsonrpc: String,
1361 pub id: RequestId,
1363 #[serde(skip_serializing_if = "Option::is_none")]
1365 pub result: Option<serde_json::Value>,
1366}
1367
1368#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1370pub struct JsonRpcError {
1371 pub jsonrpc: String,
1373 pub id: RequestId,
1375 pub error: ErrorObject,
1377}
1378
1379#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1381pub struct ErrorObject {
1382 pub code: i32,
1384 pub message: String,
1386 #[serde(skip_serializing_if = "Option::is_none")]
1388 pub data: Option<serde_json::Value>,
1389}
1390
1391#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1393pub struct JsonRpcNotification {
1394 pub jsonrpc: String,
1396 pub method: String,
1398 #[serde(skip_serializing_if = "Option::is_none")]
1400 pub params: Option<serde_json::Value>,
1401}
1402
1403#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1405#[serde(untagged)]
1406pub enum JsonRpcMessage {
1407 Request(JsonRpcRequest),
1408 Response(JsonRpcResponse),
1409 Error(JsonRpcError),
1410 Notification(JsonRpcNotification),
1411}
1412
1413#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1419pub struct Request {
1420 pub method: String,
1422 #[serde(skip_serializing_if = "Option::is_none")]
1424 pub params: Option<RequestParams>,
1425}
1426
1427#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1429pub struct RequestParams {
1430 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1432 pub meta: Option<RequestMeta>,
1433 #[serde(flatten)]
1435 pub params: HashMap<String, serde_json::Value>,
1436}
1437
1438#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1440pub struct RequestMeta {
1441 #[serde(rename = "progressToken", skip_serializing_if = "Option::is_none")]
1443 pub progress_token: Option<ProgressToken>,
1444}
1445
1446#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1448pub struct Notification {
1449 pub method: String,
1451 #[serde(skip_serializing_if = "Option::is_none")]
1453 pub params: Option<NotificationParams>,
1454}
1455
1456#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1458pub struct NotificationParams {
1459 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1461 pub meta: Option<HashMap<String, serde_json::Value>>,
1462 #[serde(flatten)]
1464 pub params: HashMap<String, serde_json::Value>,
1465}
1466
1467#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1473pub struct PaginatedRequest {
1474 #[serde(skip_serializing_if = "Option::is_none")]
1476 pub cursor: Option<Cursor>,
1477}
1478
1479#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1481pub struct PaginatedResult {
1482 #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
1484 pub next_cursor: Option<Cursor>,
1485}
1486
1487impl SamplingContent {
1490 pub fn text<S: Into<String>>(text: S) -> Self {
1492 Self::Text {
1493 text: text.into(),
1494 annotations: None,
1495 meta: None,
1496 }
1497 }
1498
1499 pub fn image<S: Into<String>>(data: S, mime_type: S) -> Self {
1501 Self::Image {
1502 data: data.into(),
1503 mime_type: mime_type.into(),
1504 annotations: None,
1505 meta: None,
1506 }
1507 }
1508
1509 pub fn audio<S: Into<String>>(data: S, mime_type: S) -> Self {
1511 Self::Audio {
1512 data: data.into(),
1513 mime_type: mime_type.into(),
1514 annotations: None,
1515 meta: None,
1516 }
1517 }
1518}
1519
1520impl Annotations {
1521 pub fn new() -> Self {
1523 Self {
1524 audience: None,
1525 priority: None,
1526 last_modified: None,
1527 danger: None,
1528 destructive: None,
1529 read_only: None,
1530 }
1531 }
1532
1533 pub fn with_priority(mut self, priority: f64) -> Self {
1535 self.priority = Some(priority.clamp(0.0, 1.0));
1536 self
1537 }
1538
1539 pub fn for_audience(mut self, audience: Vec<Role>) -> Self {
1541 self.audience = Some(audience);
1542 self
1543 }
1544
1545 pub fn with_last_modified<S: Into<String>>(mut self, timestamp: S) -> Self {
1547 self.last_modified = Some(timestamp.into());
1548 self
1549 }
1550
1551 pub fn for_audience_legacy(self, _audience: Vec<AnnotationAudience>) -> Self {
1553 self
1555 }
1556
1557 pub fn with_danger_level(mut self, level: DangerLevel) -> Self {
1559 self.danger = Some(level);
1561 self
1562 }
1563
1564 pub fn danger(&self) -> Option<DangerLevel> {
1566 None
1567 }
1568
1569 pub fn audience(&self) -> Option<Vec<AnnotationAudience>> {
1571 None
1572 }
1573
1574 pub fn read_only(mut self) -> Self {
1576 self.read_only = Some(true);
1577 self.destructive = Some(false);
1578 self
1579 }
1580
1581 pub fn destructive(mut self, level: DangerLevel) -> Self {
1583 self.destructive = Some(true);
1584 self.read_only = Some(false);
1585 self.danger = Some(level);
1586 self
1587 }
1588}
1589
1590impl Tool {
1591 pub fn new<S: Into<String>>(name: S, description: S) -> Self {
1593 Self {
1594 name: name.into(),
1595 description: Some(description.into()),
1596 input_schema: ToolInputSchema {
1597 schema_type: "object".to_string(),
1598 properties: None,
1599 required: None,
1600 additional_properties: HashMap::new(),
1601 },
1602 output_schema: None,
1603 annotations: None,
1604 title: None,
1605 icons: None,
1606 meta: None,
1607 }
1608 }
1609
1610 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1612 self.title = Some(title.into());
1613 self
1614 }
1615
1616 pub fn with_annotations(mut self, annotations: ToolAnnotations) -> Self {
1618 self.annotations = Some(annotations);
1619 self
1620 }
1621
1622 pub fn with_output_schema(mut self, output_schema: ToolOutputSchema) -> Self {
1624 self.output_schema = Some(output_schema);
1625 self
1626 }
1627
1628 pub fn with_icons(mut self, icons: Vec<Icon>) -> Self {
1630 self.icons = Some(icons);
1631 self
1632 }
1633}
1634
1635impl Resource {
1636 pub fn new<S: Into<String>>(uri: S, name: S) -> Self {
1638 Self {
1639 uri: uri.into(),
1640 name: name.into(),
1641 description: None,
1642 mime_type: None,
1643 annotations: None,
1644 size: None,
1645 title: None,
1646 icons: None,
1647 meta: None,
1648 }
1649 }
1650
1651 pub fn from_legacy<S: Into<String>>(uri: S, name: Option<S>) -> Self {
1653 Self {
1654 uri: uri.into(),
1655 name: name
1656 .map(|n| n.into())
1657 .unwrap_or_else(|| "Unnamed Resource".to_string()),
1658 description: None,
1659 mime_type: None,
1660 annotations: None,
1661 size: None,
1662 title: None,
1663 icons: None,
1664 meta: None,
1665 }
1666 }
1667
1668 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1670 self.title = Some(title.into());
1671 self
1672 }
1673
1674 pub fn with_description<S: Into<String>>(mut self, description: S) -> Self {
1676 self.description = Some(description.into());
1677 self
1678 }
1679
1680 pub fn with_icons(mut self, icons: Vec<Icon>) -> Self {
1682 self.icons = Some(icons);
1683 self
1684 }
1685}
1686
1687impl ResourceTemplate {
1688 pub fn new<S: Into<String>>(uri_template: S, name: S) -> Self {
1690 Self {
1691 uri_template: uri_template.into(),
1692 name: name.into(),
1693 description: None,
1694 mime_type: None,
1695 annotations: None,
1696 title: None,
1697 icons: None,
1698 meta: None,
1699 }
1700 }
1701
1702 pub fn from_legacy<S: Into<String>>(uri_template: S, name: Option<S>) -> Self {
1704 Self {
1705 uri_template: uri_template.into(),
1706 name: name
1707 .map(|n| n.into())
1708 .unwrap_or_else(|| "Unnamed Template".to_string()),
1709 description: None,
1710 mime_type: None,
1711 annotations: None,
1712 title: None,
1713 icons: None,
1714 meta: None,
1715 }
1716 }
1717
1718 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1720 self.title = Some(title.into());
1721 self
1722 }
1723
1724 pub fn with_icons(mut self, icons: Vec<Icon>) -> Self {
1726 self.icons = Some(icons);
1727 self
1728 }
1729}
1730
1731impl Prompt {
1732 pub fn new<S: Into<String>>(name: S) -> Self {
1734 Self {
1735 name: name.into(),
1736 description: None,
1737 arguments: None,
1738 title: None,
1739 icons: None,
1740 meta: None,
1741 }
1742 }
1743
1744 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1746 self.title = Some(title.into());
1747 self
1748 }
1749
1750 pub fn with_description<S: Into<String>>(mut self, description: S) -> Self {
1752 self.description = Some(description.into());
1753 self
1754 }
1755
1756 pub fn with_icons(mut self, icons: Vec<Icon>) -> Self {
1758 self.icons = Some(icons);
1759 self
1760 }
1761}
1762
1763impl PromptArgument {
1764 pub fn new<S: Into<String>>(name: S) -> Self {
1766 Self {
1767 name: name.into(),
1768 description: None,
1769 required: None,
1770 title: None,
1771 }
1772 }
1773
1774 pub fn with_title<S: Into<String>>(mut self, title: S) -> Self {
1776 self.title = Some(title.into());
1777 self
1778 }
1779
1780 pub fn required(mut self, required: bool) -> Self {
1782 self.required = Some(required);
1783 self
1784 }
1785}
1786
1787impl JsonRpcRequest {
1788 pub fn new<T: Serialize>(
1790 id: RequestId,
1791 method: String,
1792 params: Option<T>,
1793 ) -> std::result::Result<Self, serde_json::Error> {
1794 let params = match params {
1795 Some(p) => Some(serde_json::to_value(p)?),
1796 None => None,
1797 };
1798
1799 Ok(Self {
1800 jsonrpc: JSONRPC_VERSION.to_string(),
1801 id,
1802 method,
1803 params,
1804 })
1805 }
1806}
1807
1808impl JsonRpcResponse {
1809 pub fn success<T: Serialize>(
1811 id: RequestId,
1812 result: T,
1813 ) -> std::result::Result<Self, serde_json::Error> {
1814 Ok(Self {
1815 jsonrpc: JSONRPC_VERSION.to_string(),
1816 id,
1817 result: Some(serde_json::to_value(result)?),
1818 })
1819 }
1820
1821 pub fn success_unchecked(id: RequestId, result: serde_json::Value) -> Self {
1824 Self {
1825 jsonrpc: JSONRPC_VERSION.to_string(),
1826 id,
1827 result: Some(result),
1828 }
1829 }
1830}
1831
1832impl JsonRpcError {
1833 pub fn error(
1835 id: RequestId,
1836 code: i32,
1837 message: String,
1838 data: Option<serde_json::Value>,
1839 ) -> Self {
1840 Self {
1841 jsonrpc: JSONRPC_VERSION.to_string(),
1842 id,
1843 error: ErrorObject {
1844 code,
1845 message,
1846 data,
1847 },
1848 }
1849 }
1850}
1851
1852impl JsonRpcNotification {
1853 pub fn new<T: Serialize>(
1855 method: String,
1856 params: Option<T>,
1857 ) -> std::result::Result<Self, serde_json::Error> {
1858 let params = match params {
1859 Some(p) => Some(serde_json::to_value(p)?),
1860 None => None,
1861 };
1862
1863 Ok(Self {
1864 jsonrpc: JSONRPC_VERSION.to_string(),
1865 method,
1866 params,
1867 })
1868 }
1869}
1870
1871impl SamplingMessage {
1872 pub fn user_text<S: Into<String>>(text: S) -> Self {
1874 Self {
1875 role: Role::User,
1876 content: SamplingContent::text(text),
1877 }
1878 }
1879
1880 pub fn assistant_text<S: Into<String>>(text: S) -> Self {
1882 Self {
1883 role: Role::Assistant,
1884 content: SamplingContent::text(text),
1885 }
1886 }
1887
1888 pub fn user_image<S: Into<String>>(data: S, mime_type: S) -> Self {
1890 Self {
1891 role: Role::User,
1892 content: SamplingContent::image(data, mime_type),
1893 }
1894 }
1895
1896 pub fn user_audio<S: Into<String>>(data: S, mime_type: S) -> Self {
1898 Self {
1899 role: Role::User,
1900 content: SamplingContent::audio(data, mime_type),
1901 }
1902 }
1903}
1904
1905pub mod error_codes {
1911 pub const PARSE_ERROR: i32 = -32700;
1913 pub const INVALID_REQUEST: i32 = -32600;
1915 pub const METHOD_NOT_FOUND: i32 = -32601;
1917 pub const INVALID_PARAMS: i32 = -32602;
1919 pub const INTERNAL_ERROR: i32 = -32603;
1921
1922 pub const TOOL_NOT_FOUND: i32 = -32000;
1924 pub const RESOURCE_NOT_FOUND: i32 = -32001;
1925 pub const PROMPT_NOT_FOUND: i32 = -32002;
1926}
1927
1928#[cfg(test)]
1929mod tests {
1930 use super::*;
1931 use serde_json::json;
1932
1933 #[test]
1934 fn test_protocol_version() {
1935 assert_eq!(LATEST_PROTOCOL_VERSION, "2026-07-28");
1936 assert_eq!(JSONRPC_VERSION, "2.0");
1937 }
1938
1939 #[test]
1940 fn test_content_block_types() {
1941 let text = ContentBlock::text("Hello, world!");
1943 let json = serde_json::to_value(&text).unwrap();
1944 assert_eq!(json["type"], "text");
1945 assert_eq!(json["text"], "Hello, world!");
1946
1947 let audio = ContentBlock::audio("base64data", "audio/wav");
1949 let json = serde_json::to_value(&audio).unwrap();
1950 assert_eq!(json["type"], "audio");
1951 assert_eq!(json["data"], "base64data");
1952 assert_eq!(json["mimeType"], "audio/wav");
1953
1954 let resource_link = ContentBlock::resource_link("file:///test.txt", "test file");
1956 let json = serde_json::to_value(&resource_link).unwrap();
1957 assert_eq!(json["type"], "resource_link");
1958 assert_eq!(json["uri"], "file:///test.txt");
1959 assert_eq!(json["name"], "test file");
1960 }
1961
1962 #[test]
1963 fn test_annotations() {
1964 let annotations = Annotations::new()
1965 .with_priority(0.8)
1966 .for_audience(vec![Role::User, Role::Assistant])
1967 .with_last_modified("2025-01-12T15:00:58Z");
1968
1969 assert_eq!(annotations.priority, Some(0.8));
1970 assert_eq!(
1971 annotations.audience,
1972 Some(vec![Role::User, Role::Assistant])
1973 );
1974 assert_eq!(
1975 annotations.last_modified,
1976 Some("2025-01-12T15:00:58Z".to_string())
1977 );
1978 }
1979
1980 #[test]
1981 fn test_tool_with_title() {
1982 let tool = Tool::new("file_reader", "Read files safely")
1983 .with_title("File Reader Tool")
1984 .with_annotations(ToolAnnotations::new().with_title("File Reader"));
1985
1986 assert_eq!(tool.name, "file_reader");
1987 assert_eq!(tool.title, Some("File Reader Tool".to_string()));
1988 assert!(tool.annotations.is_some());
1989 assert_eq!(
1990 tool.annotations.unwrap().title,
1991 Some("File Reader".to_string())
1992 );
1993 }
1994
1995 #[test]
1996 fn test_tool_with_output_schema() {
1997 use serde_json::json;
1998
1999 let output_schema = ToolOutputSchema::with_properties(HashMap::from([
2001 ("result".to_string(), json!({"type": "string"})),
2002 ("count".to_string(), json!({"type": "number"})),
2003 ]))
2004 .with_required(vec!["result".to_string()]);
2005
2006 let tool = Tool::new(
2008 "data_processor",
2009 "Processes data and returns structured output",
2010 )
2011 .with_title("Data Processor")
2012 .with_output_schema(output_schema);
2013
2014 assert_eq!(tool.name, "data_processor");
2016 assert_eq!(tool.title, Some("Data Processor".to_string()));
2017 assert!(tool.output_schema.is_some());
2018
2019 let schema = tool.output_schema.as_ref().unwrap();
2020 assert_eq!(schema.schema_type, "object");
2021 assert!(schema.properties.is_some());
2022 assert_eq!(schema.required, Some(vec!["result".to_string()]));
2023
2024 let json = serde_json::to_value(&tool).unwrap();
2026 assert_eq!(json["name"], "data_processor");
2027 assert!(json["inputSchema"].is_object());
2028 assert!(json["outputSchema"].is_object());
2029 assert_eq!(json["outputSchema"]["type"], "object");
2030 assert!(json["outputSchema"]["properties"].is_object());
2031 assert!(json["outputSchema"]["required"].is_array());
2032 }
2033
2034 #[test]
2035 fn test_server_capabilities_2025_06_18() {
2036 let caps = ServerCapabilities {
2037 tools: Some(ToolsCapability {
2038 list_changed: Some(true),
2039 }),
2040 completions: Some(CompletionsCapability::default()),
2041 logging: Some(LoggingCapability::default()),
2042 experimental: Some(HashMap::new()),
2043 ..Default::default()
2044 };
2045
2046 let json = serde_json::to_value(&caps).unwrap();
2047 assert!(json["tools"]["listChanged"].as_bool().unwrap());
2048 assert!(json["completions"].is_object());
2049 assert!(json["logging"].is_object());
2050 assert!(json["experimental"].is_object());
2051 }
2052
2053 #[test]
2054 fn test_client_capabilities_with_elicitation() {
2055 let caps = ClientCapabilities {
2056 elicitation: Some(ElicitationCapability::default()),
2057 roots: Some(RootsCapability {
2058 list_changed: Some(true),
2059 }),
2060 ..Default::default()
2061 };
2062
2063 let json = serde_json::to_value(&caps).unwrap();
2064 assert!(json["elicitation"].is_object());
2065 assert!(json["roots"]["listChanged"].as_bool().unwrap());
2066 }
2067
2068 #[test]
2069 fn test_implementation_with_title() {
2070 let impl_info = Implementation::with_title("my-server", "1.0.0", "My Awesome Server");
2071
2072 assert_eq!(impl_info.name, "my-server");
2073 assert_eq!(impl_info.version, "1.0.0");
2074 assert_eq!(impl_info.title, Some("My Awesome Server".to_string()));
2075 }
2076
2077 #[test]
2078 fn test_model_preferences_improved() {
2079 let prefs = ModelPreferences {
2080 cost_priority: Some(0.3),
2081 speed_priority: Some(0.7),
2082 intelligence_priority: Some(0.9),
2083 hints: Some(vec![ModelHint {
2084 name: Some("claude".to_string()),
2085 additional_hints: None,
2086 }]),
2087 };
2088
2089 let json = serde_json::to_value(&prefs).unwrap();
2090 assert_eq!(json["costPriority"], 0.3);
2091 assert_eq!(json["speedPriority"], 0.7);
2092 assert_eq!(json["intelligencePriority"], 0.9);
2093 assert!(json["hints"].is_array());
2094 }
2095
2096 #[test]
2097 fn test_call_tool_result_with_structured_content() {
2098 let result = CallToolResult {
2099 content: vec![ContentBlock::text("Operation completed")],
2100 is_error: Some(false),
2101 structured_content: Some(json!({"status": "success", "count": 42})),
2102 meta: None,
2103 };
2104
2105 let json = serde_json::to_value(&result).unwrap();
2106 assert!(json["content"].is_array());
2107 assert_eq!(json["isError"], false);
2108 assert_eq!(json["structuredContent"]["status"], "success");
2109 assert_eq!(json["structuredContent"]["count"], 42);
2110 }
2111
2112 #[test]
2113 fn test_sampling_content_types() {
2114 let text = SamplingContent::text("Hello");
2116 let image = SamplingContent::image("data", "image/png");
2117 let audio = SamplingContent::audio("data", "audio/wav");
2118
2119 let text_json = serde_json::to_value(&text).unwrap();
2120 let image_json = serde_json::to_value(&image).unwrap();
2121 let audio_json = serde_json::to_value(&audio).unwrap();
2122
2123 assert_eq!(text_json["type"], "text");
2124 assert_eq!(image_json["type"], "image");
2125 assert_eq!(audio_json["type"], "audio");
2126 }
2127}
2128
2129pub type JsonRpcBatchRequest = Vec<JsonRpcRequest>;
2135
2136pub type JsonRpcBatchResponse = Vec<JsonRpcResponse>;
2138
2139#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2141#[serde(untagged)]
2142pub enum JsonRpcRequestOrNotification {
2143 Request(JsonRpcRequest),
2144 Notification(JsonRpcNotification),
2145}
2146
2147#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2149#[serde(untagged)]
2150pub enum JsonRpcResponseOrError {
2151 Response(JsonRpcResponse),
2152 Error(JsonRpcError),
2153}
2154
2155#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2157pub enum AnnotationAudience {
2158 User,
2159 Developer,
2160 System,
2161}
2162
2163#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2165pub enum DangerLevel {
2166 Safe,
2167 Low,
2168 Medium,
2169 High,
2170}