1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9pub const LATEST_PROTOCOL_VERSION: &str = "2025-03-26";
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 Implementation {
67 pub name: String,
69 pub version: String,
71}
72
73pub type ServerInfo = Implementation;
75pub type ClientInfo = Implementation;
76
77#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
83pub struct ServerCapabilities {
84 #[serde(skip_serializing_if = "Option::is_none")]
86 pub prompts: Option<PromptsCapability>,
87 #[serde(skip_serializing_if = "Option::is_none")]
89 pub resources: Option<ResourcesCapability>,
90 #[serde(skip_serializing_if = "Option::is_none")]
92 pub tools: Option<ToolsCapability>,
93 #[serde(skip_serializing_if = "Option::is_none")]
95 pub sampling: Option<SamplingCapability>,
96 #[serde(skip_serializing_if = "Option::is_none")]
98 pub logging: Option<LoggingCapability>,
99 #[serde(skip_serializing_if = "Option::is_none")]
101 pub completions: Option<CompletionsCapability>,
102 #[serde(skip_serializing_if = "Option::is_none")]
104 pub experimental: Option<HashMap<String, serde_json::Value>>,
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
109pub struct ClientCapabilities {
110 #[serde(skip_serializing_if = "Option::is_none")]
112 pub sampling: Option<SamplingCapability>,
113 #[serde(skip_serializing_if = "Option::is_none")]
115 pub roots: Option<RootsCapability>,
116 #[serde(skip_serializing_if = "Option::is_none")]
118 pub experimental: Option<HashMap<String, serde_json::Value>>,
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
123pub struct PromptsCapability {
124 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
126 pub list_changed: Option<bool>,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
131pub struct ResourcesCapability {
132 #[serde(skip_serializing_if = "Option::is_none")]
134 pub subscribe: Option<bool>,
135 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
137 pub list_changed: Option<bool>,
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
142pub struct ToolsCapability {
143 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
145 pub list_changed: Option<bool>,
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
150pub struct SamplingCapability {
151 #[serde(flatten)]
153 pub additional_properties: HashMap<String, serde_json::Value>,
154}
155
156#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
158pub struct LoggingCapability {
159 #[serde(flatten)]
161 pub additional_properties: HashMap<String, serde_json::Value>,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
166pub struct CompletionsCapability {
167 #[serde(flatten)]
169 pub additional_properties: HashMap<String, serde_json::Value>,
170}
171
172#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
174pub struct RootsCapability {
175 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
177 pub list_changed: Option<bool>,
178}
179
180#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
186pub struct Annotations {
187 #[serde(skip_serializing_if = "Option::is_none")]
189 pub audience: Option<Vec<AnnotationAudience>>,
190 #[serde(skip_serializing_if = "Option::is_none")]
192 pub danger: Option<DangerLevel>,
193 #[serde(skip_serializing_if = "Option::is_none")]
195 pub destructive: Option<bool>,
196 #[serde(rename = "readOnly", skip_serializing_if = "Option::is_none")]
198 pub read_only: Option<bool>,
199}
200
201#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
203#[serde(rename_all = "lowercase")]
204pub enum AnnotationAudience {
205 User,
207 Developer,
209 Admin,
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
215#[serde(rename_all = "lowercase")]
216pub enum DangerLevel {
217 Safe,
219 Low,
221 Medium,
223 High,
225 Critical,
227}
228
229#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
235pub struct TextContent {
236 #[serde(rename = "type")]
238 pub content_type: String, pub text: String,
241 #[serde(skip_serializing_if = "Option::is_none")]
243 pub annotations: Option<Annotations>,
244}
245
246#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
248pub struct ImageContent {
249 #[serde(rename = "type")]
251 pub content_type: String, pub data: String,
254 #[serde(rename = "mimeType")]
256 pub mime_type: String,
257 #[serde(skip_serializing_if = "Option::is_none")]
259 pub annotations: Option<Annotations>,
260}
261
262#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
264pub struct AudioContent {
265 #[serde(rename = "type")]
267 pub content_type: String, pub data: String,
270 #[serde(rename = "mimeType")]
272 pub mime_type: String,
273 #[serde(skip_serializing_if = "Option::is_none")]
275 pub annotations: Option<Annotations>,
276}
277
278#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
280pub struct EmbeddedResource {
281 #[serde(rename = "type")]
283 pub content_type: String, pub resource: ResourceReference,
286 #[serde(skip_serializing_if = "Option::is_none")]
288 pub annotations: Option<Annotations>,
289}
290
291#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
293pub struct ResourceReference {
294 pub uri: String,
296}
297
298#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
300#[serde(tag = "type")]
301pub enum Content {
302 #[serde(rename = "text")]
304 Text {
305 text: String,
307 #[serde(skip_serializing_if = "Option::is_none")]
309 annotations: Option<Annotations>,
310 },
311 #[serde(rename = "image")]
313 Image {
314 data: String,
316 #[serde(rename = "mimeType")]
318 mime_type: String,
319 #[serde(skip_serializing_if = "Option::is_none")]
321 annotations: Option<Annotations>,
322 },
323 #[serde(rename = "audio")]
325 Audio {
326 data: String,
328 #[serde(rename = "mimeType")]
330 mime_type: String,
331 #[serde(skip_serializing_if = "Option::is_none")]
333 annotations: Option<Annotations>,
334 },
335 #[serde(rename = "resource")]
337 Resource {
338 resource: ResourceReference,
340 #[serde(skip_serializing_if = "Option::is_none")]
342 annotations: Option<Annotations>,
343 },
344}
345
346#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
352pub struct Tool {
353 pub name: String,
355 #[serde(skip_serializing_if = "Option::is_none")]
357 pub description: Option<String>,
358 #[serde(rename = "inputSchema")]
360 pub input_schema: ToolInputSchema,
361 #[serde(skip_serializing_if = "Option::is_none")]
363 pub annotations: Option<Annotations>,
364}
365
366#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
368pub struct ToolInputSchema {
369 #[serde(rename = "type")]
371 pub schema_type: String,
372 #[serde(skip_serializing_if = "Option::is_none")]
374 pub properties: Option<HashMap<String, serde_json::Value>>,
375 #[serde(skip_serializing_if = "Option::is_none")]
377 pub required: Option<Vec<String>>,
378 #[serde(flatten)]
380 pub additional_properties: HashMap<String, serde_json::Value>,
381}
382
383#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
385pub struct CallToolResult {
386 pub content: Vec<Content>,
388 #[serde(rename = "isError", skip_serializing_if = "Option::is_none")]
390 pub is_error: Option<bool>,
391 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
393 pub meta: Option<HashMap<String, serde_json::Value>>,
394}
395
396pub type ToolInfo = Tool;
398pub type ToolResult = CallToolResult;
399
400#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
406pub struct Resource {
407 pub uri: String,
409 #[serde(skip_serializing_if = "Option::is_none")]
411 pub name: Option<String>,
412 #[serde(skip_serializing_if = "Option::is_none")]
414 pub description: Option<String>,
415 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
417 pub mime_type: Option<String>,
418 #[serde(skip_serializing_if = "Option::is_none")]
420 pub annotations: Option<Annotations>,
421 #[serde(skip_serializing_if = "Option::is_none")]
423 pub size: Option<u64>,
424}
425
426#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
428pub struct ResourceTemplate {
429 #[serde(rename = "uriTemplate")]
431 pub uri_template: String,
432 #[serde(skip_serializing_if = "Option::is_none")]
434 pub name: Option<String>,
435 #[serde(skip_serializing_if = "Option::is_none")]
437 pub description: Option<String>,
438 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
440 pub mime_type: Option<String>,
441}
442
443#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
445#[serde(untagged)]
446pub enum ResourceContents {
447 Text {
449 uri: String,
451 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
453 mime_type: Option<String>,
454 text: String,
456 },
457 Blob {
459 uri: String,
461 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
463 mime_type: Option<String>,
464 blob: String,
466 },
467}
468
469pub type ResourceInfo = Resource;
471
472#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
478pub struct Prompt {
479 pub name: String,
481 #[serde(skip_serializing_if = "Option::is_none")]
483 pub description: Option<String>,
484 #[serde(skip_serializing_if = "Option::is_none")]
486 pub arguments: Option<Vec<PromptArgument>>,
487}
488
489#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
491pub struct PromptArgument {
492 pub name: String,
494 #[serde(skip_serializing_if = "Option::is_none")]
496 pub description: Option<String>,
497 #[serde(skip_serializing_if = "Option::is_none")]
499 pub required: Option<bool>,
500}
501
502#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
504#[serde(rename_all = "lowercase")]
505pub enum Role {
506 User,
507 Assistant,
508}
509
510#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
512pub struct PromptMessage {
513 pub role: Role,
515 pub content: Content,
517}
518
519#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
521pub struct GetPromptResult {
522 #[serde(skip_serializing_if = "Option::is_none")]
524 pub description: Option<String>,
525 pub messages: Vec<PromptMessage>,
527 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
529 pub meta: Option<HashMap<String, serde_json::Value>>,
530}
531
532pub type PromptInfo = Prompt;
534pub type PromptResult = GetPromptResult;
535
536#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
542pub struct SamplingMessage {
543 pub role: Role,
545 pub content: Content,
547}
548
549#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
551pub struct ModelPreferences {
552 #[serde(rename = "costPriority", skip_serializing_if = "Option::is_none")]
554 pub cost_priority: Option<f32>,
555 #[serde(rename = "speedPriority", skip_serializing_if = "Option::is_none")]
557 pub speed_priority: Option<f32>,
558 #[serde(rename = "qualityPriority", skip_serializing_if = "Option::is_none")]
560 pub quality_priority: Option<f32>,
561}
562
563#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
565pub struct CreateMessageResult {
566 pub role: Role,
568 pub content: Content,
570 pub model: String,
572 #[serde(rename = "stopReason", skip_serializing_if = "Option::is_none")]
574 pub stop_reason: Option<StopReason>,
575 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
577 pub meta: Option<HashMap<String, serde_json::Value>>,
578}
579
580#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
582#[serde(rename_all = "camelCase")]
583pub enum StopReason {
584 EndTurn,
585 StopSequence,
586 MaxTokens,
587 #[serde(untagged)]
588 Other(String),
589}
590
591#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
597#[serde(rename_all = "lowercase")]
598pub enum LoggingLevel {
599 Debug,
600 Info,
601 Notice,
602 Warning,
603 Error,
604 Critical,
605 Alert,
606 Emergency,
607}
608
609#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
615pub struct JsonRpcRequest {
616 pub jsonrpc: String,
618 pub id: RequestId,
620 pub method: String,
622 #[serde(skip_serializing_if = "Option::is_none")]
624 pub params: Option<serde_json::Value>,
625}
626
627#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
629pub struct JsonRpcResponse {
630 pub jsonrpc: String,
632 pub id: RequestId,
634 #[serde(skip_serializing_if = "Option::is_none")]
636 pub result: Option<serde_json::Value>,
637}
638
639#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
641pub struct JsonRpcError {
642 pub jsonrpc: String,
644 pub id: RequestId,
646 pub error: ErrorObject,
648}
649
650#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
652pub struct ErrorObject {
653 pub code: i32,
655 pub message: String,
657 #[serde(skip_serializing_if = "Option::is_none")]
659 pub data: Option<serde_json::Value>,
660}
661
662#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
664pub struct JsonRpcNotification {
665 pub jsonrpc: String,
667 pub method: String,
669 #[serde(skip_serializing_if = "Option::is_none")]
671 pub params: Option<serde_json::Value>,
672}
673
674pub type JsonRpcBatchRequest = Vec<JsonRpcRequestOrNotification>;
676
677pub type JsonRpcBatchResponse = Vec<JsonRpcResponseOrError>;
679
680#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
682#[serde(untagged)]
683pub enum JsonRpcRequestOrNotification {
684 Request(JsonRpcRequest),
685 Notification(JsonRpcNotification),
686}
687
688#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
690#[serde(untagged)]
691pub enum JsonRpcResponseOrError {
692 Response(JsonRpcResponse),
693 Error(JsonRpcError),
694}
695
696#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
698#[serde(untagged)]
699pub enum JsonRpcMessage {
700 Request(JsonRpcRequest),
701 Response(JsonRpcResponse),
702 Error(JsonRpcError),
703 Notification(JsonRpcNotification),
704 BatchRequest(JsonRpcBatchRequest),
705 BatchResponse(JsonRpcBatchResponse),
706}
707
708#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
714pub struct Request {
715 pub method: String,
717 #[serde(skip_serializing_if = "Option::is_none")]
719 pub params: Option<RequestParams>,
720}
721
722#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
724pub struct RequestParams {
725 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
727 pub meta: Option<RequestMeta>,
728 #[serde(flatten)]
730 pub params: HashMap<String, serde_json::Value>,
731}
732
733#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
735pub struct RequestMeta {
736 #[serde(rename = "progressToken", skip_serializing_if = "Option::is_none")]
738 pub progress_token: Option<ProgressToken>,
739}
740
741#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
743pub struct Notification {
744 pub method: String,
746 #[serde(skip_serializing_if = "Option::is_none")]
748 pub params: Option<NotificationParams>,
749}
750
751#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
753pub struct NotificationParams {
754 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
756 pub meta: Option<HashMap<String, serde_json::Value>>,
757 #[serde(flatten)]
759 pub params: HashMap<String, serde_json::Value>,
760}
761
762#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
768pub struct PaginatedRequest {
769 #[serde(skip_serializing_if = "Option::is_none")]
771 pub cursor: Option<Cursor>,
772}
773
774#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
776pub struct PaginatedResult {
777 #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
779 pub next_cursor: Option<Cursor>,
780}
781
782impl Content {
787 pub fn text<S: Into<String>>(text: S) -> Self {
789 Self::Text {
790 text: text.into(),
791 annotations: None,
792 }
793 }
794
795 pub fn image<S: Into<String>>(data: S, mime_type: S) -> Self {
797 Self::Image {
798 data: data.into(),
799 mime_type: mime_type.into(),
800 annotations: None,
801 }
802 }
803
804 pub fn audio<S: Into<String>>(data: S, mime_type: S) -> Self {
806 Self::Audio {
807 data: data.into(),
808 mime_type: mime_type.into(),
809 annotations: None,
810 }
811 }
812
813 pub fn resource<S: Into<String>>(uri: S) -> Self {
815 Self::Resource {
816 resource: ResourceReference { uri: uri.into() },
817 annotations: None,
818 }
819 }
820}
821
822impl Annotations {
823 pub fn new() -> Self {
825 Self {
826 audience: None,
827 danger: None,
828 destructive: None,
829 read_only: None,
830 }
831 }
832
833 pub fn read_only(mut self) -> Self {
835 self.read_only = Some(true);
836 self.destructive = Some(false);
837 self
838 }
839
840 pub fn destructive(mut self, danger: DangerLevel) -> Self {
842 self.destructive = Some(true);
843 self.read_only = Some(false);
844 self.danger = Some(danger);
845 self
846 }
847
848 pub fn for_audience(mut self, audience: Vec<AnnotationAudience>) -> Self {
850 self.audience = Some(audience);
851 self
852 }
853
854 pub fn with_danger_level(mut self, danger: DangerLevel) -> Self {
856 self.danger = Some(danger);
857 self
858 }
859}
860
861impl Tool {
862 pub fn new<S: Into<String>>(name: S, description: S) -> Self {
864 Self {
865 name: name.into(),
866 description: Some(description.into()),
867 input_schema: ToolInputSchema {
868 schema_type: "object".to_string(),
869 properties: None,
870 required: None,
871 additional_properties: HashMap::new(),
872 },
873 annotations: None,
874 }
875 }
876
877 pub fn with_annotations(mut self, annotations: Annotations) -> Self {
879 self.annotations = Some(annotations);
880 self
881 }
882}
883
884impl JsonRpcRequest {
885 pub fn new<T: Serialize>(
887 id: RequestId,
888 method: String,
889 params: Option<T>,
890 ) -> std::result::Result<Self, serde_json::Error> {
891 let params = match params {
892 Some(p) => Some(serde_json::to_value(p)?),
893 None => None,
894 };
895
896 Ok(Self {
897 jsonrpc: JSONRPC_VERSION.to_string(),
898 id,
899 method,
900 params,
901 })
902 }
903}
904
905impl JsonRpcResponse {
906 pub fn success<T: Serialize>(
908 id: RequestId,
909 result: T,
910 ) -> std::result::Result<Self, serde_json::Error> {
911 Ok(Self {
912 jsonrpc: JSONRPC_VERSION.to_string(),
913 id,
914 result: Some(serde_json::to_value(result)?),
915 })
916 }
917}
918
919impl JsonRpcError {
920 pub fn error(
922 id: RequestId,
923 code: i32,
924 message: String,
925 data: Option<serde_json::Value>,
926 ) -> Self {
927 Self {
928 jsonrpc: JSONRPC_VERSION.to_string(),
929 id,
930 error: ErrorObject {
931 code,
932 message,
933 data,
934 },
935 }
936 }
937}
938
939impl JsonRpcNotification {
940 pub fn new<T: Serialize>(
942 method: String,
943 params: Option<T>,
944 ) -> std::result::Result<Self, serde_json::Error> {
945 let params = match params {
946 Some(p) => Some(serde_json::to_value(p)?),
947 None => None,
948 };
949
950 Ok(Self {
951 jsonrpc: JSONRPC_VERSION.to_string(),
952 method,
953 params,
954 })
955 }
956}
957
958impl SamplingMessage {
959 pub fn user_text<S: Into<String>>(text: S) -> Self {
961 Self {
962 role: Role::User,
963 content: Content::text(text),
964 }
965 }
966
967 pub fn assistant_text<S: Into<String>>(text: S) -> Self {
969 Self {
970 role: Role::Assistant,
971 content: Content::text(text),
972 }
973 }
974}
975
976pub mod error_codes {
982 pub const PARSE_ERROR: i32 = -32700;
984 pub const INVALID_REQUEST: i32 = -32600;
986 pub const METHOD_NOT_FOUND: i32 = -32601;
988 pub const INVALID_PARAMS: i32 = -32602;
990 pub const INTERNAL_ERROR: i32 = -32603;
992
993 pub const TOOL_NOT_FOUND: i32 = -32000;
995 pub const RESOURCE_NOT_FOUND: i32 = -32001;
996 pub const PROMPT_NOT_FOUND: i32 = -32002;
997}
998
999#[cfg(test)]
1000mod tests {
1001 use super::*;
1002 use serde_json::json;
1003
1004 #[test]
1005 fn test_protocol_version() {
1006 assert_eq!(LATEST_PROTOCOL_VERSION, "2025-03-26");
1007 assert_eq!(JSONRPC_VERSION, "2.0");
1008 }
1009
1010 #[test]
1011 fn test_content_types() {
1012 let text = Content::text("Hello, world!");
1014 let json = serde_json::to_value(&text).unwrap();
1015 assert_eq!(json["type"], "text");
1016 assert_eq!(json["text"], "Hello, world!");
1017
1018 let audio = Content::audio("base64data", "audio/wav");
1020 let json = serde_json::to_value(&audio).unwrap();
1021 assert_eq!(json["type"], "audio");
1022 assert_eq!(json["data"], "base64data");
1023 assert_eq!(json["mimeType"], "audio/wav");
1024
1025 let resource = Content::resource("file:///test.txt");
1027 let json = serde_json::to_value(&resource).unwrap();
1028 assert_eq!(json["type"], "resource");
1029 assert_eq!(json["resource"]["uri"], "file:///test.txt");
1030 }
1031
1032 #[test]
1033 fn test_annotations() {
1034 let annotations = Annotations::new()
1035 .read_only()
1036 .for_audience(vec![AnnotationAudience::Developer])
1037 .with_danger_level(DangerLevel::Safe);
1038
1039 assert_eq!(annotations.read_only, Some(true));
1040 assert_eq!(annotations.destructive, Some(false));
1041 assert_eq!(annotations.danger, Some(DangerLevel::Safe));
1042 assert_eq!(
1043 annotations.audience,
1044 Some(vec![AnnotationAudience::Developer])
1045 );
1046 }
1047
1048 #[test]
1049 fn test_tool_with_annotations() {
1050 let tool = Tool::new("safe_reader", "Read file safely")
1051 .with_annotations(Annotations::new().read_only());
1052
1053 assert_eq!(tool.name, "safe_reader");
1054 assert!(tool.annotations.is_some());
1055 assert_eq!(tool.annotations.unwrap().read_only, Some(true));
1056 }
1057
1058 #[test]
1059 fn test_jsonrpc_batching() {
1060 let req1 = JsonRpcRequest::new(json!(1), "method1".to_string(), Some(json!({}))).unwrap();
1061 let req2 = JsonRpcRequest::new::<serde_json::Value>(json!(2), "method2".to_string(), None)
1062 .unwrap();
1063
1064 let batch: JsonRpcBatchRequest = vec![
1065 JsonRpcRequestOrNotification::Request(req1),
1066 JsonRpcRequestOrNotification::Request(req2),
1067 ];
1068
1069 let json = serde_json::to_value(&batch).unwrap();
1070 assert!(json.is_array());
1071 assert_eq!(json.as_array().unwrap().len(), 2);
1072 }
1073
1074 #[test]
1075 fn test_server_capabilities_2025() {
1076 let caps = ServerCapabilities {
1077 tools: Some(ToolsCapability {
1078 list_changed: Some(true),
1079 }),
1080 completions: Some(CompletionsCapability::default()),
1081 logging: Some(LoggingCapability::default()),
1082 experimental: Some(HashMap::new()),
1083 ..Default::default()
1084 };
1085
1086 let json = serde_json::to_value(&caps).unwrap();
1087 assert!(json["tools"]["listChanged"].as_bool().unwrap());
1088 assert!(json["completions"].is_object());
1089 assert!(json["logging"].is_object());
1090 assert!(json["experimental"].is_object());
1091 }
1092}