1use serde::{Deserialize, Serialize};
7use serde_json::Value;
8
9use crate::error::JsonRpcError;
10
11pub const JSONRPC_VERSION: &str = "2.0";
13
14pub const LATEST_PROTOCOL_VERSION: &str = "2025-03-26";
16
17pub const SUPPORTED_PROTOCOL_VERSIONS: &[&str] = &["2025-03-26"];
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct JsonRpcRequest {
23 pub jsonrpc: String,
25 pub id: RequestId,
27 pub method: String,
29 #[serde(default, skip_serializing_if = "Option::is_none")]
31 pub params: Option<Value>,
32}
33
34impl JsonRpcRequest {
35 pub fn new(id: impl Into<RequestId>, method: impl Into<String>) -> Self {
37 Self {
38 jsonrpc: JSONRPC_VERSION.to_string(),
39 id: id.into(),
40 method: method.into(),
41 params: None,
42 }
43 }
44
45 pub fn with_params(mut self, params: Value) -> Self {
47 self.params = Some(params);
48 self
49 }
50
51 pub fn validate(&self) -> Result<(), JsonRpcError> {
54 if self.jsonrpc != JSONRPC_VERSION {
55 return Err(JsonRpcError::invalid_request(format!(
56 "Invalid JSON-RPC version: expected '{}', got '{}'",
57 JSONRPC_VERSION, self.jsonrpc
58 )));
59 }
60 Ok(())
61 }
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct JsonRpcResultResponse {
67 pub jsonrpc: String,
69 pub id: RequestId,
71 pub result: Value,
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct JsonRpcErrorResponse {
78 pub jsonrpc: String,
80 #[serde(skip_serializing_if = "Option::is_none")]
82 pub id: Option<RequestId>,
83 pub error: JsonRpcError,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
89#[serde(untagged)]
90pub enum JsonRpcResponse {
91 Result(JsonRpcResultResponse),
93 Error(JsonRpcErrorResponse),
95}
96
97impl JsonRpcResponse {
98 pub fn result(id: RequestId, result: Value) -> Self {
100 Self::Result(JsonRpcResultResponse {
101 jsonrpc: JSONRPC_VERSION.to_string(),
102 id,
103 result,
104 })
105 }
106
107 pub fn error(id: Option<RequestId>, error: JsonRpcError) -> Self {
109 Self::Error(JsonRpcErrorResponse {
110 jsonrpc: JSONRPC_VERSION.to_string(),
111 id,
112 error,
113 })
114 }
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize)]
119#[serde(untagged)]
120pub enum JsonRpcMessage {
121 Single(JsonRpcRequest),
123 Batch(Vec<JsonRpcRequest>),
125}
126
127impl JsonRpcMessage {
128 pub fn is_batch(&self) -> bool {
130 matches!(self, JsonRpcMessage::Batch(_))
131 }
132
133 pub fn len(&self) -> usize {
135 match self {
136 JsonRpcMessage::Single(_) => 1,
137 JsonRpcMessage::Batch(batch) => batch.len(),
138 }
139 }
140
141 pub fn is_empty(&self) -> bool {
143 self.len() == 0
144 }
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize)]
149#[serde(untagged)]
150pub enum JsonRpcResponseMessage {
151 Single(JsonRpcResponse),
153 Batch(Vec<JsonRpcResponse>),
155}
156
157impl JsonRpcResponseMessage {
158 pub fn is_batch(&self) -> bool {
160 matches!(self, JsonRpcResponseMessage::Batch(_))
161 }
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct JsonRpcNotification {
167 pub jsonrpc: String,
168 pub method: String,
169 #[serde(default, skip_serializing_if = "Option::is_none")]
170 pub params: Option<Value>,
171}
172
173impl JsonRpcNotification {
174 pub fn new(method: impl Into<String>) -> Self {
175 Self {
176 jsonrpc: JSONRPC_VERSION.to_string(),
177 method: method.into(),
178 params: None,
179 }
180 }
181
182 pub fn with_params(mut self, params: Value) -> Self {
183 self.params = Some(params);
184 self
185 }
186}
187
188pub mod notifications {
190 pub const INITIALIZED: &str = "notifications/initialized";
192 pub const CANCELLED: &str = "notifications/cancelled";
194 pub const PROGRESS: &str = "notifications/progress";
196 pub const TOOLS_LIST_CHANGED: &str = "notifications/tools/list_changed";
198 pub const RESOURCES_LIST_CHANGED: &str = "notifications/resources/list_changed";
200 pub const RESOURCE_UPDATED: &str = "notifications/resources/updated";
202 pub const PROMPTS_LIST_CHANGED: &str = "notifications/prompts/list_changed";
204 pub const ROOTS_LIST_CHANGED: &str = "notifications/roots/list_changed";
206 pub const MESSAGE: &str = "notifications/message";
208 pub const TASK_STATUS_CHANGED: &str = "notifications/tasks/status_changed";
210 pub const ELICITATION_COMPLETE: &str = "notifications/elicitation/complete";
212}
213
214#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
218#[serde(rename_all = "lowercase")]
219pub enum LogLevel {
220 Emergency,
222 Alert,
224 Critical,
226 Error,
228 Warning,
230 Notice,
232 #[default]
234 Info,
235 Debug,
237}
238
239impl std::fmt::Display for LogLevel {
240 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
241 match self {
242 LogLevel::Emergency => write!(f, "emergency"),
243 LogLevel::Alert => write!(f, "alert"),
244 LogLevel::Critical => write!(f, "critical"),
245 LogLevel::Error => write!(f, "error"),
246 LogLevel::Warning => write!(f, "warning"),
247 LogLevel::Notice => write!(f, "notice"),
248 LogLevel::Info => write!(f, "info"),
249 LogLevel::Debug => write!(f, "debug"),
250 }
251 }
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct LoggingMessageParams {
257 pub level: LogLevel,
259 #[serde(skip_serializing_if = "Option::is_none")]
261 pub logger: Option<String>,
262 #[serde(skip_serializing_if = "Option::is_none")]
264 pub data: Option<Value>,
265}
266
267impl LoggingMessageParams {
268 pub fn new(level: LogLevel) -> Self {
270 Self {
271 level,
272 logger: None,
273 data: None,
274 }
275 }
276
277 pub fn with_logger(mut self, logger: impl Into<String>) -> Self {
279 self.logger = Some(logger.into());
280 self
281 }
282
283 pub fn with_data(mut self, data: Value) -> Self {
285 self.data = Some(data);
286 self
287 }
288}
289
290#[derive(Debug, Clone, Deserialize)]
292pub struct SetLogLevelParams {
293 pub level: LogLevel,
295}
296
297#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
299#[serde(untagged)]
300pub enum RequestId {
301 String(String),
302 Number(i64),
303}
304
305impl From<String> for RequestId {
306 fn from(s: String) -> Self {
307 RequestId::String(s)
308 }
309}
310
311impl From<&str> for RequestId {
312 fn from(s: &str) -> Self {
313 RequestId::String(s.to_string())
314 }
315}
316
317impl From<i64> for RequestId {
318 fn from(n: i64) -> Self {
319 RequestId::Number(n)
320 }
321}
322
323impl From<i32> for RequestId {
324 fn from(n: i32) -> Self {
325 RequestId::Number(n as i64)
326 }
327}
328
329#[derive(Debug, Clone)]
335pub enum McpRequest {
336 Initialize(InitializeParams),
338 ListTools(ListToolsParams),
340 CallTool(CallToolParams),
342 ListResources(ListResourcesParams),
344 ListResourceTemplates(ListResourceTemplatesParams),
346 ReadResource(ReadResourceParams),
348 SubscribeResource(SubscribeResourceParams),
350 UnsubscribeResource(UnsubscribeResourceParams),
352 ListPrompts(ListPromptsParams),
354 GetPrompt(GetPromptParams),
356 EnqueueTask(EnqueueTaskParams),
358 ListTasks(ListTasksParams),
360 GetTaskInfo(GetTaskInfoParams),
362 GetTaskResult(GetTaskResultParams),
364 CancelTask(CancelTaskParams),
366 Ping,
368 SetLoggingLevel(SetLogLevelParams),
370 Complete(CompleteParams),
372 Unknown {
374 method: String,
375 params: Option<Value>,
376 },
377}
378
379impl McpRequest {
380 pub fn method_name(&self) -> &str {
382 match self {
383 McpRequest::Initialize(_) => "initialize",
384 McpRequest::ListTools(_) => "tools/list",
385 McpRequest::CallTool(_) => "tools/call",
386 McpRequest::ListResources(_) => "resources/list",
387 McpRequest::ListResourceTemplates(_) => "resources/templates/list",
388 McpRequest::ReadResource(_) => "resources/read",
389 McpRequest::SubscribeResource(_) => "resources/subscribe",
390 McpRequest::UnsubscribeResource(_) => "resources/unsubscribe",
391 McpRequest::ListPrompts(_) => "prompts/list",
392 McpRequest::GetPrompt(_) => "prompts/get",
393 McpRequest::EnqueueTask(_) => "tasks/enqueue",
394 McpRequest::ListTasks(_) => "tasks/list",
395 McpRequest::GetTaskInfo(_) => "tasks/get",
396 McpRequest::GetTaskResult(_) => "tasks/result",
397 McpRequest::CancelTask(_) => "tasks/cancel",
398 McpRequest::Ping => "ping",
399 McpRequest::SetLoggingLevel(_) => "logging/setLevel",
400 McpRequest::Complete(_) => "completion/complete",
401 McpRequest::Unknown { method, .. } => method,
402 }
403 }
404}
405
406#[derive(Debug, Clone)]
408pub enum McpNotification {
409 Initialized,
411 Cancelled(CancelledParams),
413 Progress(ProgressParams),
415 RootsListChanged,
417 Unknown {
419 method: String,
420 params: Option<Value>,
421 },
422}
423
424#[derive(Debug, Clone, Serialize, Deserialize)]
426#[serde(rename_all = "camelCase")]
427pub struct CancelledParams {
428 pub request_id: RequestId,
430 #[serde(skip_serializing_if = "Option::is_none")]
432 pub reason: Option<String>,
433}
434
435#[derive(Debug, Clone, Serialize, Deserialize)]
437#[serde(rename_all = "camelCase")]
438pub struct ProgressParams {
439 pub progress_token: ProgressToken,
441 pub progress: f64,
443 #[serde(skip_serializing_if = "Option::is_none")]
445 pub total: Option<f64>,
446 #[serde(skip_serializing_if = "Option::is_none")]
448 pub message: Option<String>,
449}
450
451#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
453#[serde(untagged)]
454pub enum ProgressToken {
455 String(String),
456 Number(i64),
457}
458
459#[derive(Debug, Clone, Default, Serialize, Deserialize)]
461#[serde(rename_all = "camelCase")]
462pub struct RequestMeta {
463 #[serde(skip_serializing_if = "Option::is_none")]
465 pub progress_token: Option<ProgressToken>,
466}
467
468#[derive(Debug, Clone, Serialize)]
470#[serde(untagged)]
471pub enum McpResponse {
472 Initialize(InitializeResult),
473 ListTools(ListToolsResult),
474 CallTool(CallToolResult),
475 ListResources(ListResourcesResult),
476 ListResourceTemplates(ListResourceTemplatesResult),
477 ReadResource(ReadResourceResult),
478 SubscribeResource(EmptyResult),
479 UnsubscribeResource(EmptyResult),
480 ListPrompts(ListPromptsResult),
481 GetPrompt(GetPromptResult),
482 EnqueueTask(EnqueueTaskResult),
483 ListTasks(ListTasksResult),
484 GetTaskInfo(TaskInfo),
485 GetTaskResult(GetTaskResultResult),
486 CancelTask(CancelTaskResult),
487 SetLoggingLevel(EmptyResult),
488 Complete(CompleteResult),
489 Pong(EmptyResult),
490 Empty(EmptyResult),
491}
492
493#[derive(Debug, Clone, Serialize, Deserialize)]
498#[serde(rename_all = "camelCase")]
499pub struct InitializeParams {
500 pub protocol_version: String,
501 pub capabilities: ClientCapabilities,
502 pub client_info: Implementation,
503}
504
505#[derive(Debug, Clone, Default, Deserialize, Serialize)]
506pub struct ClientCapabilities {
507 #[serde(default, skip_serializing_if = "Option::is_none")]
508 pub roots: Option<RootsCapability>,
509 #[serde(default, skip_serializing_if = "Option::is_none")]
510 pub sampling: Option<SamplingCapability>,
511 #[serde(default, skip_serializing_if = "Option::is_none")]
512 pub elicitation: Option<ElicitationCapability>,
513}
514
515#[derive(Debug, Clone, Default, Deserialize, Serialize)]
517pub struct ElicitationCapability {
518 #[serde(default, skip_serializing_if = "Option::is_none")]
520 pub form: Option<ElicitationFormCapability>,
521 #[serde(default, skip_serializing_if = "Option::is_none")]
523 pub url: Option<ElicitationUrlCapability>,
524}
525
526#[derive(Debug, Clone, Default, Deserialize, Serialize)]
528pub struct ElicitationFormCapability {}
529
530#[derive(Debug, Clone, Default, Deserialize, Serialize)]
532pub struct ElicitationUrlCapability {}
533
534#[derive(Debug, Clone, Default, Deserialize, Serialize)]
536#[serde(rename_all = "camelCase")]
537pub struct RootsCapability {
538 #[serde(default)]
540 pub list_changed: bool,
541}
542
543#[derive(Debug, Clone, Deserialize, Serialize)]
550pub struct Root {
551 pub uri: String,
553 #[serde(default, skip_serializing_if = "Option::is_none")]
555 pub name: Option<String>,
556}
557
558impl Root {
559 pub fn new(uri: impl Into<String>) -> Self {
561 Self {
562 uri: uri.into(),
563 name: None,
564 }
565 }
566
567 pub fn with_name(uri: impl Into<String>, name: impl Into<String>) -> Self {
569 Self {
570 uri: uri.into(),
571 name: Some(name.into()),
572 }
573 }
574}
575
576#[derive(Debug, Clone, Default, Deserialize, Serialize)]
578pub struct ListRootsParams {
579 #[serde(default, rename = "_meta", skip_serializing_if = "Option::is_none")]
581 pub meta: Option<RequestMeta>,
582}
583
584#[derive(Debug, Clone, Deserialize, Serialize)]
586pub struct ListRootsResult {
587 pub roots: Vec<Root>,
589}
590
591#[derive(Debug, Clone, Default, Deserialize, Serialize)]
592pub struct SamplingCapability {}
593
594#[derive(Debug, Clone, Default, Deserialize, Serialize)]
596pub struct CompletionsCapability {}
597
598#[derive(Debug, Clone, Serialize, Deserialize)]
604pub struct PromptReference {
605 #[serde(rename = "type")]
607 pub ref_type: String,
608 pub name: String,
610}
611
612impl PromptReference {
613 pub fn new(name: impl Into<String>) -> Self {
615 Self {
616 ref_type: "ref/prompt".to_string(),
617 name: name.into(),
618 }
619 }
620}
621
622#[derive(Debug, Clone, Serialize, Deserialize)]
624pub struct ResourceReference {
625 #[serde(rename = "type")]
627 pub ref_type: String,
628 pub uri: String,
630}
631
632impl ResourceReference {
633 pub fn new(uri: impl Into<String>) -> Self {
635 Self {
636 ref_type: "ref/resource".to_string(),
637 uri: uri.into(),
638 }
639 }
640}
641
642#[derive(Debug, Clone, Serialize, Deserialize)]
644#[serde(tag = "type")]
645pub enum CompletionReference {
646 #[serde(rename = "ref/prompt")]
648 Prompt {
649 name: String,
651 },
652 #[serde(rename = "ref/resource")]
654 Resource {
655 uri: String,
657 },
658}
659
660impl CompletionReference {
661 pub fn prompt(name: impl Into<String>) -> Self {
663 Self::Prompt { name: name.into() }
664 }
665
666 pub fn resource(uri: impl Into<String>) -> Self {
668 Self::Resource { uri: uri.into() }
669 }
670}
671
672#[derive(Debug, Clone, Serialize, Deserialize)]
674pub struct CompletionArgument {
675 pub name: String,
677 pub value: String,
679}
680
681impl CompletionArgument {
682 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
684 Self {
685 name: name.into(),
686 value: value.into(),
687 }
688 }
689}
690
691#[derive(Debug, Clone, Serialize, Deserialize)]
693#[serde(rename_all = "camelCase")]
694pub struct CompleteParams {
695 #[serde(rename = "ref")]
697 pub reference: CompletionReference,
698 pub argument: CompletionArgument,
700}
701
702#[derive(Debug, Clone, Serialize, Deserialize)]
704#[serde(rename_all = "camelCase")]
705pub struct Completion {
706 pub values: Vec<String>,
708 #[serde(default, skip_serializing_if = "Option::is_none")]
710 pub total: Option<u32>,
711 #[serde(default, skip_serializing_if = "Option::is_none")]
713 pub has_more: Option<bool>,
714}
715
716impl Completion {
717 pub fn new(values: Vec<String>) -> Self {
719 Self {
720 values,
721 total: None,
722 has_more: None,
723 }
724 }
725
726 pub fn with_pagination(values: Vec<String>, total: u32, has_more: bool) -> Self {
728 Self {
729 values,
730 total: Some(total),
731 has_more: Some(has_more),
732 }
733 }
734}
735
736#[derive(Debug, Clone, Serialize, Deserialize)]
738pub struct CompleteResult {
739 pub completion: Completion,
741}
742
743impl CompleteResult {
744 pub fn new(values: Vec<String>) -> Self {
746 Self {
747 completion: Completion::new(values),
748 }
749 }
750
751 pub fn with_pagination(values: Vec<String>, total: u32, has_more: bool) -> Self {
753 Self {
754 completion: Completion::with_pagination(values, total, has_more),
755 }
756 }
757}
758
759#[derive(Debug, Clone, Serialize, Deserialize)]
765pub struct ModelHint {
766 pub name: String,
768}
769
770impl ModelHint {
771 pub fn new(name: impl Into<String>) -> Self {
773 Self { name: name.into() }
774 }
775}
776
777#[derive(Debug, Clone, Default, Serialize, Deserialize)]
779#[serde(rename_all = "camelCase")]
780pub struct ModelPreferences {
781 #[serde(default, skip_serializing_if = "Option::is_none")]
783 pub speed_priority: Option<f64>,
784 #[serde(default, skip_serializing_if = "Option::is_none")]
786 pub intelligence_priority: Option<f64>,
787 #[serde(default, skip_serializing_if = "Option::is_none")]
789 pub cost_priority: Option<f64>,
790 #[serde(default, skip_serializing_if = "Vec::is_empty")]
792 pub hints: Vec<ModelHint>,
793}
794
795impl ModelPreferences {
796 pub fn new() -> Self {
798 Self::default()
799 }
800
801 pub fn speed(mut self, priority: f64) -> Self {
803 self.speed_priority = Some(priority.clamp(0.0, 1.0));
804 self
805 }
806
807 pub fn intelligence(mut self, priority: f64) -> Self {
809 self.intelligence_priority = Some(priority.clamp(0.0, 1.0));
810 self
811 }
812
813 pub fn cost(mut self, priority: f64) -> Self {
815 self.cost_priority = Some(priority.clamp(0.0, 1.0));
816 self
817 }
818
819 pub fn hint(mut self, name: impl Into<String>) -> Self {
821 self.hints.push(ModelHint::new(name));
822 self
823 }
824}
825
826#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
828#[serde(rename_all = "camelCase")]
829pub enum IncludeContext {
830 AllServers,
832 ThisServer,
834 #[default]
836 None,
837}
838
839#[derive(Debug, Clone, Serialize, Deserialize)]
841pub struct SamplingMessage {
842 pub role: ContentRole,
844 pub content: SamplingContent,
846}
847
848impl SamplingMessage {
849 pub fn user(text: impl Into<String>) -> Self {
851 Self {
852 role: ContentRole::User,
853 content: SamplingContent::Text { text: text.into() },
854 }
855 }
856
857 pub fn assistant(text: impl Into<String>) -> Self {
859 Self {
860 role: ContentRole::Assistant,
861 content: SamplingContent::Text { text: text.into() },
862 }
863 }
864}
865
866#[derive(Debug, Clone, Serialize, Deserialize)]
868#[serde(tag = "type", rename_all = "lowercase")]
869pub enum SamplingContent {
870 Text {
872 text: String,
874 },
875 Image {
877 data: String,
879 #[serde(rename = "mimeType")]
881 mime_type: String,
882 },
883 Audio {
885 data: String,
887 #[serde(rename = "mimeType")]
889 mime_type: String,
890 },
891}
892
893#[derive(Debug, Clone, Serialize, Deserialize)]
895#[serde(rename_all = "camelCase")]
896pub struct CreateMessageParams {
897 pub messages: Vec<SamplingMessage>,
899 pub max_tokens: u32,
901 #[serde(default, skip_serializing_if = "Option::is_none")]
903 pub system_prompt: Option<String>,
904 #[serde(default, skip_serializing_if = "Option::is_none")]
906 pub temperature: Option<f64>,
907 #[serde(default, skip_serializing_if = "Vec::is_empty")]
909 pub stop_sequences: Vec<String>,
910 #[serde(default, skip_serializing_if = "Option::is_none")]
912 pub model_preferences: Option<ModelPreferences>,
913 #[serde(default, skip_serializing_if = "Option::is_none")]
915 pub include_context: Option<IncludeContext>,
916 #[serde(default, skip_serializing_if = "Option::is_none")]
918 pub metadata: Option<serde_json::Map<String, Value>>,
919}
920
921impl CreateMessageParams {
922 pub fn new(messages: Vec<SamplingMessage>, max_tokens: u32) -> Self {
924 Self {
925 messages,
926 max_tokens,
927 system_prompt: None,
928 temperature: None,
929 stop_sequences: Vec::new(),
930 model_preferences: None,
931 include_context: None,
932 metadata: None,
933 }
934 }
935
936 pub fn system_prompt(mut self, prompt: impl Into<String>) -> Self {
938 self.system_prompt = Some(prompt.into());
939 self
940 }
941
942 pub fn temperature(mut self, temp: f64) -> Self {
944 self.temperature = Some(temp.clamp(0.0, 1.0));
945 self
946 }
947
948 pub fn stop_sequence(mut self, seq: impl Into<String>) -> Self {
950 self.stop_sequences.push(seq.into());
951 self
952 }
953
954 pub fn model_preferences(mut self, prefs: ModelPreferences) -> Self {
956 self.model_preferences = Some(prefs);
957 self
958 }
959
960 pub fn include_context(mut self, mode: IncludeContext) -> Self {
962 self.include_context = Some(mode);
963 self
964 }
965}
966
967#[derive(Debug, Clone, Serialize, Deserialize)]
969#[serde(rename_all = "camelCase")]
970pub struct CreateMessageResult {
971 pub content: SamplingContent,
973 pub model: String,
975 pub role: ContentRole,
977 #[serde(default, skip_serializing_if = "Option::is_none")]
979 pub stop_reason: Option<String>,
980}
981
982#[derive(Debug, Clone, Deserialize, Serialize)]
983pub struct Implementation {
984 pub name: String,
985 pub version: String,
986}
987
988#[derive(Debug, Clone, Serialize, Deserialize)]
989#[serde(rename_all = "camelCase")]
990pub struct InitializeResult {
991 pub protocol_version: String,
992 pub capabilities: ServerCapabilities,
993 pub server_info: Implementation,
994 #[serde(skip_serializing_if = "Option::is_none")]
997 pub instructions: Option<String>,
998}
999
1000#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1001#[serde(rename_all = "camelCase")]
1002pub struct ServerCapabilities {
1003 #[serde(default, skip_serializing_if = "Option::is_none")]
1004 pub tools: Option<ToolsCapability>,
1005 #[serde(default, skip_serializing_if = "Option::is_none")]
1006 pub resources: Option<ResourcesCapability>,
1007 #[serde(default, skip_serializing_if = "Option::is_none")]
1008 pub prompts: Option<PromptsCapability>,
1009 #[serde(default, skip_serializing_if = "Option::is_none")]
1011 pub logging: Option<LoggingCapability>,
1012 #[serde(default, skip_serializing_if = "Option::is_none")]
1013 pub tasks: Option<TasksCapability>,
1014 #[serde(default, skip_serializing_if = "Option::is_none")]
1016 pub completions: Option<CompletionsCapability>,
1017}
1018
1019#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1021pub struct LoggingCapability {}
1022
1023#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1025#[serde(rename_all = "camelCase")]
1026pub struct TasksCapability {
1027 #[serde(default, skip_serializing_if = "Option::is_none")]
1029 pub default_poll_interval: Option<u64>,
1030}
1031
1032#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1033#[serde(rename_all = "camelCase")]
1034pub struct ToolsCapability {
1035 #[serde(default)]
1036 pub list_changed: bool,
1037}
1038
1039#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1040#[serde(rename_all = "camelCase")]
1041pub struct ResourcesCapability {
1042 #[serde(default)]
1043 pub subscribe: bool,
1044 #[serde(default)]
1045 pub list_changed: bool,
1046}
1047
1048#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1049#[serde(rename_all = "camelCase")]
1050pub struct PromptsCapability {
1051 #[serde(default)]
1052 pub list_changed: bool,
1053}
1054
1055#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1060pub struct ListToolsParams {
1061 #[serde(default)]
1062 pub cursor: Option<String>,
1063}
1064
1065#[derive(Debug, Clone, Serialize, Deserialize)]
1066#[serde(rename_all = "camelCase")]
1067pub struct ListToolsResult {
1068 pub tools: Vec<ToolDefinition>,
1069 #[serde(default, skip_serializing_if = "Option::is_none")]
1070 pub next_cursor: Option<String>,
1071}
1072
1073#[derive(Debug, Clone, Serialize, Deserialize)]
1075#[serde(rename_all = "camelCase")]
1076pub struct ToolDefinition {
1077 pub name: String,
1078 #[serde(skip_serializing_if = "Option::is_none")]
1080 pub title: Option<String>,
1081 #[serde(skip_serializing_if = "Option::is_none")]
1082 pub description: Option<String>,
1083 pub input_schema: Value,
1084 #[serde(skip_serializing_if = "Option::is_none")]
1086 pub output_schema: Option<Value>,
1087 #[serde(skip_serializing_if = "Option::is_none")]
1089 pub icons: Option<Vec<ToolIcon>>,
1090 #[serde(skip_serializing_if = "Option::is_none")]
1093 pub annotations: Option<ToolAnnotations>,
1094}
1095
1096#[derive(Debug, Clone, Serialize, Deserialize)]
1098#[serde(rename_all = "camelCase")]
1099pub struct ToolIcon {
1100 pub src: String,
1102 #[serde(skip_serializing_if = "Option::is_none")]
1104 pub mime_type: Option<String>,
1105 #[serde(skip_serializing_if = "Option::is_none")]
1107 pub sizes: Option<Vec<String>>,
1108}
1109
1110#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1113#[serde(rename_all = "camelCase")]
1114pub struct ToolAnnotations {
1115 #[serde(skip_serializing_if = "Option::is_none")]
1117 pub title: Option<String>,
1118 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1120 pub read_only_hint: bool,
1121 #[serde(default = "default_true", skip_serializing_if = "is_true")]
1124 pub destructive_hint: bool,
1125 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1128 pub idempotent_hint: bool,
1129 #[serde(default = "default_true", skip_serializing_if = "is_true")]
1131 pub open_world_hint: bool,
1132}
1133
1134fn default_true() -> bool {
1135 true
1136}
1137
1138fn is_true(v: &bool) -> bool {
1139 *v
1140}
1141
1142#[derive(Debug, Clone, Serialize, Deserialize)]
1143pub struct CallToolParams {
1144 pub name: String,
1145 #[serde(default)]
1146 pub arguments: Value,
1147 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1149 pub meta: Option<RequestMeta>,
1150}
1151
1152#[derive(Debug, Clone, Serialize, Deserialize)]
1173#[serde(rename_all = "camelCase")]
1174pub struct CallToolResult {
1175 pub content: Vec<Content>,
1177 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1179 pub is_error: bool,
1180 #[serde(default, skip_serializing_if = "Option::is_none")]
1182 pub structured_content: Option<Value>,
1183}
1184
1185impl CallToolResult {
1186 pub fn text(text: impl Into<String>) -> Self {
1190 Self {
1191 content: vec![Content::Text {
1192 text: text.into(),
1193 annotations: None,
1194 }],
1195 is_error: false,
1196 structured_content: None,
1197 }
1198 }
1199
1200 pub fn error(message: impl Into<String>) -> Self {
1205 Self {
1206 content: vec![Content::Text {
1207 text: message.into(),
1208 annotations: None,
1209 }],
1210 is_error: true,
1211 structured_content: None,
1212 }
1213 }
1214
1215 pub fn json(value: Value) -> Self {
1220 let text = serde_json::to_string_pretty(&value).unwrap_or_default();
1221 Self {
1222 content: vec![Content::Text {
1223 text,
1224 annotations: None,
1225 }],
1226 is_error: false,
1227 structured_content: Some(value),
1228 }
1229 }
1230
1231 pub fn image(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1233 Self {
1234 content: vec![Content::Image {
1235 data: data.into(),
1236 mime_type: mime_type.into(),
1237 annotations: None,
1238 }],
1239 is_error: false,
1240 structured_content: None,
1241 }
1242 }
1243
1244 pub fn audio(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1246 Self {
1247 content: vec![Content::Audio {
1248 data: data.into(),
1249 mime_type: mime_type.into(),
1250 annotations: None,
1251 }],
1252 is_error: false,
1253 structured_content: None,
1254 }
1255 }
1256
1257 pub fn resource_link(uri: impl Into<String>) -> Self {
1259 Self {
1260 content: vec![Content::ResourceLink {
1261 uri: uri.into(),
1262 name: None,
1263 description: None,
1264 mime_type: None,
1265 annotations: None,
1266 }],
1267 is_error: false,
1268 structured_content: None,
1269 }
1270 }
1271
1272 pub fn resource_link_with_meta(
1274 uri: impl Into<String>,
1275 name: Option<String>,
1276 description: Option<String>,
1277 mime_type: Option<String>,
1278 ) -> Self {
1279 Self {
1280 content: vec![Content::ResourceLink {
1281 uri: uri.into(),
1282 name,
1283 description,
1284 mime_type,
1285 annotations: None,
1286 }],
1287 is_error: false,
1288 structured_content: None,
1289 }
1290 }
1291
1292 pub fn resource(resource: ResourceContent) -> Self {
1294 Self {
1295 content: vec![Content::Resource {
1296 resource,
1297 annotations: None,
1298 }],
1299 is_error: false,
1300 structured_content: None,
1301 }
1302 }
1303}
1304
1305#[derive(Debug, Clone, Serialize, Deserialize)]
1310#[serde(tag = "type", rename_all = "snake_case")]
1311pub enum Content {
1312 Text {
1314 text: String,
1316 #[serde(skip_serializing_if = "Option::is_none")]
1318 annotations: Option<ContentAnnotations>,
1319 },
1320 Image {
1322 data: String,
1324 #[serde(rename = "mimeType")]
1326 mime_type: String,
1327 #[serde(skip_serializing_if = "Option::is_none")]
1329 annotations: Option<ContentAnnotations>,
1330 },
1331 Audio {
1333 data: String,
1335 #[serde(rename = "mimeType")]
1337 mime_type: String,
1338 #[serde(skip_serializing_if = "Option::is_none")]
1340 annotations: Option<ContentAnnotations>,
1341 },
1342 Resource {
1344 resource: ResourceContent,
1346 #[serde(skip_serializing_if = "Option::is_none")]
1348 annotations: Option<ContentAnnotations>,
1349 },
1350 ResourceLink {
1352 uri: String,
1354 #[serde(skip_serializing_if = "Option::is_none")]
1356 name: Option<String>,
1357 #[serde(skip_serializing_if = "Option::is_none")]
1359 description: Option<String>,
1360 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
1362 mime_type: Option<String>,
1363 #[serde(skip_serializing_if = "Option::is_none")]
1364 annotations: Option<ContentAnnotations>,
1365 },
1366}
1367
1368#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1370pub struct ContentAnnotations {
1371 #[serde(skip_serializing_if = "Option::is_none")]
1373 pub audience: Option<Vec<ContentRole>>,
1374 #[serde(skip_serializing_if = "Option::is_none")]
1376 pub priority: Option<f64>,
1377}
1378
1379#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1383#[serde(rename_all = "lowercase")]
1384pub enum ContentRole {
1385 User,
1387 Assistant,
1389}
1390
1391#[derive(Debug, Clone, Serialize, Deserialize)]
1395#[serde(rename_all = "camelCase")]
1396pub struct ResourceContent {
1397 pub uri: String,
1399 #[serde(skip_serializing_if = "Option::is_none")]
1401 pub mime_type: Option<String>,
1402 #[serde(skip_serializing_if = "Option::is_none")]
1404 pub text: Option<String>,
1405 #[serde(skip_serializing_if = "Option::is_none")]
1407 pub blob: Option<String>,
1408}
1409
1410#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1415pub struct ListResourcesParams {
1416 #[serde(default)]
1417 pub cursor: Option<String>,
1418}
1419
1420#[derive(Debug, Clone, Serialize, Deserialize)]
1421#[serde(rename_all = "camelCase")]
1422pub struct ListResourcesResult {
1423 pub resources: Vec<ResourceDefinition>,
1424 #[serde(default, skip_serializing_if = "Option::is_none")]
1425 pub next_cursor: Option<String>,
1426}
1427
1428#[derive(Debug, Clone, Serialize, Deserialize)]
1429#[serde(rename_all = "camelCase")]
1430pub struct ResourceDefinition {
1431 pub uri: String,
1432 pub name: String,
1433 #[serde(skip_serializing_if = "Option::is_none")]
1434 pub description: Option<String>,
1435 #[serde(skip_serializing_if = "Option::is_none")]
1436 pub mime_type: Option<String>,
1437}
1438
1439#[derive(Debug, Clone, Serialize, Deserialize)]
1440pub struct ReadResourceParams {
1441 pub uri: String,
1442}
1443
1444#[derive(Debug, Clone, Serialize, Deserialize)]
1445pub struct ReadResourceResult {
1446 pub contents: Vec<ResourceContent>,
1447}
1448
1449impl ReadResourceResult {
1450 pub fn text(uri: impl Into<String>, content: impl Into<String>) -> Self {
1460 Self {
1461 contents: vec![ResourceContent {
1462 uri: uri.into(),
1463 mime_type: Some("text/plain".to_string()),
1464 text: Some(content.into()),
1465 blob: None,
1466 }],
1467 }
1468 }
1469
1470 pub fn text_with_mime(
1484 uri: impl Into<String>,
1485 content: impl Into<String>,
1486 mime_type: impl Into<String>,
1487 ) -> Self {
1488 Self {
1489 contents: vec![ResourceContent {
1490 uri: uri.into(),
1491 mime_type: Some(mime_type.into()),
1492 text: Some(content.into()),
1493 blob: None,
1494 }],
1495 }
1496 }
1497
1498 pub fn json<T: serde::Serialize>(uri: impl Into<String>, value: &T) -> Self {
1512 let json_string =
1513 serde_json::to_string_pretty(value).unwrap_or_else(|_| "null".to_string());
1514 Self {
1515 contents: vec![ResourceContent {
1516 uri: uri.into(),
1517 mime_type: Some("application/json".to_string()),
1518 text: Some(json_string),
1519 blob: None,
1520 }],
1521 }
1522 }
1523
1524 pub fn blob(uri: impl Into<String>, bytes: &[u8]) -> Self {
1535 use base64::Engine;
1536 let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
1537 Self {
1538 contents: vec![ResourceContent {
1539 uri: uri.into(),
1540 mime_type: Some("application/octet-stream".to_string()),
1541 text: None,
1542 blob: Some(encoded),
1543 }],
1544 }
1545 }
1546
1547 pub fn blob_with_mime(
1558 uri: impl Into<String>,
1559 bytes: &[u8],
1560 mime_type: impl Into<String>,
1561 ) -> Self {
1562 use base64::Engine;
1563 let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
1564 Self {
1565 contents: vec![ResourceContent {
1566 uri: uri.into(),
1567 mime_type: Some(mime_type.into()),
1568 text: None,
1569 blob: Some(encoded),
1570 }],
1571 }
1572 }
1573}
1574
1575#[derive(Debug, Clone, Deserialize)]
1576pub struct SubscribeResourceParams {
1577 pub uri: String,
1578}
1579
1580#[derive(Debug, Clone, Deserialize)]
1581pub struct UnsubscribeResourceParams {
1582 pub uri: String,
1583}
1584
1585#[derive(Debug, Clone, Default, Deserialize)]
1587pub struct ListResourceTemplatesParams {
1588 #[serde(default)]
1590 pub cursor: Option<String>,
1591}
1592
1593#[derive(Debug, Clone, Serialize)]
1595#[serde(rename_all = "camelCase")]
1596pub struct ListResourceTemplatesResult {
1597 pub resource_templates: Vec<ResourceTemplateDefinition>,
1599 #[serde(skip_serializing_if = "Option::is_none")]
1601 pub next_cursor: Option<String>,
1602}
1603
1604#[derive(Debug, Clone, Serialize, Deserialize)]
1620#[serde(rename_all = "camelCase")]
1621pub struct ResourceTemplateDefinition {
1622 pub uri_template: String,
1624 pub name: String,
1626 #[serde(skip_serializing_if = "Option::is_none")]
1628 pub description: Option<String>,
1629 #[serde(skip_serializing_if = "Option::is_none")]
1631 pub mime_type: Option<String>,
1632}
1633
1634#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1639pub struct ListPromptsParams {
1640 #[serde(default)]
1641 pub cursor: Option<String>,
1642}
1643
1644#[derive(Debug, Clone, Serialize, Deserialize)]
1645#[serde(rename_all = "camelCase")]
1646pub struct ListPromptsResult {
1647 pub prompts: Vec<PromptDefinition>,
1648 #[serde(default, skip_serializing_if = "Option::is_none")]
1649 pub next_cursor: Option<String>,
1650}
1651
1652#[derive(Debug, Clone, Serialize, Deserialize)]
1653pub struct PromptDefinition {
1654 pub name: String,
1655 #[serde(skip_serializing_if = "Option::is_none")]
1656 pub description: Option<String>,
1657 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1658 pub arguments: Vec<PromptArgument>,
1659}
1660
1661#[derive(Debug, Clone, Serialize, Deserialize)]
1662pub struct PromptArgument {
1663 pub name: String,
1664 #[serde(skip_serializing_if = "Option::is_none")]
1665 pub description: Option<String>,
1666 #[serde(default)]
1667 pub required: bool,
1668}
1669
1670#[derive(Debug, Clone, Serialize, Deserialize)]
1671pub struct GetPromptParams {
1672 pub name: String,
1673 #[serde(default)]
1674 pub arguments: std::collections::HashMap<String, String>,
1675}
1676
1677#[derive(Debug, Clone, Serialize, Deserialize)]
1678pub struct GetPromptResult {
1679 #[serde(default, skip_serializing_if = "Option::is_none")]
1680 pub description: Option<String>,
1681 pub messages: Vec<PromptMessage>,
1682}
1683
1684impl GetPromptResult {
1685 pub fn user_message(text: impl Into<String>) -> Self {
1695 Self {
1696 description: None,
1697 messages: vec![PromptMessage {
1698 role: PromptRole::User,
1699 content: Content::Text {
1700 text: text.into(),
1701 annotations: None,
1702 },
1703 }],
1704 }
1705 }
1706
1707 pub fn user_message_with_description(
1720 text: impl Into<String>,
1721 description: impl Into<String>,
1722 ) -> Self {
1723 Self {
1724 description: Some(description.into()),
1725 messages: vec![PromptMessage {
1726 role: PromptRole::User,
1727 content: Content::Text {
1728 text: text.into(),
1729 annotations: None,
1730 },
1731 }],
1732 }
1733 }
1734
1735 pub fn assistant_message(text: impl Into<String>) -> Self {
1745 Self {
1746 description: None,
1747 messages: vec![PromptMessage {
1748 role: PromptRole::Assistant,
1749 content: Content::Text {
1750 text: text.into(),
1751 annotations: None,
1752 },
1753 }],
1754 }
1755 }
1756
1757 pub fn builder() -> GetPromptResultBuilder {
1772 GetPromptResultBuilder::new()
1773 }
1774}
1775
1776#[derive(Debug, Clone, Default)]
1778pub struct GetPromptResultBuilder {
1779 description: Option<String>,
1780 messages: Vec<PromptMessage>,
1781}
1782
1783impl GetPromptResultBuilder {
1784 pub fn new() -> Self {
1786 Self::default()
1787 }
1788
1789 pub fn description(mut self, description: impl Into<String>) -> Self {
1791 self.description = Some(description.into());
1792 self
1793 }
1794
1795 pub fn user(mut self, text: impl Into<String>) -> Self {
1797 self.messages.push(PromptMessage {
1798 role: PromptRole::User,
1799 content: Content::Text {
1800 text: text.into(),
1801 annotations: None,
1802 },
1803 });
1804 self
1805 }
1806
1807 pub fn assistant(mut self, text: impl Into<String>) -> Self {
1809 self.messages.push(PromptMessage {
1810 role: PromptRole::Assistant,
1811 content: Content::Text {
1812 text: text.into(),
1813 annotations: None,
1814 },
1815 });
1816 self
1817 }
1818
1819 pub fn build(self) -> GetPromptResult {
1821 GetPromptResult {
1822 description: self.description,
1823 messages: self.messages,
1824 }
1825 }
1826}
1827
1828#[derive(Debug, Clone, Serialize, Deserialize)]
1829pub struct PromptMessage {
1830 pub role: PromptRole,
1831 pub content: Content,
1832}
1833
1834#[derive(Debug, Clone, Serialize, Deserialize)]
1835#[serde(rename_all = "lowercase")]
1836pub enum PromptRole {
1837 User,
1838 Assistant,
1839}
1840
1841#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1847#[serde(rename_all = "snake_case")]
1848pub enum TaskStatus {
1849 Working,
1851 InputRequired,
1853 Completed,
1855 Failed,
1857 Cancelled,
1859}
1860
1861impl std::fmt::Display for TaskStatus {
1862 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1863 match self {
1864 TaskStatus::Working => write!(f, "working"),
1865 TaskStatus::InputRequired => write!(f, "input_required"),
1866 TaskStatus::Completed => write!(f, "completed"),
1867 TaskStatus::Failed => write!(f, "failed"),
1868 TaskStatus::Cancelled => write!(f, "cancelled"),
1869 }
1870 }
1871}
1872
1873impl TaskStatus {
1874 pub fn is_terminal(&self) -> bool {
1876 matches!(
1877 self,
1878 TaskStatus::Completed | TaskStatus::Failed | TaskStatus::Cancelled
1879 )
1880 }
1881}
1882
1883#[derive(Debug, Clone, Serialize, Deserialize)]
1885#[serde(rename_all = "camelCase")]
1886pub struct TaskInfo {
1887 pub task_id: String,
1889 pub status: TaskStatus,
1891 pub created_at: String,
1893 #[serde(skip_serializing_if = "Option::is_none")]
1895 pub ttl: Option<u64>,
1896 #[serde(skip_serializing_if = "Option::is_none")]
1898 pub poll_interval: Option<u64>,
1899 #[serde(skip_serializing_if = "Option::is_none")]
1901 pub progress: Option<f64>,
1902 #[serde(skip_serializing_if = "Option::is_none")]
1904 pub message: Option<String>,
1905}
1906
1907#[derive(Debug, Clone, Deserialize)]
1909#[serde(rename_all = "camelCase")]
1910pub struct EnqueueTaskParams {
1911 pub tool_name: String,
1913 #[serde(default)]
1915 pub arguments: Value,
1916 #[serde(default)]
1918 pub ttl: Option<u64>,
1919}
1920
1921#[derive(Debug, Clone, Serialize)]
1923#[serde(rename_all = "camelCase")]
1924pub struct EnqueueTaskResult {
1925 pub task_id: String,
1927 pub status: TaskStatus,
1929 #[serde(skip_serializing_if = "Option::is_none")]
1931 pub poll_interval: Option<u64>,
1932}
1933
1934#[derive(Debug, Clone, Default, Deserialize)]
1936#[serde(rename_all = "camelCase")]
1937pub struct ListTasksParams {
1938 #[serde(default)]
1940 pub status: Option<TaskStatus>,
1941 #[serde(default)]
1943 pub cursor: Option<String>,
1944}
1945
1946#[derive(Debug, Clone, Serialize)]
1948#[serde(rename_all = "camelCase")]
1949pub struct ListTasksResult {
1950 pub tasks: Vec<TaskInfo>,
1952 #[serde(skip_serializing_if = "Option::is_none")]
1954 pub next_cursor: Option<String>,
1955}
1956
1957#[derive(Debug, Clone, Deserialize)]
1959#[serde(rename_all = "camelCase")]
1960pub struct GetTaskInfoParams {
1961 pub task_id: String,
1963}
1964
1965pub type GetTaskInfoResult = TaskInfo;
1967
1968#[derive(Debug, Clone, Deserialize)]
1970#[serde(rename_all = "camelCase")]
1971pub struct GetTaskResultParams {
1972 pub task_id: String,
1974}
1975
1976#[derive(Debug, Clone, Serialize)]
1978#[serde(rename_all = "camelCase")]
1979pub struct GetTaskResultResult {
1980 pub task_id: String,
1982 pub status: TaskStatus,
1984 #[serde(skip_serializing_if = "Option::is_none")]
1986 pub result: Option<CallToolResult>,
1987 #[serde(skip_serializing_if = "Option::is_none")]
1989 pub error: Option<String>,
1990}
1991
1992#[derive(Debug, Clone, Deserialize)]
1994#[serde(rename_all = "camelCase")]
1995pub struct CancelTaskParams {
1996 pub task_id: String,
1998 #[serde(default)]
2000 pub reason: Option<String>,
2001}
2002
2003#[derive(Debug, Clone, Serialize)]
2005#[serde(rename_all = "camelCase")]
2006pub struct CancelTaskResult {
2007 pub cancelled: bool,
2009 pub status: TaskStatus,
2011}
2012
2013#[derive(Debug, Clone, Serialize, Deserialize)]
2015#[serde(rename_all = "camelCase")]
2016pub struct TaskStatusChangedParams {
2017 pub task_id: String,
2019 pub status: TaskStatus,
2021 #[serde(skip_serializing_if = "Option::is_none")]
2023 pub message: Option<String>,
2024}
2025
2026#[derive(Debug, Clone, Serialize, Deserialize)]
2032#[serde(rename_all = "camelCase")]
2033pub struct ElicitFormParams {
2034 pub mode: ElicitMode,
2036 pub message: String,
2038 pub requested_schema: ElicitFormSchema,
2040 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2042 pub meta: Option<RequestMeta>,
2043}
2044
2045#[derive(Debug, Clone, Serialize, Deserialize)]
2047#[serde(rename_all = "camelCase")]
2048pub struct ElicitUrlParams {
2049 pub mode: ElicitMode,
2051 pub elicitation_id: String,
2053 pub message: String,
2055 pub url: String,
2057 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2059 pub meta: Option<RequestMeta>,
2060}
2061
2062#[derive(Debug, Clone, Serialize, Deserialize)]
2064#[serde(untagged)]
2065pub enum ElicitRequestParams {
2066 Form(ElicitFormParams),
2067 Url(ElicitUrlParams),
2068}
2069
2070#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2072#[serde(rename_all = "lowercase")]
2073pub enum ElicitMode {
2074 Form,
2076 Url,
2078}
2079
2080#[derive(Debug, Clone, Serialize, Deserialize)]
2084pub struct ElicitFormSchema {
2085 #[serde(rename = "type")]
2087 pub schema_type: String,
2088 pub properties: std::collections::HashMap<String, PrimitiveSchemaDefinition>,
2090 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2092 pub required: Vec<String>,
2093}
2094
2095impl ElicitFormSchema {
2096 pub fn new() -> Self {
2098 Self {
2099 schema_type: "object".to_string(),
2100 properties: std::collections::HashMap::new(),
2101 required: Vec::new(),
2102 }
2103 }
2104
2105 pub fn string_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2107 self.properties.insert(
2108 name.to_string(),
2109 PrimitiveSchemaDefinition::String(StringSchema {
2110 schema_type: "string".to_string(),
2111 description: description.map(|s| s.to_string()),
2112 format: None,
2113 min_length: None,
2114 max_length: None,
2115 }),
2116 );
2117 if required {
2118 self.required.push(name.to_string());
2119 }
2120 self
2121 }
2122
2123 pub fn number_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2125 self.properties.insert(
2126 name.to_string(),
2127 PrimitiveSchemaDefinition::Number(NumberSchema {
2128 schema_type: "number".to_string(),
2129 description: description.map(|s| s.to_string()),
2130 minimum: None,
2131 maximum: None,
2132 }),
2133 );
2134 if required {
2135 self.required.push(name.to_string());
2136 }
2137 self
2138 }
2139
2140 pub fn boolean_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2142 self.properties.insert(
2143 name.to_string(),
2144 PrimitiveSchemaDefinition::Boolean(BooleanSchema {
2145 schema_type: "boolean".to_string(),
2146 description: description.map(|s| s.to_string()),
2147 }),
2148 );
2149 if required {
2150 self.required.push(name.to_string());
2151 }
2152 self
2153 }
2154
2155 pub fn enum_field(
2157 mut self,
2158 name: &str,
2159 description: Option<&str>,
2160 options: Vec<String>,
2161 required: bool,
2162 ) -> Self {
2163 self.properties.insert(
2164 name.to_string(),
2165 PrimitiveSchemaDefinition::SingleSelectEnum(SingleSelectEnumSchema {
2166 schema_type: "string".to_string(),
2167 description: description.map(|s| s.to_string()),
2168 enum_values: options,
2169 }),
2170 );
2171 if required {
2172 self.required.push(name.to_string());
2173 }
2174 self
2175 }
2176}
2177
2178impl Default for ElicitFormSchema {
2179 fn default() -> Self {
2180 Self::new()
2181 }
2182}
2183
2184#[derive(Debug, Clone, Serialize, Deserialize)]
2186#[serde(untagged)]
2187pub enum PrimitiveSchemaDefinition {
2188 String(StringSchema),
2189 Number(NumberSchema),
2190 Boolean(BooleanSchema),
2191 SingleSelectEnum(SingleSelectEnumSchema),
2192 MultiSelectEnum(MultiSelectEnumSchema),
2193}
2194
2195#[derive(Debug, Clone, Serialize, Deserialize)]
2197#[serde(rename_all = "camelCase")]
2198pub struct StringSchema {
2199 #[serde(rename = "type")]
2200 pub schema_type: String,
2201 #[serde(skip_serializing_if = "Option::is_none")]
2202 pub description: Option<String>,
2203 #[serde(skip_serializing_if = "Option::is_none")]
2204 pub format: Option<String>,
2205 #[serde(skip_serializing_if = "Option::is_none")]
2206 pub min_length: Option<u64>,
2207 #[serde(skip_serializing_if = "Option::is_none")]
2208 pub max_length: Option<u64>,
2209}
2210
2211#[derive(Debug, Clone, Serialize, Deserialize)]
2213#[serde(rename_all = "camelCase")]
2214pub struct NumberSchema {
2215 #[serde(rename = "type")]
2216 pub schema_type: String,
2217 #[serde(skip_serializing_if = "Option::is_none")]
2218 pub description: Option<String>,
2219 #[serde(skip_serializing_if = "Option::is_none")]
2220 pub minimum: Option<f64>,
2221 #[serde(skip_serializing_if = "Option::is_none")]
2222 pub maximum: Option<f64>,
2223}
2224
2225#[derive(Debug, Clone, Serialize, Deserialize)]
2227#[serde(rename_all = "camelCase")]
2228pub struct BooleanSchema {
2229 #[serde(rename = "type")]
2230 pub schema_type: String,
2231 #[serde(skip_serializing_if = "Option::is_none")]
2232 pub description: Option<String>,
2233}
2234
2235#[derive(Debug, Clone, Serialize, Deserialize)]
2237#[serde(rename_all = "camelCase")]
2238pub struct SingleSelectEnumSchema {
2239 #[serde(rename = "type")]
2240 pub schema_type: String,
2241 #[serde(skip_serializing_if = "Option::is_none")]
2242 pub description: Option<String>,
2243 #[serde(rename = "enum")]
2244 pub enum_values: Vec<String>,
2245}
2246
2247#[derive(Debug, Clone, Serialize, Deserialize)]
2249#[serde(rename_all = "camelCase")]
2250pub struct MultiSelectEnumSchema {
2251 #[serde(rename = "type")]
2252 pub schema_type: String,
2253 #[serde(skip_serializing_if = "Option::is_none")]
2254 pub description: Option<String>,
2255 pub items: MultiSelectEnumItems,
2256 #[serde(skip_serializing_if = "Option::is_none")]
2257 pub unique_items: Option<bool>,
2258}
2259
2260#[derive(Debug, Clone, Serialize, Deserialize)]
2262pub struct MultiSelectEnumItems {
2263 #[serde(rename = "type")]
2264 pub schema_type: String,
2265 #[serde(rename = "enum")]
2266 pub enum_values: Vec<String>,
2267}
2268
2269#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2271#[serde(rename_all = "lowercase")]
2272pub enum ElicitAction {
2273 Accept,
2275 Decline,
2277 Cancel,
2279}
2280
2281#[derive(Debug, Clone, Serialize, Deserialize)]
2283pub struct ElicitResult {
2284 pub action: ElicitAction,
2286 #[serde(default, skip_serializing_if = "Option::is_none")]
2288 pub content: Option<std::collections::HashMap<String, ElicitFieldValue>>,
2289}
2290
2291impl ElicitResult {
2292 pub fn accept(content: std::collections::HashMap<String, ElicitFieldValue>) -> Self {
2294 Self {
2295 action: ElicitAction::Accept,
2296 content: Some(content),
2297 }
2298 }
2299
2300 pub fn decline() -> Self {
2302 Self {
2303 action: ElicitAction::Decline,
2304 content: None,
2305 }
2306 }
2307
2308 pub fn cancel() -> Self {
2310 Self {
2311 action: ElicitAction::Cancel,
2312 content: None,
2313 }
2314 }
2315}
2316
2317#[derive(Debug, Clone, Serialize, Deserialize)]
2319#[serde(untagged)]
2320pub enum ElicitFieldValue {
2321 String(String),
2322 Number(f64),
2323 Integer(i64),
2324 Boolean(bool),
2325 StringArray(Vec<String>),
2326}
2327
2328#[derive(Debug, Clone, Serialize, Deserialize)]
2330#[serde(rename_all = "camelCase")]
2331pub struct ElicitationCompleteParams {
2332 pub elicitation_id: String,
2334}
2335
2336#[derive(Debug, Clone, Default, Serialize)]
2341pub struct EmptyResult {}
2342
2343impl McpRequest {
2348 pub fn from_jsonrpc(req: &JsonRpcRequest) -> Result<Self, crate::error::Error> {
2350 let params = req
2351 .params
2352 .clone()
2353 .unwrap_or(Value::Object(Default::default()));
2354
2355 match req.method.as_str() {
2356 "initialize" => {
2357 let p: InitializeParams = serde_json::from_value(params)?;
2358 Ok(McpRequest::Initialize(p))
2359 }
2360 "tools/list" => {
2361 let p: ListToolsParams = serde_json::from_value(params).unwrap_or_default();
2362 Ok(McpRequest::ListTools(p))
2363 }
2364 "tools/call" => {
2365 let p: CallToolParams = serde_json::from_value(params)?;
2366 Ok(McpRequest::CallTool(p))
2367 }
2368 "resources/list" => {
2369 let p: ListResourcesParams = serde_json::from_value(params).unwrap_or_default();
2370 Ok(McpRequest::ListResources(p))
2371 }
2372 "resources/templates/list" => {
2373 let p: ListResourceTemplatesParams =
2374 serde_json::from_value(params).unwrap_or_default();
2375 Ok(McpRequest::ListResourceTemplates(p))
2376 }
2377 "resources/read" => {
2378 let p: ReadResourceParams = serde_json::from_value(params)?;
2379 Ok(McpRequest::ReadResource(p))
2380 }
2381 "resources/subscribe" => {
2382 let p: SubscribeResourceParams = serde_json::from_value(params)?;
2383 Ok(McpRequest::SubscribeResource(p))
2384 }
2385 "resources/unsubscribe" => {
2386 let p: UnsubscribeResourceParams = serde_json::from_value(params)?;
2387 Ok(McpRequest::UnsubscribeResource(p))
2388 }
2389 "prompts/list" => {
2390 let p: ListPromptsParams = serde_json::from_value(params).unwrap_or_default();
2391 Ok(McpRequest::ListPrompts(p))
2392 }
2393 "prompts/get" => {
2394 let p: GetPromptParams = serde_json::from_value(params)?;
2395 Ok(McpRequest::GetPrompt(p))
2396 }
2397 "tasks/enqueue" => {
2398 let p: EnqueueTaskParams = serde_json::from_value(params)?;
2399 Ok(McpRequest::EnqueueTask(p))
2400 }
2401 "tasks/list" => {
2402 let p: ListTasksParams = serde_json::from_value(params).unwrap_or_default();
2403 Ok(McpRequest::ListTasks(p))
2404 }
2405 "tasks/get" => {
2406 let p: GetTaskInfoParams = serde_json::from_value(params)?;
2407 Ok(McpRequest::GetTaskInfo(p))
2408 }
2409 "tasks/result" => {
2410 let p: GetTaskResultParams = serde_json::from_value(params)?;
2411 Ok(McpRequest::GetTaskResult(p))
2412 }
2413 "tasks/cancel" => {
2414 let p: CancelTaskParams = serde_json::from_value(params)?;
2415 Ok(McpRequest::CancelTask(p))
2416 }
2417 "ping" => Ok(McpRequest::Ping),
2418 "logging/setLevel" => {
2419 let p: SetLogLevelParams = serde_json::from_value(params)?;
2420 Ok(McpRequest::SetLoggingLevel(p))
2421 }
2422 "completion/complete" => {
2423 let p: CompleteParams = serde_json::from_value(params)?;
2424 Ok(McpRequest::Complete(p))
2425 }
2426 method => Ok(McpRequest::Unknown {
2427 method: method.to_string(),
2428 params: req.params.clone(),
2429 }),
2430 }
2431 }
2432}
2433
2434impl McpNotification {
2435 pub fn from_jsonrpc(notif: &JsonRpcNotification) -> Result<Self, crate::error::Error> {
2437 let params = notif
2438 .params
2439 .clone()
2440 .unwrap_or(Value::Object(Default::default()));
2441
2442 match notif.method.as_str() {
2443 notifications::INITIALIZED => Ok(McpNotification::Initialized),
2444 notifications::CANCELLED => {
2445 let p: CancelledParams = serde_json::from_value(params)?;
2446 Ok(McpNotification::Cancelled(p))
2447 }
2448 notifications::PROGRESS => {
2449 let p: ProgressParams = serde_json::from_value(params)?;
2450 Ok(McpNotification::Progress(p))
2451 }
2452 notifications::ROOTS_LIST_CHANGED => Ok(McpNotification::RootsListChanged),
2453 method => Ok(McpNotification::Unknown {
2454 method: method.to_string(),
2455 params: notif.params.clone(),
2456 }),
2457 }
2458 }
2459}
2460
2461#[cfg(test)]
2462mod tests {
2463 use super::*;
2464
2465 #[test]
2466 fn test_elicit_form_schema_builder() {
2467 let schema = ElicitFormSchema::new()
2468 .string_field("name", Some("Your name"), true)
2469 .number_field("age", Some("Your age"), false)
2470 .boolean_field("agree", Some("Do you agree?"), true)
2471 .enum_field(
2472 "color",
2473 Some("Favorite color"),
2474 vec!["red".to_string(), "green".to_string(), "blue".to_string()],
2475 false,
2476 );
2477
2478 assert_eq!(schema.schema_type, "object");
2479 assert_eq!(schema.properties.len(), 4);
2480 assert_eq!(schema.required.len(), 2);
2481 assert!(schema.required.contains(&"name".to_string()));
2482 assert!(schema.required.contains(&"agree".to_string()));
2483 }
2484
2485 #[test]
2486 fn test_elicit_form_schema_serialization() {
2487 let schema = ElicitFormSchema::new().string_field("username", Some("Enter username"), true);
2488
2489 let json = serde_json::to_value(&schema).unwrap();
2490 assert_eq!(json["type"], "object");
2491 assert!(json["properties"]["username"]["type"] == "string");
2492 assert!(
2493 json["required"]
2494 .as_array()
2495 .unwrap()
2496 .contains(&serde_json::json!("username"))
2497 );
2498 }
2499
2500 #[test]
2501 fn test_elicit_result_accept() {
2502 let mut content = std::collections::HashMap::new();
2503 content.insert(
2504 "name".to_string(),
2505 ElicitFieldValue::String("Alice".to_string()),
2506 );
2507 content.insert("age".to_string(), ElicitFieldValue::Integer(30));
2508
2509 let result = ElicitResult::accept(content);
2510 assert_eq!(result.action, ElicitAction::Accept);
2511 assert!(result.content.is_some());
2512 }
2513
2514 #[test]
2515 fn test_elicit_result_decline() {
2516 let result = ElicitResult::decline();
2517 assert_eq!(result.action, ElicitAction::Decline);
2518 assert!(result.content.is_none());
2519 }
2520
2521 #[test]
2522 fn test_elicit_result_cancel() {
2523 let result = ElicitResult::cancel();
2524 assert_eq!(result.action, ElicitAction::Cancel);
2525 assert!(result.content.is_none());
2526 }
2527
2528 #[test]
2529 fn test_elicit_mode_serialization() {
2530 assert_eq!(
2531 serde_json::to_string(&ElicitMode::Form).unwrap(),
2532 "\"form\""
2533 );
2534 assert_eq!(serde_json::to_string(&ElicitMode::Url).unwrap(), "\"url\"");
2535 }
2536
2537 #[test]
2538 fn test_elicit_action_serialization() {
2539 assert_eq!(
2540 serde_json::to_string(&ElicitAction::Accept).unwrap(),
2541 "\"accept\""
2542 );
2543 assert_eq!(
2544 serde_json::to_string(&ElicitAction::Decline).unwrap(),
2545 "\"decline\""
2546 );
2547 assert_eq!(
2548 serde_json::to_string(&ElicitAction::Cancel).unwrap(),
2549 "\"cancel\""
2550 );
2551 }
2552
2553 #[test]
2554 fn test_elicitation_capability() {
2555 let cap = ElicitationCapability {
2556 form: Some(ElicitationFormCapability {}),
2557 url: None,
2558 };
2559
2560 let json = serde_json::to_value(&cap).unwrap();
2561 assert!(json["form"].is_object());
2562 assert!(json.get("url").is_none());
2563 }
2564
2565 #[test]
2566 fn test_client_capabilities_with_elicitation() {
2567 let caps = ClientCapabilities {
2568 roots: None,
2569 sampling: None,
2570 elicitation: Some(ElicitationCapability {
2571 form: Some(ElicitationFormCapability {}),
2572 url: Some(ElicitationUrlCapability {}),
2573 }),
2574 };
2575
2576 let json = serde_json::to_value(&caps).unwrap();
2577 assert!(json["elicitation"]["form"].is_object());
2578 assert!(json["elicitation"]["url"].is_object());
2579 }
2580
2581 #[test]
2582 fn test_elicit_url_params() {
2583 let params = ElicitUrlParams {
2584 mode: ElicitMode::Url,
2585 elicitation_id: "abc123".to_string(),
2586 message: "Please authorize".to_string(),
2587 url: "https://example.com/auth".to_string(),
2588 meta: None,
2589 };
2590
2591 let json = serde_json::to_value(¶ms).unwrap();
2592 assert_eq!(json["mode"], "url");
2593 assert_eq!(json["elicitationId"], "abc123");
2594 assert_eq!(json["message"], "Please authorize");
2595 assert_eq!(json["url"], "https://example.com/auth");
2596 }
2597
2598 #[test]
2599 fn test_elicitation_complete_params() {
2600 let params = ElicitationCompleteParams {
2601 elicitation_id: "xyz789".to_string(),
2602 };
2603
2604 let json = serde_json::to_value(¶ms).unwrap();
2605 assert_eq!(json["elicitationId"], "xyz789");
2606 }
2607
2608 #[test]
2609 fn test_root_new() {
2610 let root = Root::new("file:///home/user/project");
2611 assert_eq!(root.uri, "file:///home/user/project");
2612 assert!(root.name.is_none());
2613 }
2614
2615 #[test]
2616 fn test_root_with_name() {
2617 let root = Root::with_name("file:///home/user/project", "My Project");
2618 assert_eq!(root.uri, "file:///home/user/project");
2619 assert_eq!(root.name.as_deref(), Some("My Project"));
2620 }
2621
2622 #[test]
2623 fn test_root_serialization() {
2624 let root = Root::with_name("file:///workspace", "Workspace");
2625 let json = serde_json::to_value(&root).unwrap();
2626 assert_eq!(json["uri"], "file:///workspace");
2627 assert_eq!(json["name"], "Workspace");
2628 }
2629
2630 #[test]
2631 fn test_root_serialization_without_name() {
2632 let root = Root::new("file:///workspace");
2633 let json = serde_json::to_value(&root).unwrap();
2634 assert_eq!(json["uri"], "file:///workspace");
2635 assert!(json.get("name").is_none());
2636 }
2637
2638 #[test]
2639 fn test_root_deserialization() {
2640 let json = serde_json::json!({
2641 "uri": "file:///home/user",
2642 "name": "Home"
2643 });
2644 let root: Root = serde_json::from_value(json).unwrap();
2645 assert_eq!(root.uri, "file:///home/user");
2646 assert_eq!(root.name.as_deref(), Some("Home"));
2647 }
2648
2649 #[test]
2650 fn test_list_roots_result() {
2651 let result = ListRootsResult {
2652 roots: vec![
2653 Root::new("file:///project1"),
2654 Root::with_name("file:///project2", "Project 2"),
2655 ],
2656 };
2657
2658 let json = serde_json::to_value(&result).unwrap();
2659 let roots = json["roots"].as_array().unwrap();
2660 assert_eq!(roots.len(), 2);
2661 assert_eq!(roots[0]["uri"], "file:///project1");
2662 assert_eq!(roots[1]["name"], "Project 2");
2663 }
2664
2665 #[test]
2666 fn test_roots_capability_serialization() {
2667 let cap = RootsCapability { list_changed: true };
2668 let json = serde_json::to_value(&cap).unwrap();
2669 assert_eq!(json["listChanged"], true);
2670 }
2671
2672 #[test]
2673 fn test_client_capabilities_with_roots() {
2674 let caps = ClientCapabilities {
2675 roots: Some(RootsCapability { list_changed: true }),
2676 sampling: None,
2677 elicitation: None,
2678 };
2679
2680 let json = serde_json::to_value(&caps).unwrap();
2681 assert_eq!(json["roots"]["listChanged"], true);
2682 }
2683
2684 #[test]
2685 fn test_roots_list_changed_notification_parsing() {
2686 let notif = JsonRpcNotification {
2687 jsonrpc: "2.0".to_string(),
2688 method: notifications::ROOTS_LIST_CHANGED.to_string(),
2689 params: None,
2690 };
2691
2692 let mcp_notif = McpNotification::from_jsonrpc(¬if).unwrap();
2693 assert!(matches!(mcp_notif, McpNotification::RootsListChanged));
2694 }
2695
2696 #[test]
2701 fn test_prompt_reference() {
2702 let ref_ = PromptReference::new("my-prompt");
2703 assert_eq!(ref_.ref_type, "ref/prompt");
2704 assert_eq!(ref_.name, "my-prompt");
2705
2706 let json = serde_json::to_value(&ref_).unwrap();
2707 assert_eq!(json["type"], "ref/prompt");
2708 assert_eq!(json["name"], "my-prompt");
2709 }
2710
2711 #[test]
2712 fn test_resource_reference() {
2713 let ref_ = ResourceReference::new("file:///path/to/file");
2714 assert_eq!(ref_.ref_type, "ref/resource");
2715 assert_eq!(ref_.uri, "file:///path/to/file");
2716
2717 let json = serde_json::to_value(&ref_).unwrap();
2718 assert_eq!(json["type"], "ref/resource");
2719 assert_eq!(json["uri"], "file:///path/to/file");
2720 }
2721
2722 #[test]
2723 fn test_completion_reference_prompt() {
2724 let ref_ = CompletionReference::prompt("test-prompt");
2725 let json = serde_json::to_value(&ref_).unwrap();
2726 assert_eq!(json["type"], "ref/prompt");
2727 assert_eq!(json["name"], "test-prompt");
2728 }
2729
2730 #[test]
2731 fn test_completion_reference_resource() {
2732 let ref_ = CompletionReference::resource("file:///test");
2733 let json = serde_json::to_value(&ref_).unwrap();
2734 assert_eq!(json["type"], "ref/resource");
2735 assert_eq!(json["uri"], "file:///test");
2736 }
2737
2738 #[test]
2739 fn test_completion_argument() {
2740 let arg = CompletionArgument::new("query", "SELECT * FROM");
2741 assert_eq!(arg.name, "query");
2742 assert_eq!(arg.value, "SELECT * FROM");
2743 }
2744
2745 #[test]
2746 fn test_complete_params_serialization() {
2747 let params = CompleteParams {
2748 reference: CompletionReference::prompt("sql-prompt"),
2749 argument: CompletionArgument::new("query", "SEL"),
2750 };
2751
2752 let json = serde_json::to_value(¶ms).unwrap();
2753 assert_eq!(json["ref"]["type"], "ref/prompt");
2754 assert_eq!(json["ref"]["name"], "sql-prompt");
2755 assert_eq!(json["argument"]["name"], "query");
2756 assert_eq!(json["argument"]["value"], "SEL");
2757 }
2758
2759 #[test]
2760 fn test_completion_new() {
2761 let completion = Completion::new(vec!["SELECT".to_string(), "SET".to_string()]);
2762 assert_eq!(completion.values.len(), 2);
2763 assert!(completion.total.is_none());
2764 assert!(completion.has_more.is_none());
2765 }
2766
2767 #[test]
2768 fn test_completion_with_pagination() {
2769 let completion =
2770 Completion::with_pagination(vec!["a".to_string(), "b".to_string()], 100, true);
2771 assert_eq!(completion.values.len(), 2);
2772 assert_eq!(completion.total, Some(100));
2773 assert_eq!(completion.has_more, Some(true));
2774 }
2775
2776 #[test]
2777 fn test_complete_result() {
2778 let result = CompleteResult::new(vec!["option1".to_string(), "option2".to_string()]);
2779 let json = serde_json::to_value(&result).unwrap();
2780 assert!(json["completion"]["values"].is_array());
2781 assert_eq!(json["completion"]["values"][0], "option1");
2782 }
2783
2784 #[test]
2789 fn test_model_hint() {
2790 let hint = ModelHint::new("claude-3-opus");
2791 assert_eq!(hint.name, "claude-3-opus");
2792 }
2793
2794 #[test]
2795 fn test_model_preferences_builder() {
2796 let prefs = ModelPreferences::new()
2797 .speed(0.8)
2798 .intelligence(0.9)
2799 .cost(0.5)
2800 .hint("gpt-4")
2801 .hint("claude-3");
2802
2803 assert_eq!(prefs.speed_priority, Some(0.8));
2804 assert_eq!(prefs.intelligence_priority, Some(0.9));
2805 assert_eq!(prefs.cost_priority, Some(0.5));
2806 assert_eq!(prefs.hints.len(), 2);
2807 }
2808
2809 #[test]
2810 fn test_model_preferences_clamping() {
2811 let prefs = ModelPreferences::new().speed(1.5).cost(-0.5);
2812
2813 assert_eq!(prefs.speed_priority, Some(1.0)); assert_eq!(prefs.cost_priority, Some(0.0)); }
2816
2817 #[test]
2818 fn test_include_context_serialization() {
2819 assert_eq!(
2820 serde_json::to_string(&IncludeContext::AllServers).unwrap(),
2821 "\"allServers\""
2822 );
2823 assert_eq!(
2824 serde_json::to_string(&IncludeContext::ThisServer).unwrap(),
2825 "\"thisServer\""
2826 );
2827 assert_eq!(
2828 serde_json::to_string(&IncludeContext::None).unwrap(),
2829 "\"none\""
2830 );
2831 }
2832
2833 #[test]
2834 fn test_sampling_message_user() {
2835 let msg = SamplingMessage::user("Hello, how are you?");
2836 assert_eq!(msg.role, ContentRole::User);
2837 assert!(
2838 matches!(msg.content, SamplingContent::Text { text } if text == "Hello, how are you?")
2839 );
2840 }
2841
2842 #[test]
2843 fn test_sampling_message_assistant() {
2844 let msg = SamplingMessage::assistant("I'm doing well!");
2845 assert_eq!(msg.role, ContentRole::Assistant);
2846 }
2847
2848 #[test]
2849 fn test_sampling_content_text_serialization() {
2850 let content = SamplingContent::Text {
2851 text: "Hello".to_string(),
2852 };
2853 let json = serde_json::to_value(&content).unwrap();
2854 assert_eq!(json["type"], "text");
2855 assert_eq!(json["text"], "Hello");
2856 }
2857
2858 #[test]
2859 fn test_sampling_content_image_serialization() {
2860 let content = SamplingContent::Image {
2861 data: "base64data".to_string(),
2862 mime_type: "image/png".to_string(),
2863 };
2864 let json = serde_json::to_value(&content).unwrap();
2865 assert_eq!(json["type"], "image");
2866 assert_eq!(json["data"], "base64data");
2867 assert_eq!(json["mimeType"], "image/png");
2868 }
2869
2870 #[test]
2871 fn test_create_message_params() {
2872 let params = CreateMessageParams::new(
2873 vec![
2874 SamplingMessage::user("What is 2+2?"),
2875 SamplingMessage::assistant("4"),
2876 SamplingMessage::user("And 3+3?"),
2877 ],
2878 100,
2879 )
2880 .system_prompt("You are a math tutor")
2881 .temperature(0.7)
2882 .stop_sequence("END")
2883 .include_context(IncludeContext::ThisServer);
2884
2885 assert_eq!(params.messages.len(), 3);
2886 assert_eq!(params.max_tokens, 100);
2887 assert_eq!(
2888 params.system_prompt.as_deref(),
2889 Some("You are a math tutor")
2890 );
2891 assert_eq!(params.temperature, Some(0.7));
2892 assert_eq!(params.stop_sequences.len(), 1);
2893 assert_eq!(params.include_context, Some(IncludeContext::ThisServer));
2894 }
2895
2896 #[test]
2897 fn test_create_message_params_serialization() {
2898 let params = CreateMessageParams::new(vec![SamplingMessage::user("Hello")], 50);
2899
2900 let json = serde_json::to_value(¶ms).unwrap();
2901 assert!(json["messages"].is_array());
2902 assert_eq!(json["maxTokens"], 50);
2903 }
2904
2905 #[test]
2906 fn test_create_message_result_deserialization() {
2907 let json = serde_json::json!({
2908 "content": {
2909 "type": "text",
2910 "text": "The answer is 42"
2911 },
2912 "model": "claude-3-opus",
2913 "role": "assistant",
2914 "stopReason": "end_turn"
2915 });
2916
2917 let result: CreateMessageResult = serde_json::from_value(json).unwrap();
2918 assert_eq!(result.model, "claude-3-opus");
2919 assert_eq!(result.role, ContentRole::Assistant);
2920 assert_eq!(result.stop_reason.as_deref(), Some("end_turn"));
2921 }
2922
2923 #[test]
2924 fn test_completions_capability_serialization() {
2925 let cap = CompletionsCapability {};
2926 let json = serde_json::to_value(&cap).unwrap();
2927 assert!(json.is_object());
2928 }
2929
2930 #[test]
2931 fn test_server_capabilities_with_completions() {
2932 let caps = ServerCapabilities {
2933 completions: Some(CompletionsCapability {}),
2934 ..Default::default()
2935 };
2936
2937 let json = serde_json::to_value(&caps).unwrap();
2938 assert!(json["completions"].is_object());
2939 }
2940
2941 #[test]
2942 fn test_content_resource_link_serialization() {
2943 let content = Content::ResourceLink {
2944 uri: "file:///test.txt".to_string(),
2945 name: Some("test.txt".to_string()),
2946 description: Some("A test file".to_string()),
2947 mime_type: Some("text/plain".to_string()),
2948 annotations: None,
2949 };
2950 let json = serde_json::to_value(&content).unwrap();
2951 assert_eq!(json["type"], "resource_link");
2952 assert_eq!(json["uri"], "file:///test.txt");
2953 assert_eq!(json["name"], "test.txt");
2954 assert_eq!(json["description"], "A test file");
2955 assert_eq!(json["mimeType"], "text/plain");
2956 }
2957
2958 #[test]
2959 fn test_call_tool_result_resource_link() {
2960 let result = CallToolResult::resource_link("file:///output.json");
2961 assert_eq!(result.content.len(), 1);
2962 assert!(!result.is_error);
2963 match &result.content[0] {
2964 Content::ResourceLink { uri, .. } => assert_eq!(uri, "file:///output.json"),
2965 _ => panic!("Expected ResourceLink content"),
2966 }
2967 }
2968
2969 #[test]
2970 fn test_call_tool_result_image() {
2971 let result = CallToolResult::image("base64data", "image/png");
2972 assert_eq!(result.content.len(), 1);
2973 match &result.content[0] {
2974 Content::Image {
2975 data, mime_type, ..
2976 } => {
2977 assert_eq!(data, "base64data");
2978 assert_eq!(mime_type, "image/png");
2979 }
2980 _ => panic!("Expected Image content"),
2981 }
2982 }
2983
2984 #[test]
2985 fn test_call_tool_result_audio() {
2986 let result = CallToolResult::audio("audiodata", "audio/wav");
2987 assert_eq!(result.content.len(), 1);
2988 match &result.content[0] {
2989 Content::Audio {
2990 data, mime_type, ..
2991 } => {
2992 assert_eq!(data, "audiodata");
2993 assert_eq!(mime_type, "audio/wav");
2994 }
2995 _ => panic!("Expected Audio content"),
2996 }
2997 }
2998}