1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use turbomcp_core::MessageId;
9
10pub type ProtocolVersion = String;
12
13pub type RequestId = MessageId;
15
16pub type ProgressToken = String;
18
19pub type Uri = String;
21
22pub type MimeType = String;
24
25pub type Base64String = String;
27
28pub mod error_codes {
34 pub const PARSE_ERROR: i32 = -32700;
36 pub const INVALID_REQUEST: i32 = -32600;
38 pub const METHOD_NOT_FOUND: i32 = -32601;
40 pub const INVALID_PARAMS: i32 = -32602;
42 pub const INTERNAL_ERROR: i32 = -32603;
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
48pub struct JsonRpcError {
49 pub code: i32,
51 pub message: String,
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub data: Option<serde_json::Value>,
56}
57
58impl JsonRpcError {
59 pub fn new(code: i32, message: String) -> Self {
61 Self {
62 code,
63 message,
64 data: None,
65 }
66 }
67
68 pub fn with_data(code: i32, message: String, data: serde_json::Value) -> Self {
70 Self {
71 code,
72 message,
73 data: Some(data),
74 }
75 }
76
77 pub fn parse_error() -> Self {
79 Self::new(error_codes::PARSE_ERROR, "Parse error".to_string())
80 }
81
82 pub fn invalid_request() -> Self {
84 Self::new(error_codes::INVALID_REQUEST, "Invalid Request".to_string())
85 }
86
87 pub fn method_not_found(method: &str) -> Self {
89 Self::new(
90 error_codes::METHOD_NOT_FOUND,
91 format!("Method not found: {method}"),
92 )
93 }
94
95 pub fn invalid_params(details: &str) -> Self {
97 Self::new(
98 error_codes::INVALID_PARAMS,
99 format!("Invalid params: {details}"),
100 )
101 }
102
103 pub fn internal_error(details: &str) -> Self {
105 Self::new(
106 error_codes::INTERNAL_ERROR,
107 format!("Internal error: {details}"),
108 )
109 }
110}
111
112pub type Cursor = String;
114
115#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct BaseMetadata {
123 pub name: String,
125
126 #[serde(skip_serializing_if = "Option::is_none")]
132 pub title: Option<String>,
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct Implementation {
138 pub name: String,
140 #[serde(skip_serializing_if = "Option::is_none")]
142 pub title: Option<String>,
143 pub version: String,
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
149pub struct Annotations {
150 #[serde(skip_serializing_if = "Option::is_none")]
152 pub audience: Option<Vec<String>>,
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub priority: Option<f64>,
156 #[serde(skip_serializing_if = "Option::is_none")]
158 #[serde(rename = "lastModified")]
159 pub last_modified: Option<String>,
160 #[serde(flatten)]
162 pub custom: HashMap<String, serde_json::Value>,
163}
164
165#[derive(Debug, Clone, Serialize, Deserialize)]
171#[serde(tag = "method")]
172pub enum ClientRequest {
173 #[serde(rename = "initialize")]
175 Initialize(InitializeRequest),
176
177 #[serde(rename = "tools/list")]
179 ListTools(ListToolsRequest),
180
181 #[serde(rename = "tools/call")]
183 CallTool(CallToolRequest),
184
185 #[serde(rename = "prompts/list")]
187 ListPrompts(ListPromptsRequest),
188
189 #[serde(rename = "prompts/get")]
191 GetPrompt(GetPromptRequest),
192
193 #[serde(rename = "resources/list")]
195 ListResources(ListResourcesRequest),
196
197 #[serde(rename = "resources/templates/list")]
199 ListResourceTemplates(ListResourceTemplatesRequest),
200
201 #[serde(rename = "resources/read")]
203 ReadResource(ReadResourceRequest),
204
205 #[serde(rename = "resources/subscribe")]
207 Subscribe(SubscribeRequest),
208
209 #[serde(rename = "resources/unsubscribe")]
211 Unsubscribe(UnsubscribeRequest),
212
213 #[serde(rename = "logging/setLevel")]
215 SetLevel(SetLevelRequest),
216
217 #[serde(rename = "completion/complete")]
219 Complete(CompleteRequestParams),
220
221 #[serde(rename = "ping")]
223 Ping(PingParams),
224}
225
226#[derive(Debug, Clone, Serialize, Deserialize)]
228#[serde(tag = "method")]
229pub enum ServerRequest {
230 #[serde(rename = "ping")]
232 Ping(PingParams),
233
234 #[serde(rename = "sampling/createMessage")]
236 CreateMessage(CreateMessageRequest),
237
238 #[serde(rename = "roots/list")]
240 ListRoots(ListRootsRequest),
241
242 #[serde(rename = "elicitation/create")]
244 ElicitationCreate(ElicitRequestParams),
245}
246
247#[derive(Debug, Clone, Serialize, Deserialize)]
249#[serde(tag = "method")]
250pub enum ClientNotification {
251 #[serde(rename = "notifications/initialized")]
253 Initialized(InitializedNotification),
254
255 #[serde(rename = "notifications/progress")]
257 Progress(ProgressNotification),
258
259 #[serde(rename = "notifications/roots/list_changed")]
261 RootsListChanged(RootsListChangedNotification),
262}
263
264#[derive(Debug, Clone, Serialize, Deserialize)]
266#[serde(tag = "method")]
267pub enum ServerNotification {
268 #[serde(rename = "notifications/message")]
270 Message(LoggingNotification),
271
272 #[serde(rename = "notifications/resources/updated")]
274 ResourceUpdated(ResourceUpdatedNotification),
275
276 #[serde(rename = "notifications/resources/list_changed")]
278 ResourceListChanged,
279
280 #[serde(rename = "notifications/progress")]
282 Progress(ProgressNotification),
283
284 #[serde(rename = "notifications/cancelled")]
286 Cancelled(CancelledNotification),
287
288 #[serde(rename = "notifications/prompts/list_changed")]
290 PromptsListChanged,
291
292 #[serde(rename = "notifications/tools/list_changed")]
294 ToolsListChanged,
295
296 #[serde(rename = "notifications/roots/list_changed")]
298 RootsListChanged,
299}
300
301#[derive(Debug, Clone, Serialize, Deserialize)]
307pub struct InitializeRequest {
308 #[serde(rename = "protocolVersion")]
310 pub protocol_version: ProtocolVersion,
311 pub capabilities: ClientCapabilities,
313 #[serde(rename = "clientInfo")]
315 pub client_info: Implementation,
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize)]
320pub struct InitializeResult {
321 #[serde(rename = "protocolVersion")]
323 pub protocol_version: ProtocolVersion,
324 pub capabilities: ServerCapabilities,
326 #[serde(rename = "serverInfo")]
328 pub server_info: Implementation,
329 #[serde(skip_serializing_if = "Option::is_none")]
331 pub instructions: Option<String>,
332}
333
334#[derive(Debug, Clone, Serialize, Deserialize)]
336pub struct InitializedNotification;
337
338#[derive(Debug, Clone, Serialize, Deserialize, Default)]
344pub struct ClientCapabilities {
345 #[serde(skip_serializing_if = "Option::is_none")]
347 pub experimental: Option<HashMap<String, serde_json::Value>>,
348
349 #[serde(skip_serializing_if = "Option::is_none")]
351 pub roots: Option<RootsCapabilities>,
352
353 #[serde(skip_serializing_if = "Option::is_none")]
355 pub sampling: Option<SamplingCapabilities>,
356
357 #[serde(skip_serializing_if = "Option::is_none")]
359 pub elicitation: Option<ElicitationCapabilities>,
360}
361
362#[derive(Debug, Clone, Serialize, Deserialize, Default)]
364pub struct ServerCapabilities {
365 #[serde(skip_serializing_if = "Option::is_none")]
367 pub experimental: Option<HashMap<String, serde_json::Value>>,
368
369 #[serde(skip_serializing_if = "Option::is_none")]
371 pub logging: Option<LoggingCapabilities>,
372
373 #[serde(skip_serializing_if = "Option::is_none")]
375 pub completions: Option<CompletionCapabilities>,
376
377 #[serde(skip_serializing_if = "Option::is_none")]
379 pub prompts: Option<PromptsCapabilities>,
380
381 #[serde(skip_serializing_if = "Option::is_none")]
383 pub resources: Option<ResourcesCapabilities>,
384
385 #[serde(skip_serializing_if = "Option::is_none")]
387 pub tools: Option<ToolsCapabilities>,
388}
389
390#[derive(Debug, Clone, Serialize, Deserialize, Default)]
392pub struct SamplingCapabilities;
393
394#[derive(Debug, Clone, Serialize, Deserialize, Default)]
396pub struct ElicitationCapabilities;
397
398#[derive(Debug, Clone, Serialize, Deserialize, Default)]
400pub struct CompletionCapabilities;
401
402#[derive(Debug, Clone, Serialize, Deserialize, Default)]
404pub struct RootsCapabilities {
405 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
407 pub list_changed: Option<bool>,
408}
409
410#[derive(Debug, Clone, Serialize, Deserialize, Default)]
412pub struct LoggingCapabilities;
413
414#[derive(Debug, Clone, Serialize, Deserialize, Default)]
416pub struct PromptsCapabilities {
417 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
419 pub list_changed: Option<bool>,
420}
421
422#[derive(Debug, Clone, Serialize, Deserialize, Default)]
424pub struct ResourcesCapabilities {
425 #[serde(skip_serializing_if = "Option::is_none")]
427 pub subscribe: Option<bool>,
428
429 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
431 pub list_changed: Option<bool>,
432}
433
434#[derive(Debug, Clone, Serialize, Deserialize, Default)]
436pub struct ToolsCapabilities {
437 #[serde(rename = "listChanged", skip_serializing_if = "Option::is_none")]
439 pub list_changed: Option<bool>,
440}
441
442#[derive(Debug, Clone, Serialize, Deserialize)]
448#[serde(tag = "type")]
449pub enum ContentBlock {
450 #[serde(rename = "text")]
452 Text(TextContent),
453 #[serde(rename = "image")]
455 Image(ImageContent),
456 #[serde(rename = "audio")]
458 Audio(AudioContent),
459 #[serde(rename = "resource_link")]
461 ResourceLink(ResourceLink),
462 #[serde(rename = "resource")]
464 Resource(EmbeddedResource),
465}
466
467pub type Content = ContentBlock;
469
470#[derive(Debug, Clone, Serialize, Deserialize)]
472pub struct TextContent {
473 pub text: String,
475 #[serde(skip_serializing_if = "Option::is_none")]
477 pub annotations: Option<Annotations>,
478 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
480 pub meta: Option<HashMap<String, serde_json::Value>>,
481}
482
483#[derive(Debug, Clone, Serialize, Deserialize)]
485pub struct ImageContent {
486 pub data: String,
488 #[serde(rename = "mimeType")]
490 pub mime_type: String,
491 #[serde(skip_serializing_if = "Option::is_none")]
493 pub annotations: Option<Annotations>,
494 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
496 pub meta: Option<HashMap<String, serde_json::Value>>,
497}
498
499#[derive(Debug, Clone, Serialize, Deserialize)]
501pub struct AudioContent {
502 pub data: String,
504 #[serde(rename = "mimeType")]
506 pub mime_type: String,
507 #[serde(skip_serializing_if = "Option::is_none")]
509 pub annotations: Option<Annotations>,
510 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
512 pub meta: Option<HashMap<String, serde_json::Value>>,
513}
514
515#[derive(Debug, Clone, Serialize, Deserialize)]
517pub struct ResourceLink {
518 pub name: String,
520 #[serde(skip_serializing_if = "Option::is_none")]
522 pub title: Option<String>,
523 pub uri: String,
525 #[serde(skip_serializing_if = "Option::is_none")]
527 pub description: Option<String>,
528 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
530 pub mime_type: Option<String>,
531 #[serde(skip_serializing_if = "Option::is_none")]
533 pub annotations: Option<Annotations>,
534 #[serde(skip_serializing_if = "Option::is_none")]
536 pub size: Option<u64>,
537 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
539 pub meta: Option<HashMap<String, serde_json::Value>>,
540}
541
542#[derive(Debug, Clone, Serialize, Deserialize)]
544pub struct EmbeddedResource {
545 pub resource: ResourceContent,
547 #[serde(skip_serializing_if = "Option::is_none")]
549 pub annotations: Option<Annotations>,
550 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
552 pub meta: Option<HashMap<String, serde_json::Value>>,
553}
554
555#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
557#[serde(rename_all = "lowercase")]
558pub enum Role {
559 User,
561 Assistant,
563}
564
565#[derive(Debug, Clone, Serialize, Deserialize, Default)]
571pub struct ToolAnnotations {
572 #[serde(skip_serializing_if = "Option::is_none")]
574 pub title: Option<String>,
575 #[serde(skip_serializing_if = "Option::is_none")]
577 pub audience: Option<Vec<String>>,
578 #[serde(skip_serializing_if = "Option::is_none")]
580 pub priority: Option<f64>,
581 #[serde(skip_serializing_if = "Option::is_none")]
583 #[serde(rename = "destructiveHint")]
584 pub destructive_hint: Option<bool>,
585 #[serde(skip_serializing_if = "Option::is_none")]
587 #[serde(rename = "idempotentHint")]
588 pub idempotent_hint: Option<bool>,
589 #[serde(skip_serializing_if = "Option::is_none")]
591 #[serde(rename = "openWorldHint")]
592 pub open_world_hint: Option<bool>,
593 #[serde(skip_serializing_if = "Option::is_none")]
595 #[serde(rename = "readOnlyHint")]
596 pub read_only_hint: Option<bool>,
597 #[serde(flatten)]
599 pub custom: HashMap<String, serde_json::Value>,
600}
601
602#[derive(Debug, Clone, Serialize, Deserialize)]
604pub struct Tool {
605 pub name: String,
607
608 #[serde(skip_serializing_if = "Option::is_none")]
610 pub title: Option<String>,
611
612 #[serde(skip_serializing_if = "Option::is_none")]
615 pub description: Option<String>,
616
617 #[serde(rename = "inputSchema")]
619 pub input_schema: ToolInputSchema,
620
621 #[serde(rename = "outputSchema", skip_serializing_if = "Option::is_none")]
624 pub output_schema: Option<ToolOutputSchema>,
625
626 #[serde(skip_serializing_if = "Option::is_none")]
629 pub annotations: Option<ToolAnnotations>,
630
631 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
633 pub meta: Option<HashMap<String, serde_json::Value>>,
634}
635
636impl Default for Tool {
637 fn default() -> Self {
638 Self {
639 name: "unnamed_tool".to_string(), title: None,
641 description: None,
642 input_schema: ToolInputSchema::default(),
643 output_schema: None,
644 annotations: None,
645 meta: None,
646 }
647 }
648}
649
650impl Tool {
651 pub fn new(name: impl Into<String>) -> Self {
656 let name = name.into();
657 assert!(!name.trim().is_empty(), "Tool name cannot be empty");
658
659 Self {
660 name,
661 title: None,
662 description: None,
663 input_schema: ToolInputSchema::default(),
664 output_schema: None,
665 annotations: None,
666 meta: None,
667 }
668 }
669
670 pub fn with_description(name: impl Into<String>, description: impl Into<String>) -> Self {
675 let name = name.into();
676 assert!(!name.trim().is_empty(), "Tool name cannot be empty");
677
678 Self {
679 name,
680 title: None,
681 description: Some(description.into()),
682 input_schema: ToolInputSchema::default(),
683 output_schema: None,
684 annotations: None,
685 meta: None,
686 }
687 }
688}
689
690#[derive(Debug, Clone, Serialize, Deserialize)]
692pub struct ToolInputSchema {
693 #[serde(rename = "type")]
695 pub schema_type: String,
696 #[serde(skip_serializing_if = "Option::is_none")]
698 pub properties: Option<HashMap<String, serde_json::Value>>,
699 #[serde(skip_serializing_if = "Option::is_none")]
701 pub required: Option<Vec<String>>,
702 #[serde(
704 rename = "additionalProperties",
705 skip_serializing_if = "Option::is_none"
706 )]
707 pub additional_properties: Option<bool>,
708}
709
710impl Default for ToolInputSchema {
711 fn default() -> Self {
712 Self {
713 schema_type: "object".to_string(),
714 properties: None,
715 required: None,
716 additional_properties: None,
717 }
718 }
719}
720
721impl ToolInputSchema {
722 pub fn empty() -> Self {
724 Self::default()
725 }
726
727 pub fn with_properties(properties: HashMap<String, serde_json::Value>) -> Self {
729 Self {
730 schema_type: "object".to_string(),
731 properties: Some(properties),
732 required: None,
733 additional_properties: None,
734 }
735 }
736
737 pub fn with_required_properties(
739 properties: HashMap<String, serde_json::Value>,
740 required: Vec<String>,
741 ) -> Self {
742 Self {
743 schema_type: "object".to_string(),
744 properties: Some(properties),
745 required: Some(required),
746 additional_properties: None,
747 }
748 }
749}
750
751#[derive(Debug, Clone, Serialize, Deserialize)]
753pub struct ToolOutputSchema {
754 #[serde(rename = "type")]
756 pub schema_type: String,
757 #[serde(skip_serializing_if = "Option::is_none")]
759 pub properties: Option<HashMap<String, serde_json::Value>>,
760 #[serde(skip_serializing_if = "Option::is_none")]
762 pub required: Option<Vec<String>>,
763 #[serde(
765 rename = "additionalProperties",
766 skip_serializing_if = "Option::is_none"
767 )]
768 pub additional_properties: Option<bool>,
769}
770
771#[derive(Debug, Clone, Serialize, Deserialize)]
773pub struct ListToolsRequest;
774
775#[derive(Debug, Clone, Serialize, Deserialize)]
777pub struct ListToolsResult {
778 pub tools: Vec<Tool>,
780 #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
782 pub next_cursor: Option<String>,
783}
784
785#[derive(Debug, Clone, Serialize, Deserialize)]
787pub struct CallToolRequest {
788 pub name: String,
790 #[serde(skip_serializing_if = "Option::is_none")]
792 pub arguments: Option<HashMap<String, serde_json::Value>>,
793}
794
795#[derive(Debug, Clone, Serialize, Deserialize)]
797pub struct CallToolResult {
798 pub content: Vec<ContentBlock>,
800 #[serde(rename = "isError", skip_serializing_if = "Option::is_none")]
802 pub is_error: Option<bool>,
803}
804
805#[derive(Debug, Clone, Serialize, Deserialize)]
811pub struct Prompt {
812 pub name: String,
814
815 #[serde(skip_serializing_if = "Option::is_none")]
817 pub title: Option<String>,
818
819 #[serde(skip_serializing_if = "Option::is_none")]
821 pub description: Option<String>,
822
823 #[serde(skip_serializing_if = "Option::is_none")]
825 pub arguments: Option<Vec<PromptArgument>>,
826
827 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
829 pub meta: Option<HashMap<String, serde_json::Value>>,
830}
831
832#[derive(Debug, Clone, Serialize, Deserialize)]
834pub struct PromptArgument {
835 pub name: String,
837
838 #[serde(skip_serializing_if = "Option::is_none")]
840 pub title: Option<String>,
841
842 #[serde(skip_serializing_if = "Option::is_none")]
844 pub description: Option<String>,
845
846 #[serde(skip_serializing_if = "Option::is_none")]
848 pub required: Option<bool>,
849}
850
851pub type PromptInput = HashMap<String, serde_json::Value>;
853
854#[derive(Debug, Clone, Serialize, Deserialize)]
856pub struct ListPromptsRequest;
857
858#[derive(Debug, Clone, Serialize, Deserialize)]
860pub struct ListPromptsResult {
861 pub prompts: Vec<Prompt>,
863 #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
865 pub next_cursor: Option<String>,
866}
867
868#[derive(Debug, Clone, Serialize, Deserialize)]
870pub struct GetPromptRequest {
871 pub name: String,
873 #[serde(skip_serializing_if = "Option::is_none")]
875 pub arguments: Option<PromptInput>,
876}
877
878#[derive(Debug, Clone, Serialize, Deserialize)]
880pub struct GetPromptResult {
881 #[serde(skip_serializing_if = "Option::is_none")]
883 pub description: Option<String>,
884 pub messages: Vec<PromptMessage>,
886}
887
888#[derive(Debug, Clone, Serialize, Deserialize)]
890pub struct PromptMessage {
891 pub role: Role,
893 pub content: Content,
895}
896
897#[derive(Debug, Clone, Serialize, Deserialize)]
903pub struct Resource {
904 pub name: String,
906
907 #[serde(skip_serializing_if = "Option::is_none")]
909 pub title: Option<String>,
910
911 pub uri: String,
913
914 #[serde(skip_serializing_if = "Option::is_none")]
917 pub description: Option<String>,
918
919 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
921 pub mime_type: Option<String>,
922
923 #[serde(skip_serializing_if = "Option::is_none")]
925 pub annotations: Option<Annotations>,
926
927 #[serde(skip_serializing_if = "Option::is_none")]
930 pub size: Option<u64>,
931
932 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
934 pub meta: Option<HashMap<String, serde_json::Value>>,
935}
936
937#[derive(Debug, Clone, Serialize, Deserialize)]
939pub struct ResourceContents {
940 pub uri: String,
942 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
944 pub mime_type: Option<String>,
945 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
947 pub meta: Option<HashMap<String, serde_json::Value>>,
948}
949
950#[derive(Debug, Clone, Serialize, Deserialize)]
952pub struct TextResourceContents {
953 pub uri: String,
955 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
957 pub mime_type: Option<String>,
958 pub text: String,
960 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
962 pub meta: Option<HashMap<String, serde_json::Value>>,
963}
964
965#[derive(Debug, Clone, Serialize, Deserialize)]
967pub struct BlobResourceContents {
968 pub uri: String,
970 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
972 pub mime_type: Option<String>,
973 pub blob: String,
975 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
977 pub meta: Option<HashMap<String, serde_json::Value>>,
978}
979
980#[derive(Debug, Clone, Serialize, Deserialize)]
982#[serde(untagged)]
983pub enum ResourceContent {
984 Text(TextResourceContents),
986 Blob(BlobResourceContents),
988}
989
990#[derive(Debug, Clone, Serialize, Deserialize)]
992pub struct ListResourcesRequest {
993 #[serde(skip_serializing_if = "Option::is_none")]
995 pub cursor: Option<String>,
996}
997
998#[derive(Debug, Clone, Serialize, Deserialize)]
1000pub struct ListResourcesResult {
1001 pub resources: Vec<Resource>,
1003 #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
1005 pub next_cursor: Option<String>,
1006}
1007
1008#[derive(Debug, Clone, Serialize, Deserialize)]
1010pub struct ReadResourceRequest {
1011 pub uri: Uri,
1013}
1014
1015#[derive(Debug, Clone, Serialize, Deserialize)]
1017pub struct ReadResourceResult {
1018 pub contents: Vec<ResourceContent>,
1020}
1021
1022#[derive(Debug, Clone, Serialize, Deserialize)]
1024pub struct SubscribeRequest {
1025 pub uri: Uri,
1027}
1028
1029#[derive(Debug, Clone, Serialize, Deserialize)]
1031pub struct UnsubscribeRequest {
1032 pub uri: Uri,
1034}
1035
1036#[derive(Debug, Clone, Serialize, Deserialize)]
1038pub struct ResourceUpdatedNotification {
1039 pub uri: Uri,
1041}
1042
1043#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1049#[serde(rename_all = "lowercase")]
1050pub enum LogLevel {
1051 Debug,
1053 Info,
1055 Notice,
1057 Warning,
1059 Error,
1061 Critical,
1063 Alert,
1065 Emergency,
1067}
1068
1069#[derive(Debug, Clone, Serialize, Deserialize)]
1071pub struct SetLevelRequest {
1072 pub level: LogLevel,
1074}
1075
1076#[derive(Debug, Clone, Serialize, Deserialize)]
1078pub struct SetLevelResult;
1079
1080#[derive(Debug, Clone, Serialize, Deserialize)]
1082pub struct LoggingNotification {
1083 pub level: LogLevel,
1085 pub data: serde_json::Value,
1087 #[serde(skip_serializing_if = "Option::is_none")]
1089 pub logger: Option<String>,
1090}
1091
1092#[derive(Debug, Clone, Serialize, Deserialize)]
1098pub struct ProgressNotification {
1099 #[serde(rename = "progressToken")]
1102 pub progress_token: ProgressToken,
1103 pub progress: f64,
1106 #[serde(skip_serializing_if = "Option::is_none")]
1108 pub total: Option<f64>,
1109 #[serde(skip_serializing_if = "Option::is_none")]
1111 pub message: Option<String>,
1112}
1113
1114#[derive(Debug, Clone, Serialize, Deserialize)]
1116pub struct CancelledNotification {
1117 #[serde(rename = "requestId")]
1120 pub request_id: RequestId,
1121 #[serde(skip_serializing_if = "Option::is_none")]
1124 pub reason: Option<String>,
1125}
1126
1127#[derive(Debug, Clone, Serialize, Deserialize)]
1133pub struct CreateMessageRequest {
1134 pub messages: Vec<SamplingMessage>,
1136 #[serde(rename = "modelPreferences", skip_serializing_if = "Option::is_none")]
1138 pub model_preferences: Option<ModelPreferences>,
1139 #[serde(rename = "systemPrompt", skip_serializing_if = "Option::is_none")]
1141 pub system_prompt: Option<String>,
1142 #[serde(rename = "includeContext", skip_serializing_if = "Option::is_none")]
1144 pub include_context: Option<IncludeContext>,
1145 #[serde(skip_serializing_if = "Option::is_none")]
1147 pub temperature: Option<f64>,
1148 #[serde(rename = "maxTokens")]
1150 pub max_tokens: u32,
1151 #[serde(rename = "stopSequences", skip_serializing_if = "Option::is_none")]
1153 pub stop_sequences: Option<Vec<String>>,
1154 #[serde(skip_serializing_if = "Option::is_none")]
1156 pub metadata: Option<HashMap<String, serde_json::Value>>,
1157}
1158
1159#[derive(Debug, Clone, Serialize, Deserialize)]
1161pub struct ModelPreferences {
1162 #[serde(skip_serializing_if = "Option::is_none")]
1164 pub hints: Option<Vec<ModelHint>>,
1165 #[serde(rename = "costPriority", skip_serializing_if = "Option::is_none")]
1167 pub cost_priority: Option<f64>,
1168 #[serde(rename = "speedPriority", skip_serializing_if = "Option::is_none")]
1170 pub speed_priority: Option<f64>,
1171 #[serde(
1173 rename = "intelligencePriority",
1174 skip_serializing_if = "Option::is_none"
1175 )]
1176 pub intelligence_priority: Option<f64>,
1177}
1178
1179#[derive(Debug, Clone, Serialize, Deserialize)]
1181pub struct ModelHint {
1182 pub name: String,
1184}
1185
1186#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1188#[serde(rename_all = "lowercase")]
1189pub enum IncludeContext {
1190 None,
1192 ThisServer,
1194 AllServers,
1196}
1197
1198#[derive(Debug, Clone, Serialize, Deserialize)]
1200pub struct SamplingMessage {
1201 pub role: Role,
1203 pub content: Content,
1205}
1206
1207#[derive(Debug, Clone, Serialize, Deserialize)]
1209pub struct CreateMessageResult {
1210 pub role: Role,
1212 pub content: Content,
1214 #[serde(skip_serializing_if = "Option::is_none")]
1216 pub model: Option<String>,
1217 #[serde(rename = "stopReason", skip_serializing_if = "Option::is_none")]
1219 pub stop_reason: Option<String>,
1220}
1221
1222#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1229#[serde(tag = "type")]
1230pub enum PrimitiveSchemaDefinition {
1231 #[serde(rename = "string")]
1233 String {
1234 #[serde(skip_serializing_if = "Option::is_none")]
1236 title: Option<String>,
1237 #[serde(skip_serializing_if = "Option::is_none")]
1239 description: Option<String>,
1240 #[serde(skip_serializing_if = "Option::is_none")]
1242 format: Option<String>,
1243 #[serde(skip_serializing_if = "Option::is_none")]
1245 #[serde(rename = "minLength")]
1246 min_length: Option<u32>,
1247 #[serde(skip_serializing_if = "Option::is_none")]
1249 #[serde(rename = "maxLength")]
1250 max_length: Option<u32>,
1251 #[serde(skip_serializing_if = "Option::is_none")]
1253 #[serde(rename = "enum")]
1254 enum_values: Option<Vec<String>>,
1255 #[serde(skip_serializing_if = "Option::is_none")]
1257 #[serde(rename = "enumNames")]
1258 enum_names: Option<Vec<String>>,
1259 },
1260 #[serde(rename = "number")]
1262 Number {
1263 #[serde(skip_serializing_if = "Option::is_none")]
1265 title: Option<String>,
1266 #[serde(skip_serializing_if = "Option::is_none")]
1268 description: Option<String>,
1269 #[serde(skip_serializing_if = "Option::is_none")]
1271 minimum: Option<f64>,
1272 #[serde(skip_serializing_if = "Option::is_none")]
1274 maximum: Option<f64>,
1275 },
1276 #[serde(rename = "integer")]
1278 Integer {
1279 #[serde(skip_serializing_if = "Option::is_none")]
1281 title: Option<String>,
1282 #[serde(skip_serializing_if = "Option::is_none")]
1284 description: Option<String>,
1285 #[serde(skip_serializing_if = "Option::is_none")]
1287 minimum: Option<i64>,
1288 #[serde(skip_serializing_if = "Option::is_none")]
1290 maximum: Option<i64>,
1291 },
1292 #[serde(rename = "boolean")]
1294 Boolean {
1295 #[serde(skip_serializing_if = "Option::is_none")]
1297 title: Option<String>,
1298 #[serde(skip_serializing_if = "Option::is_none")]
1300 description: Option<String>,
1301 #[serde(skip_serializing_if = "Option::is_none")]
1303 default: Option<bool>,
1304 },
1305}
1306
1307#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1309pub struct ElicitationSchema {
1310 #[serde(rename = "type")]
1312 pub schema_type: String,
1313 pub properties: std::collections::HashMap<String, PrimitiveSchemaDefinition>,
1315 #[serde(skip_serializing_if = "Option::is_none")]
1317 pub required: Option<Vec<String>>,
1318}
1319
1320impl ElicitationSchema {
1321 pub fn new() -> Self {
1323 Self {
1324 schema_type: "object".to_string(),
1325 properties: std::collections::HashMap::new(),
1326 required: None,
1327 }
1328 }
1329
1330 pub fn add_string_property<K: Into<String>>(
1332 mut self,
1333 name: K,
1334 required: bool,
1335 description: Option<String>,
1336 ) -> Self {
1337 let property = PrimitiveSchemaDefinition::String {
1338 title: None,
1339 description,
1340 format: None,
1341 min_length: None,
1342 max_length: None,
1343 enum_values: None,
1344 enum_names: None,
1345 };
1346
1347 let name = name.into();
1348 self.properties.insert(name.clone(), property);
1349
1350 if required {
1351 self.required.get_or_insert_with(Vec::new).push(name);
1352 }
1353
1354 self
1355 }
1356
1357 pub fn add_number_property<K: Into<String>>(
1359 mut self,
1360 name: K,
1361 required: bool,
1362 description: Option<String>,
1363 min: Option<f64>,
1364 max: Option<f64>,
1365 ) -> Self {
1366 let property = PrimitiveSchemaDefinition::Number {
1367 title: None,
1368 description,
1369 minimum: min,
1370 maximum: max,
1371 };
1372
1373 let name = name.into();
1374 self.properties.insert(name.clone(), property);
1375
1376 if required {
1377 self.required.get_or_insert_with(Vec::new).push(name);
1378 }
1379
1380 self
1381 }
1382
1383 pub fn add_boolean_property<K: Into<String>>(
1385 mut self,
1386 name: K,
1387 required: bool,
1388 description: Option<String>,
1389 default: Option<bool>,
1390 ) -> Self {
1391 let property = PrimitiveSchemaDefinition::Boolean {
1392 title: None,
1393 description,
1394 default,
1395 };
1396
1397 let name = name.into();
1398 self.properties.insert(name.clone(), property);
1399
1400 if required {
1401 self.required.get_or_insert_with(Vec::new).push(name);
1402 }
1403
1404 self
1405 }
1406
1407 pub fn add_enum_property<K: Into<String>>(
1409 mut self,
1410 name: K,
1411 required: bool,
1412 description: Option<String>,
1413 values: Vec<String>,
1414 names: Option<Vec<String>>,
1415 ) -> Self {
1416 let property = PrimitiveSchemaDefinition::String {
1417 title: None,
1418 description,
1419 format: None,
1420 min_length: None,
1421 max_length: None,
1422 enum_values: Some(values),
1423 enum_names: names,
1424 };
1425
1426 let name = name.into();
1427 self.properties.insert(name.clone(), property);
1428
1429 if required {
1430 self.required.get_or_insert_with(Vec::new).push(name);
1431 }
1432
1433 self
1434 }
1435}
1436
1437impl Default for ElicitationSchema {
1438 fn default() -> Self {
1439 Self::new()
1440 }
1441}
1442
1443#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1445#[serde(rename_all = "camelCase")]
1446pub struct ElicitRequestParams {
1447 pub message: String,
1449 pub requested_schema: ElicitationSchema,
1451}
1452
1453#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1455pub struct ElicitRequest {
1456 pub method: String,
1458 pub params: ElicitRequestParams,
1460}
1461
1462impl ElicitRequest {
1463 pub fn new<M: Into<String>>(message: M, schema: ElicitationSchema) -> Self {
1465 Self {
1466 method: "elicitation/create".to_string(),
1467 params: ElicitRequestParams {
1468 message: message.into(),
1469 requested_schema: schema,
1470 },
1471 }
1472 }
1473}
1474
1475#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1477#[serde(rename_all = "lowercase")]
1478pub enum ElicitationAction {
1479 Accept,
1481 Decline,
1483 Cancel,
1485}
1486
1487#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1489pub struct ElicitResult {
1490 pub action: ElicitationAction,
1492 #[serde(skip_serializing_if = "Option::is_none")]
1495 pub content: Option<std::collections::HashMap<String, serde_json::Value>>,
1496 #[serde(skip_serializing_if = "Option::is_none")]
1498 pub _meta: Option<serde_json::Value>,
1499}
1500
1501impl ElicitResult {
1502 pub fn accept(content: std::collections::HashMap<String, serde_json::Value>) -> Self {
1504 Self {
1505 action: ElicitationAction::Accept,
1506 content: Some(content),
1507 _meta: None,
1508 }
1509 }
1510
1511 pub fn decline() -> Self {
1513 Self {
1514 action: ElicitationAction::Decline,
1515 content: None,
1516 _meta: None,
1517 }
1518 }
1519
1520 pub fn cancel() -> Self {
1522 Self {
1523 action: ElicitationAction::Cancel,
1524 content: None,
1525 _meta: None,
1526 }
1527 }
1528
1529 pub fn with_meta(mut self, meta: serde_json::Value) -> Self {
1531 self._meta = Some(meta);
1532 self
1533 }
1534}
1535
1536#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1542pub struct ArgumentInfo {
1543 pub name: String,
1545 pub value: String,
1547}
1548
1549#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1551pub struct CompletionContext {
1552 #[serde(skip_serializing_if = "Option::is_none")]
1554 pub arguments: Option<std::collections::HashMap<String, String>>,
1555}
1556
1557#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1559pub struct PromptReference {
1560 #[serde(rename = "type")]
1562 pub ref_type: String,
1563 pub name: String,
1565 #[serde(skip_serializing_if = "Option::is_none")]
1567 pub title: Option<String>,
1568}
1569
1570impl PromptReference {
1571 pub fn new<N: Into<String>>(name: N) -> Self {
1573 Self {
1574 ref_type: "ref/prompt".to_string(),
1575 name: name.into(),
1576 title: None,
1577 }
1578 }
1579
1580 pub fn with_title<T: Into<String>>(mut self, title: T) -> Self {
1582 self.title = Some(title.into());
1583 self
1584 }
1585}
1586
1587#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1589pub struct ResourceTemplateReference {
1590 #[serde(rename = "type")]
1592 pub ref_type: String,
1593 pub uri: String,
1595}
1596
1597impl ResourceTemplateReference {
1598 pub fn new<U: Into<String>>(uri: U) -> Self {
1600 Self {
1601 ref_type: "ref/resource".to_string(),
1602 uri: uri.into(),
1603 }
1604 }
1605}
1606
1607#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1609#[serde(tag = "type")]
1610pub enum CompletionReference {
1611 #[serde(rename = "ref/prompt")]
1613 Prompt(PromptReferenceData),
1614 #[serde(rename = "ref/resource")]
1616 ResourceTemplate(ResourceTemplateReferenceData),
1617}
1618
1619#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1621pub struct PromptReferenceData {
1622 pub name: String,
1624 #[serde(skip_serializing_if = "Option::is_none")]
1626 pub title: Option<String>,
1627}
1628
1629#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1631pub struct ResourceTemplateReferenceData {
1632 pub uri: String,
1634}
1635
1636#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1638pub struct CompleteRequestParams {
1639 pub argument: ArgumentInfo,
1641 #[serde(rename = "ref")]
1643 pub reference: CompletionReference,
1644 #[serde(skip_serializing_if = "Option::is_none")]
1646 pub context: Option<CompletionContext>,
1647}
1648
1649#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1651pub struct CompleteRequest {
1652 pub method: String,
1654 pub params: CompleteRequestParams,
1656}
1657
1658impl CompleteRequest {
1659 pub fn new(argument: ArgumentInfo, reference: CompletionReference) -> Self {
1661 Self {
1662 method: "completion/complete".to_string(),
1663 params: CompleteRequestParams {
1664 argument,
1665 reference,
1666 context: None,
1667 },
1668 }
1669 }
1670
1671 pub fn with_context(mut self, context: CompletionContext) -> Self {
1673 self.params.context = Some(context);
1674 self
1675 }
1676}
1677
1678#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1680#[serde(rename_all = "camelCase")]
1681pub struct CompletionResponse {
1682 pub values: Vec<String>,
1684 #[serde(skip_serializing_if = "Option::is_none")]
1686 pub total: Option<u32>,
1687 #[serde(skip_serializing_if = "Option::is_none")]
1689 pub has_more: Option<bool>,
1690}
1691
1692impl CompletionResponse {
1693 pub fn new(values: Vec<String>) -> Self {
1695 Self {
1696 values,
1697 total: None,
1698 has_more: None,
1699 }
1700 }
1701
1702 pub fn with_total(mut self, total: u32) -> Self {
1704 self.total = Some(total);
1705 self
1706 }
1707
1708 pub fn with_has_more(mut self, has_more: bool) -> Self {
1710 self.has_more = Some(has_more);
1711 self
1712 }
1713
1714 pub fn paginated(values: Vec<String>, total: u32, has_more: bool) -> Self {
1716 Self {
1717 values,
1718 total: Some(total),
1719 has_more: Some(has_more),
1720 }
1721 }
1722}
1723
1724#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1726pub struct CompleteResult {
1727 pub completion: CompletionResponse,
1729 #[serde(skip_serializing_if = "Option::is_none")]
1731 pub _meta: Option<serde_json::Value>,
1732}
1733
1734impl CompleteResult {
1735 pub fn new(completion: CompletionResponse) -> Self {
1737 Self {
1738 completion,
1739 _meta: None,
1740 }
1741 }
1742
1743 pub fn with_meta(mut self, meta: serde_json::Value) -> Self {
1745 self._meta = Some(meta);
1746 self
1747 }
1748}
1749
1750#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1757#[serde(rename_all = "camelCase")]
1758pub struct ResourceTemplate {
1759 pub name: String,
1761 pub uri_template: String,
1763 #[serde(skip_serializing_if = "Option::is_none")]
1765 pub title: Option<String>,
1766 #[serde(skip_serializing_if = "Option::is_none")]
1768 pub description: Option<String>,
1769 #[serde(skip_serializing_if = "Option::is_none")]
1771 pub mime_type: Option<String>,
1772 #[serde(skip_serializing_if = "Option::is_none")]
1774 pub annotations: Option<Annotations>,
1775 #[serde(skip_serializing_if = "Option::is_none")]
1777 pub _meta: Option<serde_json::Value>,
1778}
1779
1780impl ResourceTemplate {
1781 pub fn new<N: Into<String>, U: Into<String>>(name: N, uri_template: U) -> Self {
1783 Self {
1784 name: name.into(),
1785 uri_template: uri_template.into(),
1786 title: None,
1787 description: None,
1788 mime_type: None,
1789 annotations: None,
1790 _meta: None,
1791 }
1792 }
1793
1794 pub fn with_title<T: Into<String>>(mut self, title: T) -> Self {
1796 self.title = Some(title.into());
1797 self
1798 }
1799
1800 pub fn with_description<D: Into<String>>(mut self, description: D) -> Self {
1802 self.description = Some(description.into());
1803 self
1804 }
1805
1806 pub fn with_mime_type<M: Into<String>>(mut self, mime_type: M) -> Self {
1808 self.mime_type = Some(mime_type.into());
1809 self
1810 }
1811
1812 pub fn with_annotations(mut self, annotations: Annotations) -> Self {
1814 self.annotations = Some(annotations);
1815 self
1816 }
1817
1818 pub fn with_meta(mut self, meta: serde_json::Value) -> Self {
1820 self._meta = Some(meta);
1821 self
1822 }
1823
1824 pub fn file_system<N: Into<String>>(name: N, base_path: &str) -> Self {
1826 Self::new(name, format!("file://{}/{{path}}", base_path))
1827 .with_title("File System Access")
1828 .with_description("Access files within the specified directory")
1829 }
1830
1831 pub fn api_endpoint<N: Into<String>>(name: N, base_url: &str) -> Self {
1833 Self::new(name, format!("{}/{{endpoint}}", base_url))
1834 .with_mime_type("application/json")
1835 .with_title("API Endpoint Access")
1836 .with_description("Access API endpoints")
1837 }
1838
1839 pub fn database_query<N: Into<String>>(name: N) -> Self {
1841 Self::new(name, "db://query/{table}?{query*}")
1842 .with_title("Database Query")
1843 .with_description("Execute database queries")
1844 }
1845}
1846
1847#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
1849pub struct ListResourceTemplatesParams {
1850 #[serde(skip_serializing_if = "Option::is_none")]
1852 pub cursor: Option<String>,
1853}
1854
1855#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1857pub struct ListResourceTemplatesRequest {
1858 #[serde(skip_serializing_if = "Option::is_none")]
1860 pub params: Option<ListResourceTemplatesParams>,
1861}
1862
1863impl ListResourceTemplatesRequest {
1864 pub fn new() -> Self {
1866 Self { params: None }
1867 }
1868
1869 pub fn with_cursor<C: Into<String>>(cursor: C) -> Self {
1871 Self {
1872 params: Some(ListResourceTemplatesParams {
1873 cursor: Some(cursor.into()),
1874 }),
1875 }
1876 }
1877}
1878
1879impl Default for ListResourceTemplatesRequest {
1880 fn default() -> Self {
1881 Self::new()
1882 }
1883}
1884
1885#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1887#[serde(rename_all = "camelCase")]
1888pub struct ListResourceTemplatesResult {
1889 pub resource_templates: Vec<ResourceTemplate>,
1891 #[serde(skip_serializing_if = "Option::is_none")]
1893 pub next_cursor: Option<String>,
1894 #[serde(skip_serializing_if = "Option::is_none")]
1896 pub _meta: Option<serde_json::Value>,
1897}
1898
1899impl ListResourceTemplatesResult {
1900 pub fn new(templates: Vec<ResourceTemplate>) -> Self {
1902 Self {
1903 resource_templates: templates,
1904 next_cursor: None,
1905 _meta: None,
1906 }
1907 }
1908
1909 pub fn paginated(templates: Vec<ResourceTemplate>, next_cursor: String) -> Self {
1911 Self {
1912 resource_templates: templates,
1913 next_cursor: Some(next_cursor),
1914 _meta: None,
1915 }
1916 }
1917
1918 pub fn with_meta(mut self, meta: serde_json::Value) -> Self {
1920 self._meta = Some(meta);
1921 self
1922 }
1923}
1924
1925#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
1931pub struct PingParams {
1932 #[serde(skip_serializing_if = "Option::is_none")]
1934 pub _meta: Option<serde_json::Value>,
1935}
1936
1937impl PingParams {
1938 pub fn new() -> Self {
1940 Self { _meta: None }
1941 }
1942
1943 pub fn with_meta(mut self, meta: serde_json::Value) -> Self {
1945 self._meta = Some(meta);
1946 self
1947 }
1948}
1949
1950#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1952pub struct PingRequest {
1953 pub method: String,
1955 #[serde(skip_serializing_if = "Option::is_none")]
1957 pub params: Option<PingParams>,
1958}
1959
1960impl PingRequest {
1961 pub fn new() -> Self {
1963 Self {
1964 method: "ping".to_string(),
1965 params: None,
1966 }
1967 }
1968
1969 pub fn with_meta(meta: serde_json::Value) -> Self {
1971 Self {
1972 method: "ping".to_string(),
1973 params: Some(PingParams::new().with_meta(meta)),
1974 }
1975 }
1976}
1977
1978impl Default for PingRequest {
1979 fn default() -> Self {
1980 Self::new()
1981 }
1982}
1983
1984#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
1986pub struct PingResult {
1987 #[serde(skip_serializing_if = "Option::is_none")]
1989 pub _meta: Option<serde_json::Value>,
1990}
1991
1992impl PingResult {
1993 pub fn new() -> Self {
1995 Self { _meta: None }
1996 }
1997
1998 pub fn with_meta(meta: serde_json::Value) -> Self {
2000 Self { _meta: Some(meta) }
2001 }
2002}
2003
2004impl Default for PingResult {
2005 fn default() -> Self {
2006 Self::new()
2007 }
2008}
2009
2010#[derive(Debug, Clone, Serialize, Deserialize)]
2016pub struct Root {
2017 pub uri: Uri,
2019 #[serde(skip_serializing_if = "Option::is_none")]
2021 pub name: Option<String>,
2022}
2023
2024#[derive(Debug, Clone, Serialize, Deserialize)]
2026pub struct ListRootsRequest;
2027
2028#[derive(Debug, Clone, Serialize, Deserialize)]
2030pub struct ListRootsResult {
2031 pub roots: Vec<Root>,
2033}
2034
2035#[derive(Debug, Clone, Serialize, Deserialize)]
2037pub struct RootsListChangedNotification;
2038
2039#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2041pub struct EmptyResult {}
2042
2043#[cfg(test)]
2044mod tests {
2045 use super::*;
2046
2047 #[test]
2048 fn test_serialize_deserialize() {
2049 let tool = Tool {
2050 name: "test_tool".to_string(),
2051 title: Some("Test Tool".to_string()),
2052 description: Some("A test tool".to_string()),
2053 input_schema: ToolInputSchema {
2054 schema_type: "object".to_string(),
2055 properties: None,
2056 required: None,
2057 additional_properties: None,
2058 },
2059 output_schema: None,
2060 annotations: None,
2061 meta: None,
2062 };
2063
2064 let json = serde_json::to_string(&tool).unwrap();
2065 let deserialized: Tool = serde_json::from_str(&json).unwrap();
2066 assert_eq!(tool.name, deserialized.name);
2067 }
2068
2069 #[test]
2070 fn test_content_types() {
2071 let text_content = ContentBlock::Text(TextContent {
2072 text: "Hello, World!".to_string(),
2073 annotations: None,
2074 meta: None,
2075 });
2076
2077 let json = serde_json::to_string(&text_content).unwrap();
2078 let _deserialized: ContentBlock = serde_json::from_str(&json).unwrap();
2079
2080 let _compatible: Content = text_content;
2082 }
2083
2084 #[test]
2085 fn test_elicitation_schema_builder() {
2086 let schema = ElicitationSchema::new()
2087 .add_string_property("username", true, Some("Your username".to_string()))
2088 .add_number_property(
2089 "age",
2090 false,
2091 Some("Your age".to_string()),
2092 Some(0.0),
2093 Some(150.0),
2094 )
2095 .add_boolean_property(
2096 "subscribe",
2097 true,
2098 Some("Subscribe to newsletter".to_string()),
2099 Some(false),
2100 )
2101 .add_enum_property(
2102 "role",
2103 true,
2104 Some("Your role".to_string()),
2105 vec!["admin".to_string(), "user".to_string(), "guest".to_string()],
2106 None,
2107 );
2108
2109 assert_eq!(schema.schema_type, "object");
2110 assert_eq!(schema.properties.len(), 4);
2111 assert_eq!(schema.required.as_ref().unwrap().len(), 3);
2112
2113 let username_prop = &schema.properties["username"];
2115 match username_prop {
2116 PrimitiveSchemaDefinition::String { description, .. } => {
2117 assert_eq!(description.as_ref().unwrap(), "Your username");
2118 }
2119 _ => panic!("Expected string property"),
2120 }
2121
2122 let age_prop = &schema.properties["age"];
2124 match age_prop {
2125 PrimitiveSchemaDefinition::Number {
2126 minimum, maximum, ..
2127 } => {
2128 assert_eq!(*minimum, Some(0.0));
2129 assert_eq!(*maximum, Some(150.0));
2130 }
2131 _ => panic!("Expected number property"),
2132 }
2133 }
2134
2135 #[test]
2136 fn test_elicit_request_serialization() {
2137 let schema = ElicitationSchema::new()
2138 .add_string_property("name", true, Some("Your name".to_string()))
2139 .add_boolean_property("confirm", true, None, Some(false));
2140
2141 let request = ElicitRequest::new("Please provide your details", schema);
2142
2143 let json = serde_json::to_string(&request).unwrap();
2145
2146 assert!(json.contains("elicitation/create"));
2148 assert!(json.contains("Please provide your details"));
2149 assert!(json.contains("requestedSchema"));
2150
2151 let deserialized: ElicitRequest = serde_json::from_str(&json).unwrap();
2153 assert_eq!(deserialized.method, "elicitation/create");
2154 assert_eq!(deserialized.params.message, "Please provide your details");
2155 }
2156
2157 #[test]
2158 fn test_elicit_result_actions() {
2159 let mut content = std::collections::HashMap::new();
2161 content.insert(
2162 "name".to_string(),
2163 serde_json::Value::String("John".to_string()),
2164 );
2165 content.insert(
2166 "age".to_string(),
2167 serde_json::Value::Number(serde_json::Number::from(30)),
2168 );
2169
2170 let accept_result = ElicitResult::accept(content);
2171 assert_eq!(accept_result.action, ElicitationAction::Accept);
2172 assert!(accept_result.content.is_some());
2173
2174 let decline_result = ElicitResult::decline();
2176 assert_eq!(decline_result.action, ElicitationAction::Decline);
2177 assert!(decline_result.content.is_none());
2178
2179 let cancel_result = ElicitResult::cancel();
2181 assert_eq!(cancel_result.action, ElicitationAction::Cancel);
2182 assert!(cancel_result.content.is_none());
2183 }
2184
2185 #[test]
2186 fn test_elicit_result_serialization_compliance() {
2187 let mut content = std::collections::HashMap::new();
2189 content.insert(
2190 "field1".to_string(),
2191 serde_json::Value::String("value1".to_string()),
2192 );
2193
2194 let result = ElicitResult::accept(content);
2195 let json = serde_json::to_string(&result).unwrap();
2196
2197 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2199
2200 assert_eq!(parsed["action"].as_str().unwrap(), "accept");
2202
2203 assert!(parsed["content"].is_object());
2205 assert_eq!(parsed["content"]["field1"].as_str().unwrap(), "value1");
2206 }
2207
2208 #[test]
2209 fn test_primitive_schema_serialization() {
2210 let string_schema = PrimitiveSchemaDefinition::String {
2212 title: Some("Title".to_string()),
2213 description: Some("Description".to_string()),
2214 format: Some("email".to_string()),
2215 min_length: Some(1),
2216 max_length: Some(100),
2217 enum_values: None,
2218 enum_names: None,
2219 };
2220
2221 let json = serde_json::to_string(&string_schema).unwrap();
2222 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2223
2224 assert_eq!(parsed["type"].as_str().unwrap(), "string");
2225 assert_eq!(parsed["format"].as_str().unwrap(), "email");
2226 assert_eq!(parsed["minLength"].as_u64().unwrap(), 1);
2227 assert_eq!(parsed["maxLength"].as_u64().unwrap(), 100);
2228
2229 let enum_schema = PrimitiveSchemaDefinition::String {
2231 title: None,
2232 description: Some("Select option".to_string()),
2233 format: None,
2234 min_length: None,
2235 max_length: None,
2236 enum_values: Some(vec!["option1".to_string(), "option2".to_string()]),
2237 enum_names: Some(vec!["Option 1".to_string(), "Option 2".to_string()]),
2238 };
2239
2240 let enum_json = serde_json::to_string(&enum_schema).unwrap();
2241 let enum_parsed: serde_json::Value = serde_json::from_str(&enum_json).unwrap();
2242
2243 assert_eq!(enum_parsed["type"].as_str().unwrap(), "string");
2244 assert_eq!(enum_parsed["enum"].as_array().unwrap().len(), 2);
2245 assert_eq!(enum_parsed["enumNames"].as_array().unwrap().len(), 2);
2246 }
2247
2248 #[test]
2249 fn test_server_request_with_elicitation() {
2250 let schema = ElicitationSchema::new().add_string_property(
2251 "email",
2252 true,
2253 Some("Your email address".to_string()),
2254 );
2255
2256 let request_params = ElicitRequestParams {
2257 message: "Please provide your email".to_string(),
2258 requested_schema: schema,
2259 };
2260
2261 let server_request = ServerRequest::ElicitationCreate(request_params);
2262
2263 let json = serde_json::to_string(&server_request).unwrap();
2265 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2266
2267 assert_eq!(parsed["method"].as_str().unwrap(), "elicitation/create");
2268 assert!(parsed["message"].is_string());
2269 assert!(parsed["requestedSchema"].is_object());
2270 }
2271
2272 #[test]
2273 fn test_completion_request_serialization() {
2274 let argument = ArgumentInfo {
2275 name: "file_path".to_string(),
2276 value: "/home/user/doc".to_string(),
2277 };
2278
2279 let reference = CompletionReference::ResourceTemplate(ResourceTemplateReferenceData {
2280 uri: "/files/{path}".to_string(),
2281 });
2282
2283 let request = CompleteRequest::new(argument, reference);
2284
2285 let json = serde_json::to_string(&request).unwrap();
2287 assert!(json.contains("completion/complete"));
2288 assert!(json.contains("file_path"));
2289 assert!(json.contains("/home/user/doc"));
2290
2291 let deserialized: CompleteRequest = serde_json::from_str(&json).unwrap();
2293 assert_eq!(deserialized.method, "completion/complete");
2294 assert_eq!(deserialized.params.argument.name, "file_path");
2295 }
2296
2297 #[test]
2298 fn test_completion_reference_types() {
2299 let prompt_ref = CompletionReference::Prompt(PromptReferenceData {
2301 name: "code_review".to_string(),
2302 title: Some("Code Review Assistant".to_string()),
2303 });
2304
2305 let json = serde_json::to_string(&prompt_ref).unwrap();
2306 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2307 assert_eq!(parsed["type"].as_str().unwrap(), "ref/prompt");
2308 assert_eq!(parsed["name"].as_str().unwrap(), "code_review");
2309
2310 let resource_ref = CompletionReference::ResourceTemplate(ResourceTemplateReferenceData {
2312 uri: "/api/{endpoint}".to_string(),
2313 });
2314
2315 let json = serde_json::to_string(&resource_ref).unwrap();
2316 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2317 assert_eq!(parsed["type"].as_str().unwrap(), "ref/resource");
2318 assert_eq!(parsed["uri"].as_str().unwrap(), "/api/{endpoint}");
2319 }
2320
2321 #[test]
2322 fn test_completion_response_with_pagination() {
2323 let simple =
2325 CompletionResponse::new(vec!["file1.txt".to_string(), "file2.txt".to_string()]);
2326 assert_eq!(simple.values.len(), 2);
2327 assert!(simple.total.is_none());
2328
2329 let paginated = CompletionResponse::paginated(
2331 vec!["item1".to_string(), "item2".to_string()],
2332 100,
2333 true,
2334 );
2335 assert_eq!(paginated.values.len(), 2);
2336 assert_eq!(paginated.total, Some(100));
2337 assert_eq!(paginated.has_more, Some(true));
2338
2339 let json = serde_json::to_string(&paginated).unwrap();
2341 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2342 assert_eq!(parsed["total"].as_u64().unwrap(), 100);
2343 assert!(parsed["hasMore"].as_bool().unwrap());
2344 assert_eq!(parsed["values"].as_array().unwrap().len(), 2);
2345 }
2346
2347 #[test]
2348 fn test_complete_result_structure() {
2349 let completion = CompletionResponse::paginated(
2350 vec!["option1".to_string(), "option2".to_string()],
2351 50,
2352 false,
2353 );
2354
2355 let result = CompleteResult::new(completion);
2356
2357 let json = serde_json::to_string(&result).unwrap();
2359 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2360
2361 assert!(parsed["completion"].is_object());
2363 assert!(parsed["completion"]["values"].is_array());
2364 assert_eq!(parsed["completion"]["total"].as_u64().unwrap(), 50);
2365 assert!(!parsed["completion"]["hasMore"].as_bool().unwrap());
2366
2367 let deserialized: CompleteResult = serde_json::from_str(&json).unwrap();
2369 assert_eq!(deserialized.completion.values.len(), 2);
2370 assert_eq!(deserialized.completion.total, Some(50));
2371 }
2372
2373 #[test]
2374 fn test_completion_context() {
2375 let mut context_args = std::collections::HashMap::new();
2376 context_args.insert("user_id".to_string(), "12345".to_string());
2377 context_args.insert("project".to_string(), "main".to_string());
2378
2379 let context = CompletionContext {
2380 arguments: Some(context_args),
2381 };
2382
2383 let argument = ArgumentInfo {
2384 name: "endpoint".to_string(),
2385 value: "api".to_string(),
2386 };
2387
2388 let reference = CompletionReference::ResourceTemplate(ResourceTemplateReferenceData {
2389 uri: "/projects/{project}/endpoints/{endpoint}".to_string(),
2390 });
2391
2392 let request = CompleteRequest::new(argument, reference).with_context(context);
2393
2394 let json = serde_json::to_string(&request).unwrap();
2396 assert!(json.contains("user_id"));
2397 assert!(json.contains("12345"));
2398 assert!(json.contains("project"));
2399 assert!(json.contains("main"));
2400 }
2401
2402 #[test]
2403 fn test_client_request_with_completion() {
2404 let argument = ArgumentInfo {
2405 name: "query".to_string(),
2406 value: "hello".to_string(),
2407 };
2408
2409 let reference = CompletionReference::Prompt(PromptReferenceData {
2410 name: "greeting".to_string(),
2411 title: None,
2412 });
2413
2414 let complete_params = CompleteRequestParams {
2415 argument,
2416 reference,
2417 context: None,
2418 };
2419
2420 let client_request = ClientRequest::Complete(complete_params);
2421
2422 let json = serde_json::to_string(&client_request).unwrap();
2424 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2425
2426 assert_eq!(parsed["method"].as_str().unwrap(), "completion/complete");
2427 assert_eq!(parsed["argument"]["name"].as_str().unwrap(), "query");
2428 assert_eq!(parsed["ref"]["type"].as_str().unwrap(), "ref/prompt");
2429 }
2430
2431 #[test]
2432 fn test_resource_template_creation() {
2433 let template = ResourceTemplate::new("file_access", "/files/{path}");
2435 assert_eq!(template.name, "file_access");
2436 assert_eq!(template.uri_template, "/files/{path}");
2437
2438 let enhanced_template = ResourceTemplate::new("api_access", "/api/{endpoint}")
2440 .with_title("API Access")
2441 .with_description("Access to REST API endpoints")
2442 .with_mime_type("application/json");
2443
2444 assert_eq!(enhanced_template.title, Some("API Access".to_string()));
2445 assert_eq!(
2446 enhanced_template.description,
2447 Some("Access to REST API endpoints".to_string())
2448 );
2449 assert_eq!(
2450 enhanced_template.mime_type,
2451 Some("application/json".to_string())
2452 );
2453 }
2454
2455 #[test]
2456 fn test_resource_template_presets() {
2457 let fs_template = ResourceTemplate::file_system("files", "/home/user");
2459 assert_eq!(fs_template.name, "files");
2460 assert_eq!(fs_template.uri_template, "file:///home/user/{path}");
2461 assert_eq!(fs_template.title, Some("File System Access".to_string()));
2462
2463 let api_template = ResourceTemplate::api_endpoint("api", "https://api.example.com");
2465 assert_eq!(
2466 api_template.uri_template,
2467 "https://api.example.com/{endpoint}"
2468 );
2469 assert_eq!(api_template.mime_type, Some("application/json".to_string()));
2470
2471 let db_template = ResourceTemplate::database_query("queries");
2473 assert_eq!(db_template.uri_template, "db://query/{table}?{query*}");
2474 assert_eq!(db_template.title, Some("Database Query".to_string()));
2475 }
2476
2477 #[test]
2478 fn test_resource_template_serialization() {
2479 let template = ResourceTemplate::new("test_template", "/test/{id}")
2480 .with_title("Test Template")
2481 .with_description("A template for testing")
2482 .with_mime_type("text/plain");
2483
2484 let json = serde_json::to_string(&template).unwrap();
2485 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2486
2487 assert_eq!(parsed["name"].as_str().unwrap(), "test_template");
2488 assert_eq!(parsed["uriTemplate"].as_str().unwrap(), "/test/{id}");
2489 assert_eq!(parsed["title"].as_str().unwrap(), "Test Template");
2490 assert_eq!(
2491 parsed["description"].as_str().unwrap(),
2492 "A template for testing"
2493 );
2494 assert_eq!(parsed["mimeType"].as_str().unwrap(), "text/plain");
2495
2496 let deserialized: ResourceTemplate = serde_json::from_str(&json).unwrap();
2498 assert_eq!(deserialized.name, "test_template");
2499 assert_eq!(deserialized.uri_template, "/test/{id}");
2500 }
2501
2502 #[test]
2503 fn test_list_resource_templates_request() {
2504 let request = ListResourceTemplatesRequest::new();
2506 assert!(request.params.is_none());
2507
2508 let paginated_request = ListResourceTemplatesRequest::with_cursor("cursor123");
2510 assert!(paginated_request.params.is_some());
2511 assert_eq!(
2512 paginated_request.params.unwrap().cursor,
2513 Some("cursor123".to_string())
2514 );
2515
2516 let json = serde_json::to_string(&request).unwrap();
2518 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2519
2520 assert!(parsed.as_object().unwrap().is_empty());
2522 }
2523
2524 #[test]
2525 fn test_list_resource_templates_result() {
2526 let templates = vec![
2527 ResourceTemplate::new("template1", "/api/{endpoint}"),
2528 ResourceTemplate::new("template2", "/files/{path}"),
2529 ];
2530
2531 let result = ListResourceTemplatesResult::new(templates.clone());
2533 assert_eq!(result.resource_templates.len(), 2);
2534 assert!(result.next_cursor.is_none());
2535
2536 let paginated_result =
2538 ListResourceTemplatesResult::paginated(templates, "next_cursor".to_string());
2539 assert_eq!(paginated_result.resource_templates.len(), 2);
2540 assert_eq!(
2541 paginated_result.next_cursor,
2542 Some("next_cursor".to_string())
2543 );
2544
2545 let json = serde_json::to_string(&paginated_result).unwrap();
2547 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2548
2549 assert!(parsed["resourceTemplates"].is_array());
2550 assert_eq!(parsed["resourceTemplates"].as_array().unwrap().len(), 2);
2551 assert_eq!(parsed["nextCursor"].as_str().unwrap(), "next_cursor");
2552
2553 let deserialized: ListResourceTemplatesResult = serde_json::from_str(&json).unwrap();
2555 assert_eq!(deserialized.resource_templates.len(), 2);
2556 assert_eq!(deserialized.next_cursor, Some("next_cursor".to_string()));
2557 }
2558
2559 #[test]
2560 fn test_client_request_with_resource_templates() {
2561 let request = ListResourceTemplatesRequest::with_cursor("abc123");
2562 let client_request = ClientRequest::ListResourceTemplates(request);
2563
2564 let json = serde_json::to_string(&client_request).unwrap();
2566 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2567
2568 assert_eq!(
2569 parsed["method"].as_str().unwrap(),
2570 "resources/templates/list"
2571 );
2572 assert_eq!(parsed["params"]["cursor"].as_str().unwrap(), "abc123");
2573 }
2574
2575 #[test]
2576 fn test_complex_uri_templates() {
2577 let complex_templates = vec![
2579 ResourceTemplate::new(
2580 "github",
2581 "https://api.github.com/repos/{owner}/{repo}/contents/{+path}",
2582 ),
2583 ResourceTemplate::new("search", "/search{?q,type,sort,order}"),
2584 ResourceTemplate::new("matrix", "/matrix{;x,y}/data"),
2585 ResourceTemplate::new("fragment", "/documents/{id}{#section}"),
2586 ];
2587
2588 for template in complex_templates {
2589 let json = serde_json::to_string(&template).unwrap();
2590 let deserialized: ResourceTemplate = serde_json::from_str(&json).unwrap();
2591 assert_eq!(template.uri_template, deserialized.uri_template);
2592 }
2593 }
2594
2595 #[test]
2596 fn test_resource_template_with_annotations() {
2597 let annotations = Annotations {
2598 priority: Some(1.0),
2599 ..Default::default()
2600 };
2601
2602 let template =
2603 ResourceTemplate::new("important", "/critical/{id}").with_annotations(annotations);
2604
2605 assert!(template.annotations.is_some());
2606 assert_eq!(template.annotations.unwrap().priority, Some(1.0));
2607 }
2608
2609 #[test]
2610 fn test_ping_request_creation() {
2611 let ping = PingRequest::new();
2613 assert_eq!(ping.method, "ping");
2614 assert!(ping.params.is_none());
2615
2616 let meta_value = serde_json::json!({"timestamp": "2025-08-29T12:00:00Z"});
2618 let ping_with_meta = PingRequest::with_meta(meta_value.clone());
2619 assert_eq!(ping_with_meta.method, "ping");
2620 assert!(ping_with_meta.params.is_some());
2621 assert_eq!(ping_with_meta.params.unwrap()._meta, Some(meta_value));
2622 }
2623
2624 #[test]
2625 fn test_ping_serialization() {
2626 let ping = PingRequest::new();
2628 let json = serde_json::to_string(&ping).unwrap();
2629 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2630 assert_eq!(parsed["method"].as_str().unwrap(), "ping");
2631
2632 let deserialized: PingRequest = serde_json::from_str(&json).unwrap();
2634 assert_eq!(deserialized.method, "ping");
2635
2636 let meta_value = serde_json::json!({"client": "test", "version": "1.0"});
2638 let ping_with_meta = PingRequest::with_meta(meta_value.clone());
2639 let json_with_meta = serde_json::to_string(&ping_with_meta).unwrap();
2640 let parsed_meta: serde_json::Value = serde_json::from_str(&json_with_meta).unwrap();
2641
2642 assert!(parsed_meta["params"].is_object());
2643 assert_eq!(
2644 parsed_meta["params"]["_meta"]["client"].as_str().unwrap(),
2645 "test"
2646 );
2647 }
2648
2649 #[test]
2650 fn test_ping_result() {
2651 let result = PingResult::new();
2653 assert!(result._meta.is_none());
2654
2655 let meta = serde_json::json!({"latency_ms": 42});
2657 let result_with_meta = PingResult::with_meta(meta.clone());
2658 assert_eq!(result_with_meta._meta, Some(meta));
2659
2660 let json = serde_json::to_string(&result).unwrap();
2662 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2663 assert!(parsed.as_object().unwrap().is_empty());
2665
2666 let deserialized: PingResult = serde_json::from_str(&json).unwrap();
2668 assert!(deserialized._meta.is_none());
2669 }
2670
2671 #[test]
2672 fn test_ping_params() {
2673 let params = PingParams::new();
2675 assert!(params._meta.is_none());
2676
2677 let meta = serde_json::json!({"timeout": 5000});
2679 let params_with_meta = PingParams::new().with_meta(meta.clone());
2680 assert_eq!(params_with_meta._meta, Some(meta));
2681
2682 let json = serde_json::to_string(¶ms).unwrap();
2684 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2685 assert!(parsed.as_object().unwrap().is_empty());
2686 }
2687
2688 #[test]
2689 fn test_server_request_with_ping() {
2690 let ping_params = PingParams::new();
2691 let server_request = ServerRequest::Ping(ping_params);
2692
2693 let json = serde_json::to_string(&server_request).unwrap();
2695 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2696
2697 assert_eq!(parsed["method"].as_str().unwrap(), "ping");
2698 }
2699
2700 #[test]
2701 fn test_client_request_with_ping() {
2702 let ping_params = PingParams::new();
2703 let client_request = ClientRequest::Ping(ping_params);
2704
2705 let json = serde_json::to_string(&client_request).unwrap();
2707 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2708
2709 assert_eq!(parsed["method"].as_str().unwrap(), "ping");
2710 }
2711
2712 #[test]
2713 fn test_ping_protocol_bidirectional() {
2714 let meta = serde_json::json!({"source": "test"});
2716
2717 let client_ping = ClientRequest::Ping(PingParams::new().with_meta(meta.clone()));
2719 let client_json = serde_json::to_string(&client_ping).unwrap();
2720
2721 let server_ping = ServerRequest::Ping(PingParams::new().with_meta(meta.clone()));
2723 let server_json = serde_json::to_string(&server_ping).unwrap();
2724
2725 let client_parsed: serde_json::Value = serde_json::from_str(&client_json).unwrap();
2727 let server_parsed: serde_json::Value = serde_json::from_str(&server_json).unwrap();
2728
2729 assert_eq!(client_parsed["method"], server_parsed["method"]);
2730 assert_eq!(
2731 client_parsed["_meta"]["source"],
2732 server_parsed["_meta"]["source"]
2733 );
2734 }
2735}