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-11-25";
16
17pub const SUPPORTED_PROTOCOL_VERSIONS: &[&str] = &["2025-11-25", "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)]
870#[serde(rename_all = "camelCase")]
871pub struct SamplingTool {
872 pub name: String,
874 #[serde(skip_serializing_if = "Option::is_none")]
876 pub description: Option<String>,
877 pub input_schema: Value,
879}
880
881#[derive(Debug, Clone, Serialize, Deserialize)]
885#[serde(rename_all = "camelCase")]
886pub struct ToolChoice {
887 #[serde(rename = "type")]
892 pub mode: String,
893}
894
895impl ToolChoice {
896 pub fn auto() -> Self {
898 Self {
899 mode: "auto".to_string(),
900 }
901 }
902
903 pub fn required() -> Self {
905 Self {
906 mode: "required".to_string(),
907 }
908 }
909
910 pub fn none() -> Self {
912 Self {
913 mode: "none".to_string(),
914 }
915 }
916}
917
918#[derive(Debug, Clone, Serialize, Deserialize)]
920#[serde(tag = "type", rename_all = "lowercase")]
921pub enum SamplingContent {
922 Text {
924 text: String,
926 },
927 Image {
929 data: String,
931 #[serde(rename = "mimeType")]
933 mime_type: String,
934 },
935 Audio {
937 data: String,
939 #[serde(rename = "mimeType")]
941 mime_type: String,
942 },
943 #[serde(rename = "tool_use")]
945 ToolUse {
946 id: String,
948 name: String,
950 input: Value,
952 },
953 #[serde(rename = "tool_result")]
955 ToolResult {
956 tool_use_id: String,
958 content: Vec<SamplingContent>,
960 #[serde(default, skip_serializing_if = "Option::is_none")]
962 is_error: Option<bool>,
963 },
964}
965
966#[derive(Debug, Clone, Serialize, Deserialize)]
971#[serde(untagged)]
972pub enum SamplingContentOrArray {
973 Single(SamplingContent),
975 Array(Vec<SamplingContent>),
977}
978
979impl SamplingContentOrArray {
980 pub fn items(&self) -> Vec<&SamplingContent> {
982 match self {
983 Self::Single(c) => vec![c],
984 Self::Array(arr) => arr.iter().collect(),
985 }
986 }
987
988 pub fn into_items(self) -> Vec<SamplingContent> {
990 match self {
991 Self::Single(c) => vec![c],
992 Self::Array(arr) => arr,
993 }
994 }
995}
996
997#[derive(Debug, Clone, Serialize, Deserialize)]
999#[serde(rename_all = "camelCase")]
1000pub struct CreateMessageParams {
1001 pub messages: Vec<SamplingMessage>,
1003 pub max_tokens: u32,
1005 #[serde(default, skip_serializing_if = "Option::is_none")]
1007 pub system_prompt: Option<String>,
1008 #[serde(default, skip_serializing_if = "Option::is_none")]
1010 pub temperature: Option<f64>,
1011 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1013 pub stop_sequences: Vec<String>,
1014 #[serde(default, skip_serializing_if = "Option::is_none")]
1016 pub model_preferences: Option<ModelPreferences>,
1017 #[serde(default, skip_serializing_if = "Option::is_none")]
1019 pub include_context: Option<IncludeContext>,
1020 #[serde(default, skip_serializing_if = "Option::is_none")]
1022 pub metadata: Option<serde_json::Map<String, Value>>,
1023 #[serde(default, skip_serializing_if = "Option::is_none")]
1025 pub tools: Option<Vec<SamplingTool>>,
1026 #[serde(default, skip_serializing_if = "Option::is_none")]
1028 pub tool_choice: Option<ToolChoice>,
1029}
1030
1031impl CreateMessageParams {
1032 pub fn new(messages: Vec<SamplingMessage>, max_tokens: u32) -> Self {
1034 Self {
1035 messages,
1036 max_tokens,
1037 system_prompt: None,
1038 temperature: None,
1039 stop_sequences: Vec::new(),
1040 model_preferences: None,
1041 include_context: None,
1042 metadata: None,
1043 tools: None,
1044 tool_choice: None,
1045 }
1046 }
1047
1048 pub fn system_prompt(mut self, prompt: impl Into<String>) -> Self {
1050 self.system_prompt = Some(prompt.into());
1051 self
1052 }
1053
1054 pub fn temperature(mut self, temp: f64) -> Self {
1056 self.temperature = Some(temp.clamp(0.0, 1.0));
1057 self
1058 }
1059
1060 pub fn stop_sequence(mut self, seq: impl Into<String>) -> Self {
1062 self.stop_sequences.push(seq.into());
1063 self
1064 }
1065
1066 pub fn model_preferences(mut self, prefs: ModelPreferences) -> Self {
1068 self.model_preferences = Some(prefs);
1069 self
1070 }
1071
1072 pub fn include_context(mut self, mode: IncludeContext) -> Self {
1074 self.include_context = Some(mode);
1075 self
1076 }
1077
1078 pub fn tools(mut self, tools: Vec<SamplingTool>) -> Self {
1080 self.tools = Some(tools);
1081 self
1082 }
1083
1084 pub fn tool_choice(mut self, choice: ToolChoice) -> Self {
1086 self.tool_choice = Some(choice);
1087 self
1088 }
1089}
1090
1091#[derive(Debug, Clone, Serialize, Deserialize)]
1093#[serde(rename_all = "camelCase")]
1094pub struct CreateMessageResult {
1095 pub content: SamplingContentOrArray,
1097 pub model: String,
1099 pub role: ContentRole,
1101 #[serde(default, skip_serializing_if = "Option::is_none")]
1103 pub stop_reason: Option<String>,
1104}
1105
1106impl CreateMessageResult {
1107 pub fn content_items(&self) -> Vec<&SamplingContent> {
1109 self.content.items()
1110 }
1111}
1112
1113#[derive(Debug, Clone, Default, Deserialize, Serialize)]
1115#[serde(rename_all = "camelCase")]
1116pub struct Implementation {
1117 pub name: String,
1119 pub version: String,
1121 #[serde(skip_serializing_if = "Option::is_none")]
1123 pub title: Option<String>,
1124 #[serde(skip_serializing_if = "Option::is_none")]
1126 pub description: Option<String>,
1127 #[serde(skip_serializing_if = "Option::is_none")]
1129 pub icons: Option<Vec<ToolIcon>>,
1130 #[serde(skip_serializing_if = "Option::is_none")]
1132 pub website_url: Option<String>,
1133}
1134
1135#[derive(Debug, Clone, Serialize, Deserialize)]
1136#[serde(rename_all = "camelCase")]
1137pub struct InitializeResult {
1138 pub protocol_version: String,
1139 pub capabilities: ServerCapabilities,
1140 pub server_info: Implementation,
1141 #[serde(skip_serializing_if = "Option::is_none")]
1144 pub instructions: Option<String>,
1145}
1146
1147#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1148#[serde(rename_all = "camelCase")]
1149pub struct ServerCapabilities {
1150 #[serde(default, skip_serializing_if = "Option::is_none")]
1151 pub tools: Option<ToolsCapability>,
1152 #[serde(default, skip_serializing_if = "Option::is_none")]
1153 pub resources: Option<ResourcesCapability>,
1154 #[serde(default, skip_serializing_if = "Option::is_none")]
1155 pub prompts: Option<PromptsCapability>,
1156 #[serde(default, skip_serializing_if = "Option::is_none")]
1158 pub logging: Option<LoggingCapability>,
1159 #[serde(default, skip_serializing_if = "Option::is_none")]
1160 pub tasks: Option<TasksCapability>,
1161 #[serde(default, skip_serializing_if = "Option::is_none")]
1163 pub completions: Option<CompletionsCapability>,
1164}
1165
1166#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1168pub struct LoggingCapability {}
1169
1170#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1172#[serde(rename_all = "camelCase")]
1173pub struct TasksCapability {
1174 #[serde(default, skip_serializing_if = "Option::is_none")]
1176 pub default_poll_interval: Option<u64>,
1177}
1178
1179#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1180#[serde(rename_all = "camelCase")]
1181pub struct ToolsCapability {
1182 #[serde(default)]
1183 pub list_changed: bool,
1184}
1185
1186#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1187#[serde(rename_all = "camelCase")]
1188pub struct ResourcesCapability {
1189 #[serde(default)]
1190 pub subscribe: bool,
1191 #[serde(default)]
1192 pub list_changed: bool,
1193}
1194
1195#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1196#[serde(rename_all = "camelCase")]
1197pub struct PromptsCapability {
1198 #[serde(default)]
1199 pub list_changed: bool,
1200}
1201
1202#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1207pub struct ListToolsParams {
1208 #[serde(default)]
1209 pub cursor: Option<String>,
1210}
1211
1212#[derive(Debug, Clone, Serialize, Deserialize)]
1213#[serde(rename_all = "camelCase")]
1214pub struct ListToolsResult {
1215 pub tools: Vec<ToolDefinition>,
1216 #[serde(default, skip_serializing_if = "Option::is_none")]
1217 pub next_cursor: Option<String>,
1218}
1219
1220#[derive(Debug, Clone, Serialize, Deserialize)]
1222#[serde(rename_all = "camelCase")]
1223pub struct ToolDefinition {
1224 pub name: String,
1225 #[serde(skip_serializing_if = "Option::is_none")]
1227 pub title: Option<String>,
1228 #[serde(skip_serializing_if = "Option::is_none")]
1229 pub description: Option<String>,
1230 pub input_schema: Value,
1231 #[serde(skip_serializing_if = "Option::is_none")]
1233 pub output_schema: Option<Value>,
1234 #[serde(skip_serializing_if = "Option::is_none")]
1236 pub icons: Option<Vec<ToolIcon>>,
1237 #[serde(skip_serializing_if = "Option::is_none")]
1240 pub annotations: Option<ToolAnnotations>,
1241}
1242
1243#[derive(Debug, Clone, Serialize, Deserialize)]
1245#[serde(rename_all = "camelCase")]
1246pub struct ToolIcon {
1247 pub src: String,
1249 #[serde(skip_serializing_if = "Option::is_none")]
1251 pub mime_type: Option<String>,
1252 #[serde(skip_serializing_if = "Option::is_none")]
1254 pub sizes: Option<Vec<String>>,
1255}
1256
1257#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1260#[serde(rename_all = "camelCase")]
1261pub struct ToolAnnotations {
1262 #[serde(skip_serializing_if = "Option::is_none")]
1264 pub title: Option<String>,
1265 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1267 pub read_only_hint: bool,
1268 #[serde(default = "default_true", skip_serializing_if = "is_true")]
1271 pub destructive_hint: bool,
1272 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1275 pub idempotent_hint: bool,
1276 #[serde(default = "default_true", skip_serializing_if = "is_true")]
1278 pub open_world_hint: bool,
1279}
1280
1281fn default_true() -> bool {
1282 true
1283}
1284
1285fn is_true(v: &bool) -> bool {
1286 *v
1287}
1288
1289#[derive(Debug, Clone, Serialize, Deserialize)]
1290pub struct CallToolParams {
1291 pub name: String,
1292 #[serde(default)]
1293 pub arguments: Value,
1294 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1296 pub meta: Option<RequestMeta>,
1297}
1298
1299#[derive(Debug, Clone, Serialize, Deserialize)]
1320#[serde(rename_all = "camelCase")]
1321pub struct CallToolResult {
1322 pub content: Vec<Content>,
1324 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1326 pub is_error: bool,
1327 #[serde(default, skip_serializing_if = "Option::is_none")]
1329 pub structured_content: Option<Value>,
1330}
1331
1332impl CallToolResult {
1333 pub fn text(text: impl Into<String>) -> Self {
1337 Self {
1338 content: vec![Content::Text {
1339 text: text.into(),
1340 annotations: None,
1341 }],
1342 is_error: false,
1343 structured_content: None,
1344 }
1345 }
1346
1347 pub fn error(message: impl Into<String>) -> Self {
1352 Self {
1353 content: vec![Content::Text {
1354 text: message.into(),
1355 annotations: None,
1356 }],
1357 is_error: true,
1358 structured_content: None,
1359 }
1360 }
1361
1362 pub fn json(value: Value) -> Self {
1370 let text = serde_json::to_string_pretty(&value).unwrap_or_default();
1371 Self {
1372 content: vec![Content::Text {
1373 text,
1374 annotations: None,
1375 }],
1376 is_error: false,
1377 structured_content: Some(value),
1378 }
1379 }
1380
1381 pub fn from_serialize(
1413 value: &impl serde::Serialize,
1414 ) -> std::result::Result<Self, crate::error::Error> {
1415 let json_value = serde_json::to_value(value)
1416 .map_err(|e| crate::error::Error::tool(format!("Serialization failed: {}", e)))?;
1417 Ok(Self::json(json_value))
1418 }
1419
1420 pub fn image(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1422 Self {
1423 content: vec![Content::Image {
1424 data: data.into(),
1425 mime_type: mime_type.into(),
1426 annotations: None,
1427 }],
1428 is_error: false,
1429 structured_content: None,
1430 }
1431 }
1432
1433 pub fn audio(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1435 Self {
1436 content: vec![Content::Audio {
1437 data: data.into(),
1438 mime_type: mime_type.into(),
1439 annotations: None,
1440 }],
1441 is_error: false,
1442 structured_content: None,
1443 }
1444 }
1445
1446 pub fn resource_link(uri: impl Into<String>) -> Self {
1448 Self {
1449 content: vec![Content::ResourceLink {
1450 uri: uri.into(),
1451 name: None,
1452 description: None,
1453 mime_type: None,
1454 annotations: None,
1455 }],
1456 is_error: false,
1457 structured_content: None,
1458 }
1459 }
1460
1461 pub fn resource_link_with_meta(
1463 uri: impl Into<String>,
1464 name: Option<String>,
1465 description: Option<String>,
1466 mime_type: Option<String>,
1467 ) -> Self {
1468 Self {
1469 content: vec![Content::ResourceLink {
1470 uri: uri.into(),
1471 name,
1472 description,
1473 mime_type,
1474 annotations: None,
1475 }],
1476 is_error: false,
1477 structured_content: None,
1478 }
1479 }
1480
1481 pub fn resource(resource: ResourceContent) -> Self {
1483 Self {
1484 content: vec![Content::Resource {
1485 resource,
1486 annotations: None,
1487 }],
1488 is_error: false,
1489 structured_content: None,
1490 }
1491 }
1492
1493 pub fn all_text(&self) -> String {
1507 self.content.iter().filter_map(|c| c.as_text()).collect()
1508 }
1509
1510 pub fn first_text(&self) -> Option<&str> {
1523 self.content.iter().find_map(|c| c.as_text())
1524 }
1525}
1526
1527#[derive(Debug, Clone, Serialize, Deserialize)]
1532#[serde(tag = "type", rename_all = "snake_case")]
1533pub enum Content {
1534 Text {
1536 text: String,
1538 #[serde(skip_serializing_if = "Option::is_none")]
1540 annotations: Option<ContentAnnotations>,
1541 },
1542 Image {
1544 data: String,
1546 #[serde(rename = "mimeType")]
1548 mime_type: String,
1549 #[serde(skip_serializing_if = "Option::is_none")]
1551 annotations: Option<ContentAnnotations>,
1552 },
1553 Audio {
1555 data: String,
1557 #[serde(rename = "mimeType")]
1559 mime_type: String,
1560 #[serde(skip_serializing_if = "Option::is_none")]
1562 annotations: Option<ContentAnnotations>,
1563 },
1564 Resource {
1566 resource: ResourceContent,
1568 #[serde(skip_serializing_if = "Option::is_none")]
1570 annotations: Option<ContentAnnotations>,
1571 },
1572 ResourceLink {
1574 uri: String,
1576 #[serde(skip_serializing_if = "Option::is_none")]
1578 name: Option<String>,
1579 #[serde(skip_serializing_if = "Option::is_none")]
1581 description: Option<String>,
1582 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
1584 mime_type: Option<String>,
1585 #[serde(skip_serializing_if = "Option::is_none")]
1586 annotations: Option<ContentAnnotations>,
1587 },
1588}
1589
1590#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1592pub struct ContentAnnotations {
1593 #[serde(skip_serializing_if = "Option::is_none")]
1595 pub audience: Option<Vec<ContentRole>>,
1596 #[serde(skip_serializing_if = "Option::is_none")]
1598 pub priority: Option<f64>,
1599}
1600
1601impl Content {
1602 pub fn as_text(&self) -> Option<&str> {
1615 match self {
1616 Content::Text { text, .. } => Some(text),
1617 _ => None,
1618 }
1619 }
1620}
1621
1622#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1626#[serde(rename_all = "lowercase")]
1627pub enum ContentRole {
1628 User,
1630 Assistant,
1632}
1633
1634#[derive(Debug, Clone, Serialize, Deserialize)]
1638#[serde(rename_all = "camelCase")]
1639pub struct ResourceContent {
1640 pub uri: String,
1642 #[serde(skip_serializing_if = "Option::is_none")]
1644 pub mime_type: Option<String>,
1645 #[serde(skip_serializing_if = "Option::is_none")]
1647 pub text: Option<String>,
1648 #[serde(skip_serializing_if = "Option::is_none")]
1650 pub blob: Option<String>,
1651}
1652
1653#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1658pub struct ListResourcesParams {
1659 #[serde(default)]
1660 pub cursor: Option<String>,
1661}
1662
1663#[derive(Debug, Clone, Serialize, Deserialize)]
1664#[serde(rename_all = "camelCase")]
1665pub struct ListResourcesResult {
1666 pub resources: Vec<ResourceDefinition>,
1667 #[serde(default, skip_serializing_if = "Option::is_none")]
1668 pub next_cursor: Option<String>,
1669}
1670
1671#[derive(Debug, Clone, Serialize, Deserialize)]
1672#[serde(rename_all = "camelCase")]
1673pub struct ResourceDefinition {
1674 pub uri: String,
1675 pub name: String,
1676 #[serde(skip_serializing_if = "Option::is_none")]
1678 pub title: Option<String>,
1679 #[serde(skip_serializing_if = "Option::is_none")]
1680 pub description: Option<String>,
1681 #[serde(skip_serializing_if = "Option::is_none")]
1682 pub mime_type: Option<String>,
1683 #[serde(skip_serializing_if = "Option::is_none")]
1685 pub icons: Option<Vec<ToolIcon>>,
1686 #[serde(skip_serializing_if = "Option::is_none")]
1688 pub size: Option<u64>,
1689}
1690
1691#[derive(Debug, Clone, Serialize, Deserialize)]
1692pub struct ReadResourceParams {
1693 pub uri: String,
1694}
1695
1696#[derive(Debug, Clone, Serialize, Deserialize)]
1697pub struct ReadResourceResult {
1698 pub contents: Vec<ResourceContent>,
1699}
1700
1701impl ReadResourceResult {
1702 pub fn text(uri: impl Into<String>, content: impl Into<String>) -> Self {
1712 Self {
1713 contents: vec![ResourceContent {
1714 uri: uri.into(),
1715 mime_type: Some("text/plain".to_string()),
1716 text: Some(content.into()),
1717 blob: None,
1718 }],
1719 }
1720 }
1721
1722 pub fn text_with_mime(
1736 uri: impl Into<String>,
1737 content: impl Into<String>,
1738 mime_type: impl Into<String>,
1739 ) -> Self {
1740 Self {
1741 contents: vec![ResourceContent {
1742 uri: uri.into(),
1743 mime_type: Some(mime_type.into()),
1744 text: Some(content.into()),
1745 blob: None,
1746 }],
1747 }
1748 }
1749
1750 pub fn json<T: serde::Serialize>(uri: impl Into<String>, value: &T) -> Self {
1764 let json_string =
1765 serde_json::to_string_pretty(value).unwrap_or_else(|_| "null".to_string());
1766 Self {
1767 contents: vec![ResourceContent {
1768 uri: uri.into(),
1769 mime_type: Some("application/json".to_string()),
1770 text: Some(json_string),
1771 blob: None,
1772 }],
1773 }
1774 }
1775
1776 pub fn blob(uri: impl Into<String>, bytes: &[u8]) -> Self {
1787 use base64::Engine;
1788 let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
1789 Self {
1790 contents: vec![ResourceContent {
1791 uri: uri.into(),
1792 mime_type: Some("application/octet-stream".to_string()),
1793 text: None,
1794 blob: Some(encoded),
1795 }],
1796 }
1797 }
1798
1799 pub fn blob_with_mime(
1810 uri: impl Into<String>,
1811 bytes: &[u8],
1812 mime_type: impl Into<String>,
1813 ) -> Self {
1814 use base64::Engine;
1815 let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
1816 Self {
1817 contents: vec![ResourceContent {
1818 uri: uri.into(),
1819 mime_type: Some(mime_type.into()),
1820 text: None,
1821 blob: Some(encoded),
1822 }],
1823 }
1824 }
1825
1826 pub fn first_text(&self) -> Option<&str> {
1839 self.contents.first().and_then(|c| c.text.as_deref())
1840 }
1841
1842 pub fn first_uri(&self) -> Option<&str> {
1855 self.contents.first().map(|c| c.uri.as_str())
1856 }
1857}
1858
1859#[derive(Debug, Clone, Deserialize)]
1860pub struct SubscribeResourceParams {
1861 pub uri: String,
1862}
1863
1864#[derive(Debug, Clone, Deserialize)]
1865pub struct UnsubscribeResourceParams {
1866 pub uri: String,
1867}
1868
1869#[derive(Debug, Clone, Default, Deserialize)]
1871pub struct ListResourceTemplatesParams {
1872 #[serde(default)]
1874 pub cursor: Option<String>,
1875}
1876
1877#[derive(Debug, Clone, Serialize)]
1879#[serde(rename_all = "camelCase")]
1880pub struct ListResourceTemplatesResult {
1881 pub resource_templates: Vec<ResourceTemplateDefinition>,
1883 #[serde(skip_serializing_if = "Option::is_none")]
1885 pub next_cursor: Option<String>,
1886}
1887
1888#[derive(Debug, Clone, Serialize, Deserialize)]
1904#[serde(rename_all = "camelCase")]
1905pub struct ResourceTemplateDefinition {
1906 pub uri_template: String,
1908 pub name: String,
1910 #[serde(skip_serializing_if = "Option::is_none")]
1912 pub title: Option<String>,
1913 #[serde(skip_serializing_if = "Option::is_none")]
1915 pub description: Option<String>,
1916 #[serde(skip_serializing_if = "Option::is_none")]
1918 pub mime_type: Option<String>,
1919 #[serde(skip_serializing_if = "Option::is_none")]
1921 pub icons: Option<Vec<ToolIcon>>,
1922}
1923
1924#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1929pub struct ListPromptsParams {
1930 #[serde(default)]
1931 pub cursor: Option<String>,
1932}
1933
1934#[derive(Debug, Clone, Serialize, Deserialize)]
1935#[serde(rename_all = "camelCase")]
1936pub struct ListPromptsResult {
1937 pub prompts: Vec<PromptDefinition>,
1938 #[serde(default, skip_serializing_if = "Option::is_none")]
1939 pub next_cursor: Option<String>,
1940}
1941
1942#[derive(Debug, Clone, Serialize, Deserialize)]
1943pub struct PromptDefinition {
1944 pub name: String,
1945 #[serde(skip_serializing_if = "Option::is_none")]
1947 pub title: Option<String>,
1948 #[serde(skip_serializing_if = "Option::is_none")]
1949 pub description: Option<String>,
1950 #[serde(skip_serializing_if = "Option::is_none")]
1952 pub icons: Option<Vec<ToolIcon>>,
1953 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1954 pub arguments: Vec<PromptArgument>,
1955}
1956
1957#[derive(Debug, Clone, Serialize, Deserialize)]
1958pub struct PromptArgument {
1959 pub name: String,
1960 #[serde(skip_serializing_if = "Option::is_none")]
1961 pub description: Option<String>,
1962 #[serde(default)]
1963 pub required: bool,
1964}
1965
1966#[derive(Debug, Clone, Serialize, Deserialize)]
1967pub struct GetPromptParams {
1968 pub name: String,
1969 #[serde(default)]
1970 pub arguments: std::collections::HashMap<String, String>,
1971}
1972
1973#[derive(Debug, Clone, Serialize, Deserialize)]
1974pub struct GetPromptResult {
1975 #[serde(default, skip_serializing_if = "Option::is_none")]
1976 pub description: Option<String>,
1977 pub messages: Vec<PromptMessage>,
1978}
1979
1980impl GetPromptResult {
1981 pub fn user_message(text: impl Into<String>) -> Self {
1991 Self {
1992 description: None,
1993 messages: vec![PromptMessage {
1994 role: PromptRole::User,
1995 content: Content::Text {
1996 text: text.into(),
1997 annotations: None,
1998 },
1999 }],
2000 }
2001 }
2002
2003 pub fn user_message_with_description(
2016 text: impl Into<String>,
2017 description: impl Into<String>,
2018 ) -> Self {
2019 Self {
2020 description: Some(description.into()),
2021 messages: vec![PromptMessage {
2022 role: PromptRole::User,
2023 content: Content::Text {
2024 text: text.into(),
2025 annotations: None,
2026 },
2027 }],
2028 }
2029 }
2030
2031 pub fn assistant_message(text: impl Into<String>) -> Self {
2041 Self {
2042 description: None,
2043 messages: vec![PromptMessage {
2044 role: PromptRole::Assistant,
2045 content: Content::Text {
2046 text: text.into(),
2047 annotations: None,
2048 },
2049 }],
2050 }
2051 }
2052
2053 pub fn builder() -> GetPromptResultBuilder {
2068 GetPromptResultBuilder::new()
2069 }
2070
2071 pub fn first_message_text(&self) -> Option<&str> {
2085 self.messages.first().and_then(|m| m.content.as_text())
2086 }
2087}
2088
2089#[derive(Debug, Clone, Default)]
2091pub struct GetPromptResultBuilder {
2092 description: Option<String>,
2093 messages: Vec<PromptMessage>,
2094}
2095
2096impl GetPromptResultBuilder {
2097 pub fn new() -> Self {
2099 Self::default()
2100 }
2101
2102 pub fn description(mut self, description: impl Into<String>) -> Self {
2104 self.description = Some(description.into());
2105 self
2106 }
2107
2108 pub fn user(mut self, text: impl Into<String>) -> Self {
2110 self.messages.push(PromptMessage {
2111 role: PromptRole::User,
2112 content: Content::Text {
2113 text: text.into(),
2114 annotations: None,
2115 },
2116 });
2117 self
2118 }
2119
2120 pub fn assistant(mut self, text: impl Into<String>) -> Self {
2122 self.messages.push(PromptMessage {
2123 role: PromptRole::Assistant,
2124 content: Content::Text {
2125 text: text.into(),
2126 annotations: None,
2127 },
2128 });
2129 self
2130 }
2131
2132 pub fn build(self) -> GetPromptResult {
2134 GetPromptResult {
2135 description: self.description,
2136 messages: self.messages,
2137 }
2138 }
2139}
2140
2141#[derive(Debug, Clone, Serialize, Deserialize)]
2142pub struct PromptMessage {
2143 pub role: PromptRole,
2144 pub content: Content,
2145}
2146
2147#[derive(Debug, Clone, Serialize, Deserialize)]
2148#[serde(rename_all = "lowercase")]
2149pub enum PromptRole {
2150 User,
2151 Assistant,
2152}
2153
2154#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2160#[serde(rename_all = "snake_case")]
2161pub enum TaskStatus {
2162 Working,
2164 InputRequired,
2166 Completed,
2168 Failed,
2170 Cancelled,
2172}
2173
2174impl std::fmt::Display for TaskStatus {
2175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2176 match self {
2177 TaskStatus::Working => write!(f, "working"),
2178 TaskStatus::InputRequired => write!(f, "input_required"),
2179 TaskStatus::Completed => write!(f, "completed"),
2180 TaskStatus::Failed => write!(f, "failed"),
2181 TaskStatus::Cancelled => write!(f, "cancelled"),
2182 }
2183 }
2184}
2185
2186impl TaskStatus {
2187 pub fn is_terminal(&self) -> bool {
2189 matches!(
2190 self,
2191 TaskStatus::Completed | TaskStatus::Failed | TaskStatus::Cancelled
2192 )
2193 }
2194}
2195
2196#[derive(Debug, Clone, Serialize, Deserialize)]
2198#[serde(rename_all = "camelCase")]
2199pub struct TaskInfo {
2200 pub task_id: String,
2202 pub status: TaskStatus,
2204 pub created_at: String,
2206 #[serde(skip_serializing_if = "Option::is_none")]
2208 pub ttl: Option<u64>,
2209 #[serde(skip_serializing_if = "Option::is_none")]
2211 pub poll_interval: Option<u64>,
2212 #[serde(skip_serializing_if = "Option::is_none")]
2214 pub progress: Option<f64>,
2215 #[serde(skip_serializing_if = "Option::is_none")]
2217 pub message: Option<String>,
2218}
2219
2220#[derive(Debug, Clone, Deserialize)]
2222#[serde(rename_all = "camelCase")]
2223pub struct EnqueueTaskParams {
2224 pub tool_name: String,
2226 #[serde(default)]
2228 pub arguments: Value,
2229 #[serde(default)]
2231 pub ttl: Option<u64>,
2232}
2233
2234#[derive(Debug, Clone, Serialize)]
2236#[serde(rename_all = "camelCase")]
2237pub struct EnqueueTaskResult {
2238 pub task_id: String,
2240 pub status: TaskStatus,
2242 #[serde(skip_serializing_if = "Option::is_none")]
2244 pub poll_interval: Option<u64>,
2245}
2246
2247#[derive(Debug, Clone, Default, Deserialize)]
2249#[serde(rename_all = "camelCase")]
2250pub struct ListTasksParams {
2251 #[serde(default)]
2253 pub status: Option<TaskStatus>,
2254 #[serde(default)]
2256 pub cursor: Option<String>,
2257}
2258
2259#[derive(Debug, Clone, Serialize)]
2261#[serde(rename_all = "camelCase")]
2262pub struct ListTasksResult {
2263 pub tasks: Vec<TaskInfo>,
2265 #[serde(skip_serializing_if = "Option::is_none")]
2267 pub next_cursor: Option<String>,
2268}
2269
2270#[derive(Debug, Clone, Deserialize)]
2272#[serde(rename_all = "camelCase")]
2273pub struct GetTaskInfoParams {
2274 pub task_id: String,
2276}
2277
2278pub type GetTaskInfoResult = TaskInfo;
2280
2281#[derive(Debug, Clone, Deserialize)]
2283#[serde(rename_all = "camelCase")]
2284pub struct GetTaskResultParams {
2285 pub task_id: String,
2287}
2288
2289#[derive(Debug, Clone, Serialize)]
2291#[serde(rename_all = "camelCase")]
2292pub struct GetTaskResultResult {
2293 pub task_id: String,
2295 pub status: TaskStatus,
2297 #[serde(skip_serializing_if = "Option::is_none")]
2299 pub result: Option<CallToolResult>,
2300 #[serde(skip_serializing_if = "Option::is_none")]
2302 pub error: Option<String>,
2303}
2304
2305#[derive(Debug, Clone, Deserialize)]
2307#[serde(rename_all = "camelCase")]
2308pub struct CancelTaskParams {
2309 pub task_id: String,
2311 #[serde(default)]
2313 pub reason: Option<String>,
2314}
2315
2316#[derive(Debug, Clone, Serialize)]
2318#[serde(rename_all = "camelCase")]
2319pub struct CancelTaskResult {
2320 pub cancelled: bool,
2322 pub status: TaskStatus,
2324}
2325
2326#[derive(Debug, Clone, Serialize, Deserialize)]
2328#[serde(rename_all = "camelCase")]
2329pub struct TaskStatusChangedParams {
2330 pub task_id: String,
2332 pub status: TaskStatus,
2334 #[serde(skip_serializing_if = "Option::is_none")]
2336 pub message: Option<String>,
2337}
2338
2339#[derive(Debug, Clone, Serialize, Deserialize)]
2345#[serde(rename_all = "camelCase")]
2346pub struct ElicitFormParams {
2347 pub mode: ElicitMode,
2349 pub message: String,
2351 pub requested_schema: ElicitFormSchema,
2353 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2355 pub meta: Option<RequestMeta>,
2356}
2357
2358#[derive(Debug, Clone, Serialize, Deserialize)]
2360#[serde(rename_all = "camelCase")]
2361pub struct ElicitUrlParams {
2362 pub mode: ElicitMode,
2364 pub elicitation_id: String,
2366 pub message: String,
2368 pub url: String,
2370 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2372 pub meta: Option<RequestMeta>,
2373}
2374
2375#[derive(Debug, Clone, Serialize, Deserialize)]
2377#[serde(untagged)]
2378pub enum ElicitRequestParams {
2379 Form(ElicitFormParams),
2380 Url(ElicitUrlParams),
2381}
2382
2383#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2385#[serde(rename_all = "lowercase")]
2386pub enum ElicitMode {
2387 Form,
2389 Url,
2391}
2392
2393#[derive(Debug, Clone, Serialize, Deserialize)]
2397pub struct ElicitFormSchema {
2398 #[serde(rename = "type")]
2400 pub schema_type: String,
2401 pub properties: std::collections::HashMap<String, PrimitiveSchemaDefinition>,
2403 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2405 pub required: Vec<String>,
2406}
2407
2408impl ElicitFormSchema {
2409 pub fn new() -> Self {
2411 Self {
2412 schema_type: "object".to_string(),
2413 properties: std::collections::HashMap::new(),
2414 required: Vec::new(),
2415 }
2416 }
2417
2418 pub fn string_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2420 self.properties.insert(
2421 name.to_string(),
2422 PrimitiveSchemaDefinition::String(StringSchema {
2423 schema_type: "string".to_string(),
2424 description: description.map(|s| s.to_string()),
2425 format: None,
2426 min_length: None,
2427 max_length: None,
2428 default: None,
2429 }),
2430 );
2431 if required {
2432 self.required.push(name.to_string());
2433 }
2434 self
2435 }
2436
2437 pub fn string_field_with_default(
2439 mut self,
2440 name: &str,
2441 description: Option<&str>,
2442 required: bool,
2443 default: &str,
2444 ) -> Self {
2445 self.properties.insert(
2446 name.to_string(),
2447 PrimitiveSchemaDefinition::String(StringSchema {
2448 schema_type: "string".to_string(),
2449 description: description.map(|s| s.to_string()),
2450 format: None,
2451 min_length: None,
2452 max_length: None,
2453 default: Some(default.to_string()),
2454 }),
2455 );
2456 if required {
2457 self.required.push(name.to_string());
2458 }
2459 self
2460 }
2461
2462 pub fn integer_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2464 self.properties.insert(
2465 name.to_string(),
2466 PrimitiveSchemaDefinition::Integer(IntegerSchema {
2467 schema_type: "integer".to_string(),
2468 description: description.map(|s| s.to_string()),
2469 minimum: None,
2470 maximum: None,
2471 default: None,
2472 }),
2473 );
2474 if required {
2475 self.required.push(name.to_string());
2476 }
2477 self
2478 }
2479
2480 pub fn integer_field_with_default(
2482 mut self,
2483 name: &str,
2484 description: Option<&str>,
2485 required: bool,
2486 default: i64,
2487 ) -> Self {
2488 self.properties.insert(
2489 name.to_string(),
2490 PrimitiveSchemaDefinition::Integer(IntegerSchema {
2491 schema_type: "integer".to_string(),
2492 description: description.map(|s| s.to_string()),
2493 minimum: None,
2494 maximum: None,
2495 default: Some(default),
2496 }),
2497 );
2498 if required {
2499 self.required.push(name.to_string());
2500 }
2501 self
2502 }
2503
2504 pub fn number_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2506 self.properties.insert(
2507 name.to_string(),
2508 PrimitiveSchemaDefinition::Number(NumberSchema {
2509 schema_type: "number".to_string(),
2510 description: description.map(|s| s.to_string()),
2511 minimum: None,
2512 maximum: None,
2513 default: None,
2514 }),
2515 );
2516 if required {
2517 self.required.push(name.to_string());
2518 }
2519 self
2520 }
2521
2522 pub fn number_field_with_default(
2524 mut self,
2525 name: &str,
2526 description: Option<&str>,
2527 required: bool,
2528 default: f64,
2529 ) -> Self {
2530 self.properties.insert(
2531 name.to_string(),
2532 PrimitiveSchemaDefinition::Number(NumberSchema {
2533 schema_type: "number".to_string(),
2534 description: description.map(|s| s.to_string()),
2535 minimum: None,
2536 maximum: None,
2537 default: Some(default),
2538 }),
2539 );
2540 if required {
2541 self.required.push(name.to_string());
2542 }
2543 self
2544 }
2545
2546 pub fn boolean_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
2548 self.properties.insert(
2549 name.to_string(),
2550 PrimitiveSchemaDefinition::Boolean(BooleanSchema {
2551 schema_type: "boolean".to_string(),
2552 description: description.map(|s| s.to_string()),
2553 default: None,
2554 }),
2555 );
2556 if required {
2557 self.required.push(name.to_string());
2558 }
2559 self
2560 }
2561
2562 pub fn boolean_field_with_default(
2564 mut self,
2565 name: &str,
2566 description: Option<&str>,
2567 required: bool,
2568 default: bool,
2569 ) -> Self {
2570 self.properties.insert(
2571 name.to_string(),
2572 PrimitiveSchemaDefinition::Boolean(BooleanSchema {
2573 schema_type: "boolean".to_string(),
2574 description: description.map(|s| s.to_string()),
2575 default: Some(default),
2576 }),
2577 );
2578 if required {
2579 self.required.push(name.to_string());
2580 }
2581 self
2582 }
2583
2584 pub fn enum_field(
2586 mut self,
2587 name: &str,
2588 description: Option<&str>,
2589 options: Vec<String>,
2590 required: bool,
2591 ) -> Self {
2592 self.properties.insert(
2593 name.to_string(),
2594 PrimitiveSchemaDefinition::SingleSelectEnum(SingleSelectEnumSchema {
2595 schema_type: "string".to_string(),
2596 description: description.map(|s| s.to_string()),
2597 enum_values: options,
2598 default: None,
2599 }),
2600 );
2601 if required {
2602 self.required.push(name.to_string());
2603 }
2604 self
2605 }
2606
2607 pub fn enum_field_with_default(
2609 mut self,
2610 name: &str,
2611 description: Option<&str>,
2612 required: bool,
2613 options: &[&str],
2614 default: &str,
2615 ) -> Self {
2616 self.properties.insert(
2617 name.to_string(),
2618 PrimitiveSchemaDefinition::SingleSelectEnum(SingleSelectEnumSchema {
2619 schema_type: "string".to_string(),
2620 description: description.map(|s| s.to_string()),
2621 enum_values: options.iter().map(|s| s.to_string()).collect(),
2622 default: Some(default.to_string()),
2623 }),
2624 );
2625 if required {
2626 self.required.push(name.to_string());
2627 }
2628 self
2629 }
2630
2631 pub fn raw_field(mut self, name: &str, schema: serde_json::Value, required: bool) -> Self {
2635 self.properties
2636 .insert(name.to_string(), PrimitiveSchemaDefinition::Raw(schema));
2637 if required {
2638 self.required.push(name.to_string());
2639 }
2640 self
2641 }
2642}
2643
2644impl Default for ElicitFormSchema {
2645 fn default() -> Self {
2646 Self::new()
2647 }
2648}
2649
2650#[derive(Debug, Clone, Serialize, Deserialize)]
2652#[serde(untagged)]
2653pub enum PrimitiveSchemaDefinition {
2654 String(StringSchema),
2656 Integer(IntegerSchema),
2658 Number(NumberSchema),
2660 Boolean(BooleanSchema),
2662 SingleSelectEnum(SingleSelectEnumSchema),
2664 MultiSelectEnum(MultiSelectEnumSchema),
2666 Raw(serde_json::Value),
2668}
2669
2670#[derive(Debug, Clone, Serialize, Deserialize)]
2672#[serde(rename_all = "camelCase")]
2673pub struct StringSchema {
2674 #[serde(rename = "type")]
2675 pub schema_type: String,
2676 #[serde(skip_serializing_if = "Option::is_none")]
2677 pub description: Option<String>,
2678 #[serde(skip_serializing_if = "Option::is_none")]
2679 pub format: Option<String>,
2680 #[serde(skip_serializing_if = "Option::is_none")]
2681 pub min_length: Option<u64>,
2682 #[serde(skip_serializing_if = "Option::is_none")]
2683 pub max_length: Option<u64>,
2684 #[serde(skip_serializing_if = "Option::is_none")]
2686 pub default: Option<String>,
2687}
2688
2689#[derive(Debug, Clone, Serialize, Deserialize)]
2691#[serde(rename_all = "camelCase")]
2692pub struct IntegerSchema {
2693 #[serde(rename = "type")]
2694 pub schema_type: String,
2695 #[serde(skip_serializing_if = "Option::is_none")]
2696 pub description: Option<String>,
2697 #[serde(skip_serializing_if = "Option::is_none")]
2698 pub minimum: Option<i64>,
2699 #[serde(skip_serializing_if = "Option::is_none")]
2700 pub maximum: Option<i64>,
2701 #[serde(skip_serializing_if = "Option::is_none")]
2703 pub default: Option<i64>,
2704}
2705
2706#[derive(Debug, Clone, Serialize, Deserialize)]
2708#[serde(rename_all = "camelCase")]
2709pub struct NumberSchema {
2710 #[serde(rename = "type")]
2711 pub schema_type: String,
2712 #[serde(skip_serializing_if = "Option::is_none")]
2713 pub description: Option<String>,
2714 #[serde(skip_serializing_if = "Option::is_none")]
2715 pub minimum: Option<f64>,
2716 #[serde(skip_serializing_if = "Option::is_none")]
2717 pub maximum: Option<f64>,
2718 #[serde(skip_serializing_if = "Option::is_none")]
2720 pub default: Option<f64>,
2721}
2722
2723#[derive(Debug, Clone, Serialize, Deserialize)]
2725#[serde(rename_all = "camelCase")]
2726pub struct BooleanSchema {
2727 #[serde(rename = "type")]
2728 pub schema_type: String,
2729 #[serde(skip_serializing_if = "Option::is_none")]
2730 pub description: Option<String>,
2731 #[serde(skip_serializing_if = "Option::is_none")]
2733 pub default: Option<bool>,
2734}
2735
2736#[derive(Debug, Clone, Serialize, Deserialize)]
2738#[serde(rename_all = "camelCase")]
2739pub struct SingleSelectEnumSchema {
2740 #[serde(rename = "type")]
2741 pub schema_type: String,
2742 #[serde(skip_serializing_if = "Option::is_none")]
2743 pub description: Option<String>,
2744 #[serde(rename = "enum")]
2745 pub enum_values: Vec<String>,
2746 #[serde(skip_serializing_if = "Option::is_none")]
2748 pub default: Option<String>,
2749}
2750
2751#[derive(Debug, Clone, Serialize, Deserialize)]
2753#[serde(rename_all = "camelCase")]
2754pub struct MultiSelectEnumSchema {
2755 #[serde(rename = "type")]
2756 pub schema_type: String,
2757 #[serde(skip_serializing_if = "Option::is_none")]
2758 pub description: Option<String>,
2759 pub items: MultiSelectEnumItems,
2760 #[serde(skip_serializing_if = "Option::is_none")]
2761 pub unique_items: Option<bool>,
2762}
2763
2764#[derive(Debug, Clone, Serialize, Deserialize)]
2766pub struct MultiSelectEnumItems {
2767 #[serde(rename = "type")]
2768 pub schema_type: String,
2769 #[serde(rename = "enum")]
2770 pub enum_values: Vec<String>,
2771}
2772
2773#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2775#[serde(rename_all = "lowercase")]
2776pub enum ElicitAction {
2777 Accept,
2779 Decline,
2781 Cancel,
2783}
2784
2785#[derive(Debug, Clone, Serialize, Deserialize)]
2787pub struct ElicitResult {
2788 pub action: ElicitAction,
2790 #[serde(default, skip_serializing_if = "Option::is_none")]
2792 pub content: Option<std::collections::HashMap<String, ElicitFieldValue>>,
2793}
2794
2795impl ElicitResult {
2796 pub fn accept(content: std::collections::HashMap<String, ElicitFieldValue>) -> Self {
2798 Self {
2799 action: ElicitAction::Accept,
2800 content: Some(content),
2801 }
2802 }
2803
2804 pub fn decline() -> Self {
2806 Self {
2807 action: ElicitAction::Decline,
2808 content: None,
2809 }
2810 }
2811
2812 pub fn cancel() -> Self {
2814 Self {
2815 action: ElicitAction::Cancel,
2816 content: None,
2817 }
2818 }
2819}
2820
2821#[derive(Debug, Clone, Serialize, Deserialize)]
2823#[serde(untagged)]
2824pub enum ElicitFieldValue {
2825 String(String),
2826 Number(f64),
2827 Integer(i64),
2828 Boolean(bool),
2829 StringArray(Vec<String>),
2830}
2831
2832#[derive(Debug, Clone, Serialize, Deserialize)]
2834#[serde(rename_all = "camelCase")]
2835pub struct ElicitationCompleteParams {
2836 pub elicitation_id: String,
2838}
2839
2840#[derive(Debug, Clone, Default, Serialize)]
2845pub struct EmptyResult {}
2846
2847impl McpRequest {
2852 pub fn from_jsonrpc(req: &JsonRpcRequest) -> Result<Self, crate::error::Error> {
2854 let params = req
2855 .params
2856 .clone()
2857 .unwrap_or(Value::Object(Default::default()));
2858
2859 match req.method.as_str() {
2860 "initialize" => {
2861 let p: InitializeParams = serde_json::from_value(params)?;
2862 Ok(McpRequest::Initialize(p))
2863 }
2864 "tools/list" => {
2865 let p: ListToolsParams = serde_json::from_value(params).unwrap_or_default();
2866 Ok(McpRequest::ListTools(p))
2867 }
2868 "tools/call" => {
2869 let p: CallToolParams = serde_json::from_value(params)?;
2870 Ok(McpRequest::CallTool(p))
2871 }
2872 "resources/list" => {
2873 let p: ListResourcesParams = serde_json::from_value(params).unwrap_or_default();
2874 Ok(McpRequest::ListResources(p))
2875 }
2876 "resources/templates/list" => {
2877 let p: ListResourceTemplatesParams =
2878 serde_json::from_value(params).unwrap_or_default();
2879 Ok(McpRequest::ListResourceTemplates(p))
2880 }
2881 "resources/read" => {
2882 let p: ReadResourceParams = serde_json::from_value(params)?;
2883 Ok(McpRequest::ReadResource(p))
2884 }
2885 "resources/subscribe" => {
2886 let p: SubscribeResourceParams = serde_json::from_value(params)?;
2887 Ok(McpRequest::SubscribeResource(p))
2888 }
2889 "resources/unsubscribe" => {
2890 let p: UnsubscribeResourceParams = serde_json::from_value(params)?;
2891 Ok(McpRequest::UnsubscribeResource(p))
2892 }
2893 "prompts/list" => {
2894 let p: ListPromptsParams = serde_json::from_value(params).unwrap_or_default();
2895 Ok(McpRequest::ListPrompts(p))
2896 }
2897 "prompts/get" => {
2898 let p: GetPromptParams = serde_json::from_value(params)?;
2899 Ok(McpRequest::GetPrompt(p))
2900 }
2901 "tasks/enqueue" => {
2902 let p: EnqueueTaskParams = serde_json::from_value(params)?;
2903 Ok(McpRequest::EnqueueTask(p))
2904 }
2905 "tasks/list" => {
2906 let p: ListTasksParams = serde_json::from_value(params).unwrap_or_default();
2907 Ok(McpRequest::ListTasks(p))
2908 }
2909 "tasks/get" => {
2910 let p: GetTaskInfoParams = serde_json::from_value(params)?;
2911 Ok(McpRequest::GetTaskInfo(p))
2912 }
2913 "tasks/result" => {
2914 let p: GetTaskResultParams = serde_json::from_value(params)?;
2915 Ok(McpRequest::GetTaskResult(p))
2916 }
2917 "tasks/cancel" => {
2918 let p: CancelTaskParams = serde_json::from_value(params)?;
2919 Ok(McpRequest::CancelTask(p))
2920 }
2921 "ping" => Ok(McpRequest::Ping),
2922 "logging/setLevel" => {
2923 let p: SetLogLevelParams = serde_json::from_value(params)?;
2924 Ok(McpRequest::SetLoggingLevel(p))
2925 }
2926 "completion/complete" => {
2927 let p: CompleteParams = serde_json::from_value(params)?;
2928 Ok(McpRequest::Complete(p))
2929 }
2930 method => Ok(McpRequest::Unknown {
2931 method: method.to_string(),
2932 params: req.params.clone(),
2933 }),
2934 }
2935 }
2936}
2937
2938impl McpNotification {
2939 pub fn from_jsonrpc(notif: &JsonRpcNotification) -> Result<Self, crate::error::Error> {
2941 let params = notif
2942 .params
2943 .clone()
2944 .unwrap_or(Value::Object(Default::default()));
2945
2946 match notif.method.as_str() {
2947 notifications::INITIALIZED => Ok(McpNotification::Initialized),
2948 notifications::CANCELLED => {
2949 let p: CancelledParams = serde_json::from_value(params)?;
2950 Ok(McpNotification::Cancelled(p))
2951 }
2952 notifications::PROGRESS => {
2953 let p: ProgressParams = serde_json::from_value(params)?;
2954 Ok(McpNotification::Progress(p))
2955 }
2956 notifications::ROOTS_LIST_CHANGED => Ok(McpNotification::RootsListChanged),
2957 method => Ok(McpNotification::Unknown {
2958 method: method.to_string(),
2959 params: notif.params.clone(),
2960 }),
2961 }
2962 }
2963}
2964
2965#[cfg(test)]
2966mod tests {
2967 use super::*;
2968
2969 #[test]
2970 fn test_elicit_form_schema_builder() {
2971 let schema = ElicitFormSchema::new()
2972 .string_field("name", Some("Your name"), true)
2973 .number_field("age", Some("Your age"), false)
2974 .boolean_field("agree", Some("Do you agree?"), true)
2975 .enum_field(
2976 "color",
2977 Some("Favorite color"),
2978 vec!["red".to_string(), "green".to_string(), "blue".to_string()],
2979 false,
2980 );
2981
2982 assert_eq!(schema.schema_type, "object");
2983 assert_eq!(schema.properties.len(), 4);
2984 assert_eq!(schema.required.len(), 2);
2985 assert!(schema.required.contains(&"name".to_string()));
2986 assert!(schema.required.contains(&"agree".to_string()));
2987 }
2988
2989 #[test]
2990 fn test_elicit_form_schema_serialization() {
2991 let schema = ElicitFormSchema::new().string_field("username", Some("Enter username"), true);
2992
2993 let json = serde_json::to_value(&schema).unwrap();
2994 assert_eq!(json["type"], "object");
2995 assert!(json["properties"]["username"]["type"] == "string");
2996 assert!(
2997 json["required"]
2998 .as_array()
2999 .unwrap()
3000 .contains(&serde_json::json!("username"))
3001 );
3002 }
3003
3004 #[test]
3005 fn test_elicit_result_accept() {
3006 let mut content = std::collections::HashMap::new();
3007 content.insert(
3008 "name".to_string(),
3009 ElicitFieldValue::String("Alice".to_string()),
3010 );
3011 content.insert("age".to_string(), ElicitFieldValue::Integer(30));
3012
3013 let result = ElicitResult::accept(content);
3014 assert_eq!(result.action, ElicitAction::Accept);
3015 assert!(result.content.is_some());
3016 }
3017
3018 #[test]
3019 fn test_elicit_result_decline() {
3020 let result = ElicitResult::decline();
3021 assert_eq!(result.action, ElicitAction::Decline);
3022 assert!(result.content.is_none());
3023 }
3024
3025 #[test]
3026 fn test_elicit_result_cancel() {
3027 let result = ElicitResult::cancel();
3028 assert_eq!(result.action, ElicitAction::Cancel);
3029 assert!(result.content.is_none());
3030 }
3031
3032 #[test]
3033 fn test_elicit_mode_serialization() {
3034 assert_eq!(
3035 serde_json::to_string(&ElicitMode::Form).unwrap(),
3036 "\"form\""
3037 );
3038 assert_eq!(serde_json::to_string(&ElicitMode::Url).unwrap(), "\"url\"");
3039 }
3040
3041 #[test]
3042 fn test_elicit_action_serialization() {
3043 assert_eq!(
3044 serde_json::to_string(&ElicitAction::Accept).unwrap(),
3045 "\"accept\""
3046 );
3047 assert_eq!(
3048 serde_json::to_string(&ElicitAction::Decline).unwrap(),
3049 "\"decline\""
3050 );
3051 assert_eq!(
3052 serde_json::to_string(&ElicitAction::Cancel).unwrap(),
3053 "\"cancel\""
3054 );
3055 }
3056
3057 #[test]
3058 fn test_elicitation_capability() {
3059 let cap = ElicitationCapability {
3060 form: Some(ElicitationFormCapability {}),
3061 url: None,
3062 };
3063
3064 let json = serde_json::to_value(&cap).unwrap();
3065 assert!(json["form"].is_object());
3066 assert!(json.get("url").is_none());
3067 }
3068
3069 #[test]
3070 fn test_client_capabilities_with_elicitation() {
3071 let caps = ClientCapabilities {
3072 roots: None,
3073 sampling: None,
3074 elicitation: Some(ElicitationCapability {
3075 form: Some(ElicitationFormCapability {}),
3076 url: Some(ElicitationUrlCapability {}),
3077 }),
3078 };
3079
3080 let json = serde_json::to_value(&caps).unwrap();
3081 assert!(json["elicitation"]["form"].is_object());
3082 assert!(json["elicitation"]["url"].is_object());
3083 }
3084
3085 #[test]
3086 fn test_elicit_url_params() {
3087 let params = ElicitUrlParams {
3088 mode: ElicitMode::Url,
3089 elicitation_id: "abc123".to_string(),
3090 message: "Please authorize".to_string(),
3091 url: "https://example.com/auth".to_string(),
3092 meta: None,
3093 };
3094
3095 let json = serde_json::to_value(¶ms).unwrap();
3096 assert_eq!(json["mode"], "url");
3097 assert_eq!(json["elicitationId"], "abc123");
3098 assert_eq!(json["message"], "Please authorize");
3099 assert_eq!(json["url"], "https://example.com/auth");
3100 }
3101
3102 #[test]
3103 fn test_elicitation_complete_params() {
3104 let params = ElicitationCompleteParams {
3105 elicitation_id: "xyz789".to_string(),
3106 };
3107
3108 let json = serde_json::to_value(¶ms).unwrap();
3109 assert_eq!(json["elicitationId"], "xyz789");
3110 }
3111
3112 #[test]
3113 fn test_root_new() {
3114 let root = Root::new("file:///home/user/project");
3115 assert_eq!(root.uri, "file:///home/user/project");
3116 assert!(root.name.is_none());
3117 }
3118
3119 #[test]
3120 fn test_root_with_name() {
3121 let root = Root::with_name("file:///home/user/project", "My Project");
3122 assert_eq!(root.uri, "file:///home/user/project");
3123 assert_eq!(root.name.as_deref(), Some("My Project"));
3124 }
3125
3126 #[test]
3127 fn test_root_serialization() {
3128 let root = Root::with_name("file:///workspace", "Workspace");
3129 let json = serde_json::to_value(&root).unwrap();
3130 assert_eq!(json["uri"], "file:///workspace");
3131 assert_eq!(json["name"], "Workspace");
3132 }
3133
3134 #[test]
3135 fn test_root_serialization_without_name() {
3136 let root = Root::new("file:///workspace");
3137 let json = serde_json::to_value(&root).unwrap();
3138 assert_eq!(json["uri"], "file:///workspace");
3139 assert!(json.get("name").is_none());
3140 }
3141
3142 #[test]
3143 fn test_root_deserialization() {
3144 let json = serde_json::json!({
3145 "uri": "file:///home/user",
3146 "name": "Home"
3147 });
3148 let root: Root = serde_json::from_value(json).unwrap();
3149 assert_eq!(root.uri, "file:///home/user");
3150 assert_eq!(root.name.as_deref(), Some("Home"));
3151 }
3152
3153 #[test]
3154 fn test_list_roots_result() {
3155 let result = ListRootsResult {
3156 roots: vec![
3157 Root::new("file:///project1"),
3158 Root::with_name("file:///project2", "Project 2"),
3159 ],
3160 };
3161
3162 let json = serde_json::to_value(&result).unwrap();
3163 let roots = json["roots"].as_array().unwrap();
3164 assert_eq!(roots.len(), 2);
3165 assert_eq!(roots[0]["uri"], "file:///project1");
3166 assert_eq!(roots[1]["name"], "Project 2");
3167 }
3168
3169 #[test]
3170 fn test_roots_capability_serialization() {
3171 let cap = RootsCapability { list_changed: true };
3172 let json = serde_json::to_value(&cap).unwrap();
3173 assert_eq!(json["listChanged"], true);
3174 }
3175
3176 #[test]
3177 fn test_client_capabilities_with_roots() {
3178 let caps = ClientCapabilities {
3179 roots: Some(RootsCapability { list_changed: true }),
3180 sampling: None,
3181 elicitation: None,
3182 };
3183
3184 let json = serde_json::to_value(&caps).unwrap();
3185 assert_eq!(json["roots"]["listChanged"], true);
3186 }
3187
3188 #[test]
3189 fn test_roots_list_changed_notification_parsing() {
3190 let notif = JsonRpcNotification {
3191 jsonrpc: "2.0".to_string(),
3192 method: notifications::ROOTS_LIST_CHANGED.to_string(),
3193 params: None,
3194 };
3195
3196 let mcp_notif = McpNotification::from_jsonrpc(¬if).unwrap();
3197 assert!(matches!(mcp_notif, McpNotification::RootsListChanged));
3198 }
3199
3200 #[test]
3205 fn test_prompt_reference() {
3206 let ref_ = PromptReference::new("my-prompt");
3207 assert_eq!(ref_.ref_type, "ref/prompt");
3208 assert_eq!(ref_.name, "my-prompt");
3209
3210 let json = serde_json::to_value(&ref_).unwrap();
3211 assert_eq!(json["type"], "ref/prompt");
3212 assert_eq!(json["name"], "my-prompt");
3213 }
3214
3215 #[test]
3216 fn test_resource_reference() {
3217 let ref_ = ResourceReference::new("file:///path/to/file");
3218 assert_eq!(ref_.ref_type, "ref/resource");
3219 assert_eq!(ref_.uri, "file:///path/to/file");
3220
3221 let json = serde_json::to_value(&ref_).unwrap();
3222 assert_eq!(json["type"], "ref/resource");
3223 assert_eq!(json["uri"], "file:///path/to/file");
3224 }
3225
3226 #[test]
3227 fn test_completion_reference_prompt() {
3228 let ref_ = CompletionReference::prompt("test-prompt");
3229 let json = serde_json::to_value(&ref_).unwrap();
3230 assert_eq!(json["type"], "ref/prompt");
3231 assert_eq!(json["name"], "test-prompt");
3232 }
3233
3234 #[test]
3235 fn test_completion_reference_resource() {
3236 let ref_ = CompletionReference::resource("file:///test");
3237 let json = serde_json::to_value(&ref_).unwrap();
3238 assert_eq!(json["type"], "ref/resource");
3239 assert_eq!(json["uri"], "file:///test");
3240 }
3241
3242 #[test]
3243 fn test_completion_argument() {
3244 let arg = CompletionArgument::new("query", "SELECT * FROM");
3245 assert_eq!(arg.name, "query");
3246 assert_eq!(arg.value, "SELECT * FROM");
3247 }
3248
3249 #[test]
3250 fn test_complete_params_serialization() {
3251 let params = CompleteParams {
3252 reference: CompletionReference::prompt("sql-prompt"),
3253 argument: CompletionArgument::new("query", "SEL"),
3254 };
3255
3256 let json = serde_json::to_value(¶ms).unwrap();
3257 assert_eq!(json["ref"]["type"], "ref/prompt");
3258 assert_eq!(json["ref"]["name"], "sql-prompt");
3259 assert_eq!(json["argument"]["name"], "query");
3260 assert_eq!(json["argument"]["value"], "SEL");
3261 }
3262
3263 #[test]
3264 fn test_completion_new() {
3265 let completion = Completion::new(vec!["SELECT".to_string(), "SET".to_string()]);
3266 assert_eq!(completion.values.len(), 2);
3267 assert!(completion.total.is_none());
3268 assert!(completion.has_more.is_none());
3269 }
3270
3271 #[test]
3272 fn test_completion_with_pagination() {
3273 let completion =
3274 Completion::with_pagination(vec!["a".to_string(), "b".to_string()], 100, true);
3275 assert_eq!(completion.values.len(), 2);
3276 assert_eq!(completion.total, Some(100));
3277 assert_eq!(completion.has_more, Some(true));
3278 }
3279
3280 #[test]
3281 fn test_complete_result() {
3282 let result = CompleteResult::new(vec!["option1".to_string(), "option2".to_string()]);
3283 let json = serde_json::to_value(&result).unwrap();
3284 assert!(json["completion"]["values"].is_array());
3285 assert_eq!(json["completion"]["values"][0], "option1");
3286 }
3287
3288 #[test]
3293 fn test_model_hint() {
3294 let hint = ModelHint::new("claude-3-opus");
3295 assert_eq!(hint.name, "claude-3-opus");
3296 }
3297
3298 #[test]
3299 fn test_model_preferences_builder() {
3300 let prefs = ModelPreferences::new()
3301 .speed(0.8)
3302 .intelligence(0.9)
3303 .cost(0.5)
3304 .hint("gpt-4")
3305 .hint("claude-3");
3306
3307 assert_eq!(prefs.speed_priority, Some(0.8));
3308 assert_eq!(prefs.intelligence_priority, Some(0.9));
3309 assert_eq!(prefs.cost_priority, Some(0.5));
3310 assert_eq!(prefs.hints.len(), 2);
3311 }
3312
3313 #[test]
3314 fn test_model_preferences_clamping() {
3315 let prefs = ModelPreferences::new().speed(1.5).cost(-0.5);
3316
3317 assert_eq!(prefs.speed_priority, Some(1.0)); assert_eq!(prefs.cost_priority, Some(0.0)); }
3320
3321 #[test]
3322 fn test_include_context_serialization() {
3323 assert_eq!(
3324 serde_json::to_string(&IncludeContext::AllServers).unwrap(),
3325 "\"allServers\""
3326 );
3327 assert_eq!(
3328 serde_json::to_string(&IncludeContext::ThisServer).unwrap(),
3329 "\"thisServer\""
3330 );
3331 assert_eq!(
3332 serde_json::to_string(&IncludeContext::None).unwrap(),
3333 "\"none\""
3334 );
3335 }
3336
3337 #[test]
3338 fn test_sampling_message_user() {
3339 let msg = SamplingMessage::user("Hello, how are you?");
3340 assert_eq!(msg.role, ContentRole::User);
3341 assert!(
3342 matches!(msg.content, SamplingContent::Text { text } if text == "Hello, how are you?")
3343 );
3344 }
3345
3346 #[test]
3347 fn test_sampling_message_assistant() {
3348 let msg = SamplingMessage::assistant("I'm doing well!");
3349 assert_eq!(msg.role, ContentRole::Assistant);
3350 }
3351
3352 #[test]
3353 fn test_sampling_content_text_serialization() {
3354 let content = SamplingContent::Text {
3355 text: "Hello".to_string(),
3356 };
3357 let json = serde_json::to_value(&content).unwrap();
3358 assert_eq!(json["type"], "text");
3359 assert_eq!(json["text"], "Hello");
3360 }
3361
3362 #[test]
3363 fn test_sampling_content_image_serialization() {
3364 let content = SamplingContent::Image {
3365 data: "base64data".to_string(),
3366 mime_type: "image/png".to_string(),
3367 };
3368 let json = serde_json::to_value(&content).unwrap();
3369 assert_eq!(json["type"], "image");
3370 assert_eq!(json["data"], "base64data");
3371 assert_eq!(json["mimeType"], "image/png");
3372 }
3373
3374 #[test]
3375 fn test_create_message_params() {
3376 let params = CreateMessageParams::new(
3377 vec![
3378 SamplingMessage::user("What is 2+2?"),
3379 SamplingMessage::assistant("4"),
3380 SamplingMessage::user("And 3+3?"),
3381 ],
3382 100,
3383 )
3384 .system_prompt("You are a math tutor")
3385 .temperature(0.7)
3386 .stop_sequence("END")
3387 .include_context(IncludeContext::ThisServer);
3388
3389 assert_eq!(params.messages.len(), 3);
3390 assert_eq!(params.max_tokens, 100);
3391 assert_eq!(
3392 params.system_prompt.as_deref(),
3393 Some("You are a math tutor")
3394 );
3395 assert_eq!(params.temperature, Some(0.7));
3396 assert_eq!(params.stop_sequences.len(), 1);
3397 assert_eq!(params.include_context, Some(IncludeContext::ThisServer));
3398 }
3399
3400 #[test]
3401 fn test_create_message_params_serialization() {
3402 let params = CreateMessageParams::new(vec![SamplingMessage::user("Hello")], 50);
3403
3404 let json = serde_json::to_value(¶ms).unwrap();
3405 assert!(json["messages"].is_array());
3406 assert_eq!(json["maxTokens"], 50);
3407 }
3408
3409 #[test]
3410 fn test_create_message_result_deserialization() {
3411 let json = serde_json::json!({
3412 "content": {
3413 "type": "text",
3414 "text": "The answer is 42"
3415 },
3416 "model": "claude-3-opus",
3417 "role": "assistant",
3418 "stopReason": "end_turn"
3419 });
3420
3421 let result: CreateMessageResult = serde_json::from_value(json).unwrap();
3422 assert_eq!(result.model, "claude-3-opus");
3423 assert_eq!(result.role, ContentRole::Assistant);
3424 assert_eq!(result.stop_reason.as_deref(), Some("end_turn"));
3425 }
3426
3427 #[test]
3428 fn test_completions_capability_serialization() {
3429 let cap = CompletionsCapability {};
3430 let json = serde_json::to_value(&cap).unwrap();
3431 assert!(json.is_object());
3432 }
3433
3434 #[test]
3435 fn test_server_capabilities_with_completions() {
3436 let caps = ServerCapabilities {
3437 completions: Some(CompletionsCapability {}),
3438 ..Default::default()
3439 };
3440
3441 let json = serde_json::to_value(&caps).unwrap();
3442 assert!(json["completions"].is_object());
3443 }
3444
3445 #[test]
3446 fn test_content_resource_link_serialization() {
3447 let content = Content::ResourceLink {
3448 uri: "file:///test.txt".to_string(),
3449 name: Some("test.txt".to_string()),
3450 description: Some("A test file".to_string()),
3451 mime_type: Some("text/plain".to_string()),
3452 annotations: None,
3453 };
3454 let json = serde_json::to_value(&content).unwrap();
3455 assert_eq!(json["type"], "resource_link");
3456 assert_eq!(json["uri"], "file:///test.txt");
3457 assert_eq!(json["name"], "test.txt");
3458 assert_eq!(json["description"], "A test file");
3459 assert_eq!(json["mimeType"], "text/plain");
3460 }
3461
3462 #[test]
3463 fn test_call_tool_result_resource_link() {
3464 let result = CallToolResult::resource_link("file:///output.json");
3465 assert_eq!(result.content.len(), 1);
3466 assert!(!result.is_error);
3467 match &result.content[0] {
3468 Content::ResourceLink { uri, .. } => assert_eq!(uri, "file:///output.json"),
3469 _ => panic!("Expected ResourceLink content"),
3470 }
3471 }
3472
3473 #[test]
3474 fn test_call_tool_result_image() {
3475 let result = CallToolResult::image("base64data", "image/png");
3476 assert_eq!(result.content.len(), 1);
3477 match &result.content[0] {
3478 Content::Image {
3479 data, mime_type, ..
3480 } => {
3481 assert_eq!(data, "base64data");
3482 assert_eq!(mime_type, "image/png");
3483 }
3484 _ => panic!("Expected Image content"),
3485 }
3486 }
3487
3488 #[test]
3489 fn test_call_tool_result_audio() {
3490 let result = CallToolResult::audio("audiodata", "audio/wav");
3491 assert_eq!(result.content.len(), 1);
3492 match &result.content[0] {
3493 Content::Audio {
3494 data, mime_type, ..
3495 } => {
3496 assert_eq!(data, "audiodata");
3497 assert_eq!(mime_type, "audio/wav");
3498 }
3499 _ => panic!("Expected Audio content"),
3500 }
3501 }
3502
3503 #[test]
3504 fn test_sampling_tool_serialization() {
3505 let tool = SamplingTool {
3506 name: "get_weather".to_string(),
3507 description: Some("Get current weather".to_string()),
3508 input_schema: serde_json::json!({
3509 "type": "object",
3510 "properties": {
3511 "location": { "type": "string" }
3512 }
3513 }),
3514 };
3515 let json = serde_json::to_value(&tool).unwrap();
3516 assert_eq!(json["name"], "get_weather");
3517 assert_eq!(json["description"], "Get current weather");
3518 assert!(json["inputSchema"]["properties"]["location"].is_object());
3519 }
3520
3521 #[test]
3522 fn test_tool_choice_modes() {
3523 let auto = ToolChoice::auto();
3524 assert_eq!(auto.mode, "auto");
3525
3526 let required = ToolChoice::required();
3527 assert_eq!(required.mode, "required");
3528
3529 let none = ToolChoice::none();
3530 assert_eq!(none.mode, "none");
3531
3532 let json = serde_json::to_value(&auto).unwrap();
3534 assert_eq!(json["type"], "auto");
3535 }
3536
3537 #[test]
3538 fn test_sampling_content_tool_use() {
3539 let content = SamplingContent::ToolUse {
3540 id: "tool_123".to_string(),
3541 name: "get_weather".to_string(),
3542 input: serde_json::json!({"location": "San Francisco"}),
3543 };
3544 let json = serde_json::to_value(&content).unwrap();
3545 assert_eq!(json["type"], "tool_use");
3546 assert_eq!(json["id"], "tool_123");
3547 assert_eq!(json["name"], "get_weather");
3548 assert_eq!(json["input"]["location"], "San Francisco");
3549 }
3550
3551 #[test]
3552 fn test_sampling_content_tool_result() {
3553 let content = SamplingContent::ToolResult {
3554 tool_use_id: "tool_123".to_string(),
3555 content: vec![SamplingContent::Text {
3556 text: "72F, sunny".to_string(),
3557 }],
3558 is_error: None,
3559 };
3560 let json = serde_json::to_value(&content).unwrap();
3561 assert_eq!(json["type"], "tool_result");
3562 assert_eq!(json["tool_use_id"], "tool_123");
3563 assert_eq!(json["content"][0]["type"], "text");
3564 }
3565
3566 #[test]
3567 fn test_sampling_content_or_array_single() {
3568 let json = serde_json::json!({
3569 "type": "text",
3570 "text": "Hello"
3571 });
3572 let content: SamplingContentOrArray = serde_json::from_value(json).unwrap();
3573 let items = content.items();
3574 assert_eq!(items.len(), 1);
3575 match items[0] {
3576 SamplingContent::Text { text } => assert_eq!(text, "Hello"),
3577 _ => panic!("Expected text content"),
3578 }
3579 }
3580
3581 #[test]
3582 fn test_sampling_content_or_array_multiple() {
3583 let json = serde_json::json!([
3584 { "type": "text", "text": "Hello" },
3585 { "type": "text", "text": "World" }
3586 ]);
3587 let content: SamplingContentOrArray = serde_json::from_value(json).unwrap();
3588 let items = content.items();
3589 assert_eq!(items.len(), 2);
3590 }
3591
3592 #[test]
3593 fn test_create_message_params_with_tools() {
3594 let tool = SamplingTool {
3595 name: "calculator".to_string(),
3596 description: Some("Do math".to_string()),
3597 input_schema: serde_json::json!({"type": "object"}),
3598 };
3599 let params = CreateMessageParams::new(vec![], 100)
3600 .tools(vec![tool])
3601 .tool_choice(ToolChoice::auto());
3602
3603 let json = serde_json::to_value(¶ms).unwrap();
3604 assert!(json["tools"].is_array());
3605 assert_eq!(json["tools"][0]["name"], "calculator");
3606 assert_eq!(json["toolChoice"]["type"], "auto");
3607 }
3608
3609 #[test]
3610 fn test_create_message_result_content_items() {
3611 let result = CreateMessageResult {
3612 content: SamplingContentOrArray::Array(vec![
3613 SamplingContent::Text {
3614 text: "First".to_string(),
3615 },
3616 SamplingContent::Text {
3617 text: "Second".to_string(),
3618 },
3619 ]),
3620 model: "test".to_string(),
3621 role: ContentRole::Assistant,
3622 stop_reason: None,
3623 };
3624 let items = result.content_items();
3625 assert_eq!(items.len(), 2);
3626 }
3627}