1use std::collections::HashMap;
7
8use serde::de::DeserializeOwned;
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11
12use crate::error::JsonRpcError;
13
14pub const JSONRPC_VERSION: &str = "2.0";
16
17pub const LATEST_PROTOCOL_VERSION: &str = "2025-11-25";
19
20pub const SUPPORTED_PROTOCOL_VERSIONS: &[&str] = &["2025-11-25", "2025-03-26"];
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct JsonRpcRequest {
37 pub jsonrpc: String,
39 pub id: RequestId,
41 pub method: String,
43 #[serde(default, skip_serializing_if = "Option::is_none")]
45 pub params: Option<Value>,
46}
47
48impl JsonRpcRequest {
49 pub fn new(id: impl Into<RequestId>, method: impl Into<String>) -> Self {
51 Self {
52 jsonrpc: JSONRPC_VERSION.to_string(),
53 id: id.into(),
54 method: method.into(),
55 params: None,
56 }
57 }
58
59 pub fn with_params(mut self, params: Value) -> Self {
61 self.params = Some(params);
62 self
63 }
64
65 pub fn validate(&self) -> Result<(), JsonRpcError> {
68 if self.jsonrpc != JSONRPC_VERSION {
69 return Err(JsonRpcError::invalid_request(format!(
70 "Invalid JSON-RPC version: expected '{}', got '{}'",
71 JSONRPC_VERSION, self.jsonrpc
72 )));
73 }
74 Ok(())
75 }
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct JsonRpcResultResponse {
81 pub jsonrpc: String,
83 pub id: RequestId,
85 pub result: Value,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct JsonRpcErrorResponse {
92 pub jsonrpc: String,
94 #[serde(skip_serializing_if = "Option::is_none")]
96 pub id: Option<RequestId>,
97 pub error: JsonRpcError,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
103#[serde(untagged)]
104#[non_exhaustive]
105pub enum JsonRpcResponse {
106 Result(JsonRpcResultResponse),
108 Error(JsonRpcErrorResponse),
110}
111
112impl JsonRpcResponse {
113 pub fn result(id: RequestId, result: Value) -> Self {
115 Self::Result(JsonRpcResultResponse {
116 jsonrpc: JSONRPC_VERSION.to_string(),
117 id,
118 result,
119 })
120 }
121
122 pub fn error(id: Option<RequestId>, error: JsonRpcError) -> Self {
124 Self::Error(JsonRpcErrorResponse {
125 jsonrpc: JSONRPC_VERSION.to_string(),
126 id,
127 error,
128 })
129 }
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
134#[serde(untagged)]
135#[non_exhaustive]
136pub enum JsonRpcMessage {
137 Single(JsonRpcRequest),
139 Batch(Vec<JsonRpcRequest>),
141}
142
143impl JsonRpcMessage {
144 pub fn is_batch(&self) -> bool {
146 matches!(self, JsonRpcMessage::Batch(_))
147 }
148
149 pub fn len(&self) -> usize {
151 match self {
152 JsonRpcMessage::Single(_) => 1,
153 JsonRpcMessage::Batch(batch) => batch.len(),
154 }
155 }
156
157 pub fn is_empty(&self) -> bool {
159 self.len() == 0
160 }
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize)]
165#[serde(untagged)]
166#[non_exhaustive]
167pub enum JsonRpcResponseMessage {
168 Single(JsonRpcResponse),
170 Batch(Vec<JsonRpcResponse>),
172}
173
174impl JsonRpcResponseMessage {
175 pub fn is_batch(&self) -> bool {
177 matches!(self, JsonRpcResponseMessage::Batch(_))
178 }
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct JsonRpcNotification {
184 pub jsonrpc: String,
185 pub method: String,
186 #[serde(default, skip_serializing_if = "Option::is_none")]
187 pub params: Option<Value>,
188}
189
190impl JsonRpcNotification {
191 pub fn new(method: impl Into<String>) -> Self {
192 Self {
193 jsonrpc: JSONRPC_VERSION.to_string(),
194 method: method.into(),
195 params: None,
196 }
197 }
198
199 pub fn with_params(mut self, params: Value) -> Self {
200 self.params = Some(params);
201 self
202 }
203}
204
205pub mod notifications {
207 pub const INITIALIZED: &str = "notifications/initialized";
209 pub const CANCELLED: &str = "notifications/cancelled";
211 pub const PROGRESS: &str = "notifications/progress";
213 pub const TOOLS_LIST_CHANGED: &str = "notifications/tools/list_changed";
215 pub const RESOURCES_LIST_CHANGED: &str = "notifications/resources/list_changed";
217 pub const RESOURCE_UPDATED: &str = "notifications/resources/updated";
219 pub const PROMPTS_LIST_CHANGED: &str = "notifications/prompts/list_changed";
221 pub const ROOTS_LIST_CHANGED: &str = "notifications/roots/list_changed";
223 pub const MESSAGE: &str = "notifications/message";
225 pub const TASK_STATUS_CHANGED: &str = "notifications/tasks/status";
227 pub const ELICITATION_COMPLETE: &str = "notifications/elicitation/complete";
229}
230
231#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
235#[serde(rename_all = "lowercase")]
236#[non_exhaustive]
237pub enum LogLevel {
238 Emergency,
240 Alert,
242 Critical,
244 Error,
246 Warning,
248 Notice,
250 #[default]
252 Info,
253 Debug,
255}
256
257impl std::fmt::Display for LogLevel {
258 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259 match self {
260 LogLevel::Emergency => write!(f, "emergency"),
261 LogLevel::Alert => write!(f, "alert"),
262 LogLevel::Critical => write!(f, "critical"),
263 LogLevel::Error => write!(f, "error"),
264 LogLevel::Warning => write!(f, "warning"),
265 LogLevel::Notice => write!(f, "notice"),
266 LogLevel::Info => write!(f, "info"),
267 LogLevel::Debug => write!(f, "debug"),
268 }
269 }
270}
271
272#[derive(Debug, Clone, Serialize, Deserialize)]
274pub struct LoggingMessageParams {
275 pub level: LogLevel,
277 #[serde(skip_serializing_if = "Option::is_none")]
279 pub logger: Option<String>,
280 #[serde(default)]
282 pub data: Value,
283 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
285 pub meta: Option<Value>,
286}
287
288impl LoggingMessageParams {
289 pub fn new(level: LogLevel, data: impl Into<Value>) -> Self {
291 Self {
292 level,
293 logger: None,
294 data: data.into(),
295 meta: None,
296 }
297 }
298
299 pub fn with_logger(mut self, logger: impl Into<String>) -> Self {
301 self.logger = Some(logger.into());
302 self
303 }
304
305 pub fn with_data(mut self, data: impl Into<Value>) -> Self {
307 self.data = data.into();
308 self
309 }
310}
311
312#[derive(Debug, Clone, Deserialize)]
314pub struct SetLogLevelParams {
315 pub level: LogLevel,
317 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
319 pub meta: Option<RequestMeta>,
320}
321
322#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
324#[serde(untagged)]
325#[non_exhaustive]
326pub enum RequestId {
327 String(String),
328 Number(i64),
329}
330
331impl From<String> for RequestId {
332 fn from(s: String) -> Self {
333 RequestId::String(s)
334 }
335}
336
337impl From<&str> for RequestId {
338 fn from(s: &str) -> Self {
339 RequestId::String(s.to_string())
340 }
341}
342
343impl From<i64> for RequestId {
344 fn from(n: i64) -> Self {
345 RequestId::Number(n)
346 }
347}
348
349impl From<i32> for RequestId {
350 fn from(n: i32) -> Self {
351 RequestId::Number(n as i64)
352 }
353}
354
355#[derive(Debug, Clone)]
361#[non_exhaustive]
362pub enum McpRequest {
363 Initialize(InitializeParams),
365 ListTools(ListToolsParams),
367 CallTool(CallToolParams),
369 ListResources(ListResourcesParams),
371 ListResourceTemplates(ListResourceTemplatesParams),
373 ReadResource(ReadResourceParams),
375 SubscribeResource(SubscribeResourceParams),
377 UnsubscribeResource(UnsubscribeResourceParams),
379 ListPrompts(ListPromptsParams),
381 GetPrompt(GetPromptParams),
383 ListTasks(ListTasksParams),
385 GetTaskInfo(GetTaskInfoParams),
387 GetTaskResult(GetTaskResultParams),
389 CancelTask(CancelTaskParams),
391 Ping,
393 SetLoggingLevel(SetLogLevelParams),
395 Complete(CompleteParams),
397 Unknown {
399 method: String,
400 params: Option<Value>,
401 },
402}
403
404impl McpRequest {
405 pub fn method_name(&self) -> &str {
407 match self {
408 McpRequest::Initialize(_) => "initialize",
409 McpRequest::ListTools(_) => "tools/list",
410 McpRequest::CallTool(_) => "tools/call",
411 McpRequest::ListResources(_) => "resources/list",
412 McpRequest::ListResourceTemplates(_) => "resources/templates/list",
413 McpRequest::ReadResource(_) => "resources/read",
414 McpRequest::SubscribeResource(_) => "resources/subscribe",
415 McpRequest::UnsubscribeResource(_) => "resources/unsubscribe",
416 McpRequest::ListPrompts(_) => "prompts/list",
417 McpRequest::GetPrompt(_) => "prompts/get",
418 McpRequest::ListTasks(_) => "tasks/list",
419 McpRequest::GetTaskInfo(_) => "tasks/get",
420 McpRequest::GetTaskResult(_) => "tasks/result",
421 McpRequest::CancelTask(_) => "tasks/cancel",
422 McpRequest::Ping => "ping",
423 McpRequest::SetLoggingLevel(_) => "logging/setLevel",
424 McpRequest::Complete(_) => "completion/complete",
425 McpRequest::Unknown { method, .. } => method,
426 }
427 }
428}
429
430#[derive(Debug, Clone)]
432#[non_exhaustive]
433pub enum McpNotification {
434 Initialized,
436 Cancelled(CancelledParams),
438 Progress(ProgressParams),
440 RootsListChanged,
442 Unknown {
444 method: String,
445 params: Option<Value>,
446 },
447}
448
449#[derive(Debug, Clone, Serialize, Deserialize)]
451#[serde(rename_all = "camelCase")]
452pub struct CancelledParams {
453 #[serde(default, skip_serializing_if = "Option::is_none")]
455 pub request_id: Option<RequestId>,
456 #[serde(skip_serializing_if = "Option::is_none")]
458 pub reason: Option<String>,
459 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
461 pub meta: Option<Value>,
462}
463
464#[derive(Debug, Clone, Serialize, Deserialize)]
466#[serde(rename_all = "camelCase")]
467pub struct ProgressParams {
468 pub progress_token: ProgressToken,
470 pub progress: f64,
472 #[serde(skip_serializing_if = "Option::is_none")]
474 pub total: Option<f64>,
475 #[serde(skip_serializing_if = "Option::is_none")]
477 pub message: Option<String>,
478 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
480 pub meta: Option<Value>,
481}
482
483#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
485#[serde(untagged)]
486#[non_exhaustive]
487pub enum ProgressToken {
488 String(String),
489 Number(i64),
490}
491
492#[derive(Debug, Clone, Default, Serialize, Deserialize)]
494#[serde(rename_all = "camelCase")]
495pub struct RequestMeta {
496 #[serde(skip_serializing_if = "Option::is_none")]
498 pub progress_token: Option<ProgressToken>,
499}
500
501#[derive(Debug, Clone, Serialize, Deserialize)]
503#[serde(untagged)]
504#[non_exhaustive]
505pub enum McpResponse {
506 Initialize(InitializeResult),
507 ListTools(ListToolsResult),
508 CallTool(CallToolResult),
509 ListResources(ListResourcesResult),
510 ListResourceTemplates(ListResourceTemplatesResult),
511 ReadResource(ReadResourceResult),
512 SubscribeResource(EmptyResult),
513 UnsubscribeResource(EmptyResult),
514 ListPrompts(ListPromptsResult),
515 GetPrompt(GetPromptResult),
516 CreateTask(CreateTaskResult),
517 ListTasks(ListTasksResult),
518 GetTaskInfo(TaskObject),
519 GetTaskResult(CallToolResult),
520 CancelTask(TaskObject),
521 SetLoggingLevel(EmptyResult),
522 Complete(CompleteResult),
523 Pong(EmptyResult),
524 Empty(EmptyResult),
525 Raw(Value),
527}
528
529#[derive(Debug, Clone, Serialize, Deserialize)]
534#[serde(rename_all = "camelCase")]
535pub struct InitializeParams {
536 pub protocol_version: String,
537 pub capabilities: ClientCapabilities,
538 pub client_info: Implementation,
539 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
541 pub meta: Option<Value>,
542}
543
544#[derive(Debug, Clone, Default, Serialize, Deserialize)]
545pub struct ClientCapabilities {
546 #[serde(default, skip_serializing_if = "Option::is_none")]
547 pub roots: Option<RootsCapability>,
548 #[serde(default, skip_serializing_if = "Option::is_none")]
549 pub sampling: Option<SamplingCapability>,
550 #[serde(default, skip_serializing_if = "Option::is_none")]
551 pub elicitation: Option<ElicitationCapability>,
552 #[serde(default, skip_serializing_if = "Option::is_none")]
553 pub tasks: Option<ClientTasksCapability>,
554 #[serde(default, skip_serializing_if = "Option::is_none")]
556 pub experimental: Option<HashMap<String, serde_json::Value>>,
557 #[serde(default, skip_serializing_if = "Option::is_none")]
559 pub extensions: Option<HashMap<String, serde_json::Value>>,
560}
561
562#[derive(Debug, Clone, Default, Serialize, Deserialize)]
564pub struct ElicitationCapability {
565 #[serde(default, skip_serializing_if = "Option::is_none")]
567 pub form: Option<ElicitationFormCapability>,
568 #[serde(default, skip_serializing_if = "Option::is_none")]
570 pub url: Option<ElicitationUrlCapability>,
571}
572
573#[derive(Debug, Clone, Default, Serialize, Deserialize)]
575pub struct ElicitationFormCapability {}
576
577#[derive(Debug, Clone, Default, Serialize, Deserialize)]
579pub struct ElicitationUrlCapability {}
580
581#[derive(Debug, Clone, Default, Serialize, Deserialize)]
583#[serde(rename_all = "camelCase")]
584pub struct ClientTasksCapability {
585 #[serde(default, skip_serializing_if = "Option::is_none")]
587 pub list: Option<ClientTasksListCapability>,
588 #[serde(default, skip_serializing_if = "Option::is_none")]
590 pub cancel: Option<ClientTasksCancelCapability>,
591 #[serde(default, skip_serializing_if = "Option::is_none")]
593 pub requests: Option<ClientTasksRequestsCapability>,
594}
595
596#[derive(Debug, Clone, Default, Serialize, Deserialize)]
598pub struct ClientTasksListCapability {}
599
600#[derive(Debug, Clone, Default, Serialize, Deserialize)]
602pub struct ClientTasksCancelCapability {}
603
604#[derive(Debug, Clone, Default, Serialize, Deserialize)]
606#[serde(rename_all = "camelCase")]
607pub struct ClientTasksRequestsCapability {
608 #[serde(default, skip_serializing_if = "Option::is_none")]
610 pub sampling: Option<ClientTasksSamplingCapability>,
611 #[serde(default, skip_serializing_if = "Option::is_none")]
613 pub elicitation: Option<ClientTasksElicitationCapability>,
614}
615
616#[derive(Debug, Clone, Default, Serialize, Deserialize)]
618#[serde(rename_all = "camelCase")]
619pub struct ClientTasksSamplingCapability {
620 #[serde(default, skip_serializing_if = "Option::is_none")]
622 pub create_message: Option<ClientTasksSamplingCreateMessageCapability>,
623}
624
625#[derive(Debug, Clone, Default, Serialize, Deserialize)]
627pub struct ClientTasksSamplingCreateMessageCapability {}
628
629#[derive(Debug, Clone, Default, Serialize, Deserialize)]
631#[serde(rename_all = "camelCase")]
632pub struct ClientTasksElicitationCapability {
633 #[serde(default, skip_serializing_if = "Option::is_none")]
635 pub create: Option<ClientTasksElicitationCreateCapability>,
636}
637
638#[derive(Debug, Clone, Default, Serialize, Deserialize)]
640pub struct ClientTasksElicitationCreateCapability {}
641
642#[derive(Debug, Clone, Default, Serialize, Deserialize)]
666#[serde(rename_all = "camelCase")]
667pub struct RootsCapability {
668 #[serde(default)]
670 pub list_changed: bool,
671}
672
673#[derive(Debug, Clone, Serialize, Deserialize)]
693pub struct Root {
694 pub uri: String,
696 #[serde(default, skip_serializing_if = "Option::is_none")]
698 pub name: Option<String>,
699 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
701 pub meta: Option<Value>,
702}
703
704impl Root {
705 pub fn new(uri: impl Into<String>) -> Self {
707 Self {
708 uri: uri.into(),
709 name: None,
710 meta: None,
711 }
712 }
713
714 pub fn with_name(uri: impl Into<String>, name: impl Into<String>) -> Self {
716 Self {
717 uri: uri.into(),
718 name: Some(name.into()),
719 meta: None,
720 }
721 }
722}
723
724#[derive(Debug, Clone, Default, Serialize, Deserialize)]
731pub struct ListRootsParams {
732 #[serde(default, rename = "_meta", skip_serializing_if = "Option::is_none")]
734 pub meta: Option<RequestMeta>,
735}
736
737#[derive(Debug, Clone, Serialize, Deserialize)]
739pub struct ListRootsResult {
740 pub roots: Vec<Root>,
742 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
744 pub meta: Option<Value>,
745}
746
747#[derive(Debug, Clone, Default, Serialize, Deserialize)]
748pub struct SamplingCapability {
749 #[serde(default, skip_serializing_if = "Option::is_none")]
751 pub tools: Option<SamplingToolsCapability>,
752 #[serde(default, skip_serializing_if = "Option::is_none")]
754 pub context: Option<SamplingContextCapability>,
755}
756
757#[derive(Debug, Clone, Default, Serialize, Deserialize)]
759pub struct SamplingToolsCapability {}
760
761#[derive(Debug, Clone, Default, Serialize, Deserialize)]
763pub struct SamplingContextCapability {}
764
765#[derive(Debug, Clone, Default, Serialize, Deserialize)]
767pub struct CompletionsCapability {}
768
769#[derive(Debug, Clone, Serialize, Deserialize)]
775pub struct PromptReference {
776 #[serde(rename = "type")]
778 pub ref_type: String,
779 pub name: String,
781}
782
783impl PromptReference {
784 pub fn new(name: impl Into<String>) -> Self {
786 Self {
787 ref_type: "ref/prompt".to_string(),
788 name: name.into(),
789 }
790 }
791}
792
793#[derive(Debug, Clone, Serialize, Deserialize)]
795pub struct ResourceReference {
796 #[serde(rename = "type")]
798 pub ref_type: String,
799 pub uri: String,
801}
802
803impl ResourceReference {
804 pub fn new(uri: impl Into<String>) -> Self {
806 Self {
807 ref_type: "ref/resource".to_string(),
808 uri: uri.into(),
809 }
810 }
811}
812
813#[derive(Debug, Clone, Serialize, Deserialize)]
815#[serde(tag = "type")]
816#[non_exhaustive]
817pub enum CompletionReference {
818 #[serde(rename = "ref/prompt")]
820 Prompt {
821 name: String,
823 },
824 #[serde(rename = "ref/resource")]
826 Resource {
827 uri: String,
829 },
830}
831
832impl CompletionReference {
833 pub fn prompt(name: impl Into<String>) -> Self {
835 Self::Prompt { name: name.into() }
836 }
837
838 pub fn resource(uri: impl Into<String>) -> Self {
840 Self::Resource { uri: uri.into() }
841 }
842}
843
844#[derive(Debug, Clone, Serialize, Deserialize)]
846pub struct CompletionArgument {
847 pub name: String,
849 pub value: String,
851}
852
853impl CompletionArgument {
854 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
856 Self {
857 name: name.into(),
858 value: value.into(),
859 }
860 }
861}
862
863#[derive(Debug, Clone, Serialize, Deserialize)]
865#[serde(rename_all = "camelCase")]
866pub struct CompleteParams {
867 #[serde(rename = "ref")]
869 pub reference: CompletionReference,
870 pub argument: CompletionArgument,
872 #[serde(default, skip_serializing_if = "Option::is_none")]
874 pub context: Option<CompletionContext>,
875 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
877 pub meta: Option<Value>,
878}
879
880#[derive(Debug, Clone, Serialize, Deserialize)]
882#[serde(rename_all = "camelCase")]
883pub struct CompletionContext {
884 #[serde(default, skip_serializing_if = "Option::is_none")]
886 pub arguments: Option<std::collections::HashMap<String, String>>,
887}
888
889#[derive(Debug, Clone, Serialize, Deserialize)]
891#[serde(rename_all = "camelCase")]
892pub struct Completion {
893 pub values: Vec<String>,
895 #[serde(default, skip_serializing_if = "Option::is_none")]
897 pub total: Option<u32>,
898 #[serde(default, skip_serializing_if = "Option::is_none")]
900 pub has_more: Option<bool>,
901}
902
903impl Completion {
904 pub fn new(values: Vec<String>) -> Self {
906 Self {
907 values,
908 total: None,
909 has_more: None,
910 }
911 }
912
913 pub fn with_pagination(values: Vec<String>, total: u32, has_more: bool) -> Self {
915 Self {
916 values,
917 total: Some(total),
918 has_more: Some(has_more),
919 }
920 }
921}
922
923#[derive(Debug, Clone, Serialize, Deserialize)]
925pub struct CompleteResult {
926 pub completion: Completion,
928 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
930 pub meta: Option<Value>,
931}
932
933impl CompleteResult {
934 pub fn new(values: Vec<String>) -> Self {
936 Self {
937 completion: Completion::new(values),
938 meta: None,
939 }
940 }
941
942 pub fn with_pagination(values: Vec<String>, total: u32, has_more: bool) -> Self {
944 Self {
945 completion: Completion::with_pagination(values, total, has_more),
946 meta: None,
947 }
948 }
949}
950
951#[derive(Debug, Clone, Serialize, Deserialize)]
957pub struct ModelHint {
958 #[serde(default, skip_serializing_if = "Option::is_none")]
960 pub name: Option<String>,
961}
962
963impl ModelHint {
964 pub fn new(name: impl Into<String>) -> Self {
966 Self {
967 name: Some(name.into()),
968 }
969 }
970}
971
972#[derive(Debug, Clone, Default, Serialize, Deserialize)]
974#[serde(rename_all = "camelCase")]
975pub struct ModelPreferences {
976 #[serde(default, skip_serializing_if = "Option::is_none")]
978 pub speed_priority: Option<f64>,
979 #[serde(default, skip_serializing_if = "Option::is_none")]
981 pub intelligence_priority: Option<f64>,
982 #[serde(default, skip_serializing_if = "Option::is_none")]
984 pub cost_priority: Option<f64>,
985 #[serde(default, skip_serializing_if = "Vec::is_empty")]
987 pub hints: Vec<ModelHint>,
988}
989
990impl ModelPreferences {
991 pub fn new() -> Self {
993 Self::default()
994 }
995
996 pub fn speed(mut self, priority: f64) -> Self {
998 self.speed_priority = Some(priority.clamp(0.0, 1.0));
999 self
1000 }
1001
1002 pub fn intelligence(mut self, priority: f64) -> Self {
1004 self.intelligence_priority = Some(priority.clamp(0.0, 1.0));
1005 self
1006 }
1007
1008 pub fn cost(mut self, priority: f64) -> Self {
1010 self.cost_priority = Some(priority.clamp(0.0, 1.0));
1011 self
1012 }
1013
1014 pub fn hint(mut self, name: impl Into<String>) -> Self {
1016 self.hints.push(ModelHint::new(name));
1017 self
1018 }
1019}
1020
1021#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
1023#[serde(rename_all = "camelCase")]
1024#[non_exhaustive]
1025pub enum IncludeContext {
1026 AllServers,
1028 ThisServer,
1030 #[default]
1032 None,
1033}
1034
1035#[derive(Debug, Clone, Serialize, Deserialize)]
1037pub struct SamplingMessage {
1038 pub role: ContentRole,
1040 pub content: SamplingContentOrArray,
1042 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1044 pub meta: Option<Value>,
1045}
1046
1047impl SamplingMessage {
1048 pub fn user(text: impl Into<String>) -> Self {
1050 Self {
1051 role: ContentRole::User,
1052 content: SamplingContentOrArray::Single(SamplingContent::Text {
1053 text: text.into(),
1054 annotations: None,
1055 meta: None,
1056 }),
1057 meta: None,
1058 }
1059 }
1060
1061 pub fn assistant(text: impl Into<String>) -> Self {
1063 Self {
1064 role: ContentRole::Assistant,
1065 content: SamplingContentOrArray::Single(SamplingContent::Text {
1066 text: text.into(),
1067 annotations: None,
1068 meta: None,
1069 }),
1070 meta: None,
1071 }
1072 }
1073}
1074
1075#[derive(Debug, Clone, Serialize, Deserialize)]
1080#[serde(rename_all = "camelCase")]
1081pub struct SamplingTool {
1082 pub name: String,
1084 #[serde(default, skip_serializing_if = "Option::is_none")]
1086 pub title: Option<String>,
1087 #[serde(skip_serializing_if = "Option::is_none")]
1089 pub description: Option<String>,
1090 pub input_schema: Value,
1092 #[serde(default, skip_serializing_if = "Option::is_none")]
1094 pub output_schema: Option<Value>,
1095 #[serde(default, skip_serializing_if = "Option::is_none")]
1097 pub icons: Option<Vec<ToolIcon>>,
1098 #[serde(default, skip_serializing_if = "Option::is_none")]
1100 pub annotations: Option<ToolAnnotations>,
1101 #[serde(default, skip_serializing_if = "Option::is_none")]
1103 pub execution: Option<ToolExecution>,
1104}
1105
1106#[derive(Debug, Clone, Serialize, Deserialize)]
1110pub struct ToolChoice {
1111 pub mode: String,
1113 #[serde(skip_serializing_if = "Option::is_none")]
1115 pub name: Option<String>,
1116}
1117
1118impl ToolChoice {
1119 pub fn auto() -> Self {
1121 Self {
1122 mode: "auto".to_string(),
1123 name: None,
1124 }
1125 }
1126
1127 pub fn required() -> Self {
1129 Self {
1130 mode: "required".to_string(),
1131 name: None,
1132 }
1133 }
1134
1135 pub fn none() -> Self {
1137 Self {
1138 mode: "none".to_string(),
1139 name: None,
1140 }
1141 }
1142
1143 pub fn tool(name: impl Into<String>) -> Self {
1145 Self {
1146 mode: "tool".to_string(),
1147 name: Some(name.into()),
1148 }
1149 }
1150}
1151
1152#[derive(Debug, Clone, Serialize, Deserialize)]
1154#[serde(tag = "type", rename_all = "lowercase")]
1155#[non_exhaustive]
1156pub enum SamplingContent {
1157 Text {
1159 text: String,
1161 #[serde(default, skip_serializing_if = "Option::is_none")]
1163 annotations: Option<ContentAnnotations>,
1164 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1166 meta: Option<Value>,
1167 },
1168 Image {
1170 data: String,
1172 #[serde(rename = "mimeType")]
1174 mime_type: String,
1175 #[serde(default, skip_serializing_if = "Option::is_none")]
1177 annotations: Option<ContentAnnotations>,
1178 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1180 meta: Option<Value>,
1181 },
1182 Audio {
1184 data: String,
1186 #[serde(rename = "mimeType")]
1188 mime_type: String,
1189 #[serde(default, skip_serializing_if = "Option::is_none")]
1191 annotations: Option<ContentAnnotations>,
1192 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1194 meta: Option<Value>,
1195 },
1196 #[serde(rename = "tool_use")]
1198 ToolUse {
1199 id: String,
1201 name: String,
1203 input: Value,
1205 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1207 meta: Option<Value>,
1208 },
1209 #[serde(rename = "tool_result")]
1211 ToolResult {
1212 #[serde(rename = "toolUseId")]
1214 tool_use_id: String,
1215 content: Vec<SamplingContent>,
1217 #[serde(
1219 default,
1220 rename = "structuredContent",
1221 skip_serializing_if = "Option::is_none"
1222 )]
1223 structured_content: Option<Value>,
1224 #[serde(default, rename = "isError", skip_serializing_if = "Option::is_none")]
1226 is_error: Option<bool>,
1227 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1229 meta: Option<Value>,
1230 },
1231}
1232
1233impl SamplingContent {
1234 pub fn as_text(&self) -> Option<&str> {
1255 match self {
1256 SamplingContent::Text { text, .. } => Some(text),
1257 _ => None,
1258 }
1259 }
1260}
1261
1262#[derive(Debug, Clone, Serialize, Deserialize)]
1267#[serde(untagged)]
1268#[non_exhaustive]
1269pub enum SamplingContentOrArray {
1270 Single(SamplingContent),
1272 Array(Vec<SamplingContent>),
1274}
1275
1276impl SamplingContentOrArray {
1277 pub fn items(&self) -> Vec<&SamplingContent> {
1279 match self {
1280 Self::Single(c) => vec![c],
1281 Self::Array(arr) => arr.iter().collect(),
1282 }
1283 }
1284
1285 pub fn into_items(self) -> Vec<SamplingContent> {
1287 match self {
1288 Self::Single(c) => vec![c],
1289 Self::Array(arr) => arr,
1290 }
1291 }
1292}
1293
1294#[derive(Debug, Clone, Serialize, Deserialize)]
1296#[serde(rename_all = "camelCase")]
1297pub struct CreateMessageParams {
1298 pub messages: Vec<SamplingMessage>,
1300 pub max_tokens: u32,
1302 #[serde(default, skip_serializing_if = "Option::is_none")]
1304 pub system_prompt: Option<String>,
1305 #[serde(default, skip_serializing_if = "Option::is_none")]
1307 pub temperature: Option<f64>,
1308 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1310 pub stop_sequences: Vec<String>,
1311 #[serde(default, skip_serializing_if = "Option::is_none")]
1313 pub model_preferences: Option<ModelPreferences>,
1314 #[serde(default, skip_serializing_if = "Option::is_none")]
1316 pub include_context: Option<IncludeContext>,
1317 #[serde(default, skip_serializing_if = "Option::is_none")]
1319 pub metadata: Option<serde_json::Map<String, Value>>,
1320 #[serde(default, skip_serializing_if = "Option::is_none")]
1322 pub tools: Option<Vec<SamplingTool>>,
1323 #[serde(default, skip_serializing_if = "Option::is_none")]
1325 pub tool_choice: Option<ToolChoice>,
1326 #[serde(default, skip_serializing_if = "Option::is_none")]
1328 pub task: Option<TaskRequestParams>,
1329 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1331 pub meta: Option<Value>,
1332}
1333
1334impl CreateMessageParams {
1335 pub fn new(messages: Vec<SamplingMessage>, max_tokens: u32) -> Self {
1337 Self {
1338 messages,
1339 max_tokens,
1340 system_prompt: None,
1341 temperature: None,
1342 stop_sequences: Vec::new(),
1343 model_preferences: None,
1344 include_context: None,
1345 metadata: None,
1346 tools: None,
1347 tool_choice: None,
1348 task: None,
1349 meta: None,
1350 }
1351 }
1352
1353 pub fn system_prompt(mut self, prompt: impl Into<String>) -> Self {
1355 self.system_prompt = Some(prompt.into());
1356 self
1357 }
1358
1359 pub fn temperature(mut self, temp: f64) -> Self {
1361 self.temperature = Some(temp.clamp(0.0, 1.0));
1362 self
1363 }
1364
1365 pub fn stop_sequence(mut self, seq: impl Into<String>) -> Self {
1367 self.stop_sequences.push(seq.into());
1368 self
1369 }
1370
1371 pub fn model_preferences(mut self, prefs: ModelPreferences) -> Self {
1373 self.model_preferences = Some(prefs);
1374 self
1375 }
1376
1377 pub fn include_context(mut self, mode: IncludeContext) -> Self {
1379 self.include_context = Some(mode);
1380 self
1381 }
1382
1383 pub fn tools(mut self, tools: Vec<SamplingTool>) -> Self {
1385 self.tools = Some(tools);
1386 self
1387 }
1388
1389 pub fn tool_choice(mut self, choice: ToolChoice) -> Self {
1391 self.tool_choice = Some(choice);
1392 self
1393 }
1394}
1395
1396#[derive(Debug, Clone, Serialize, Deserialize)]
1398#[serde(rename_all = "camelCase")]
1399pub struct CreateMessageResult {
1400 pub content: SamplingContentOrArray,
1402 pub model: String,
1404 pub role: ContentRole,
1406 #[serde(default, skip_serializing_if = "Option::is_none")]
1408 pub stop_reason: Option<String>,
1409 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1411 pub meta: Option<Value>,
1412}
1413
1414impl CreateMessageResult {
1415 pub fn content_items(&self) -> Vec<&SamplingContent> {
1417 self.content.items()
1418 }
1419
1420 pub fn first_text(&self) -> Option<&str> {
1444 self.content.items().iter().find_map(|c| c.as_text())
1445 }
1446}
1447
1448#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1450#[serde(rename_all = "camelCase")]
1451pub struct Implementation {
1452 pub name: String,
1454 pub version: String,
1456 #[serde(skip_serializing_if = "Option::is_none")]
1458 pub title: Option<String>,
1459 #[serde(skip_serializing_if = "Option::is_none")]
1461 pub description: Option<String>,
1462 #[serde(skip_serializing_if = "Option::is_none")]
1464 pub icons: Option<Vec<ToolIcon>>,
1465 #[serde(skip_serializing_if = "Option::is_none")]
1467 pub website_url: Option<String>,
1468 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1470 pub meta: Option<Value>,
1471}
1472
1473#[derive(Debug, Clone, Serialize, Deserialize)]
1474#[serde(rename_all = "camelCase")]
1475pub struct InitializeResult {
1476 pub protocol_version: String,
1477 pub capabilities: ServerCapabilities,
1478 pub server_info: Implementation,
1479 #[serde(skip_serializing_if = "Option::is_none")]
1482 pub instructions: Option<String>,
1483 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1485 pub meta: Option<Value>,
1486}
1487
1488#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1489#[serde(rename_all = "camelCase")]
1490pub struct ServerCapabilities {
1491 #[serde(default, skip_serializing_if = "Option::is_none")]
1492 pub tools: Option<ToolsCapability>,
1493 #[serde(default, skip_serializing_if = "Option::is_none")]
1494 pub resources: Option<ResourcesCapability>,
1495 #[serde(default, skip_serializing_if = "Option::is_none")]
1496 pub prompts: Option<PromptsCapability>,
1497 #[serde(default, skip_serializing_if = "Option::is_none")]
1499 pub logging: Option<LoggingCapability>,
1500 #[serde(default, skip_serializing_if = "Option::is_none")]
1501 pub tasks: Option<TasksCapability>,
1502 #[serde(default, skip_serializing_if = "Option::is_none")]
1504 pub completions: Option<CompletionsCapability>,
1505 #[serde(default, skip_serializing_if = "Option::is_none")]
1507 pub experimental: Option<HashMap<String, serde_json::Value>>,
1508 #[serde(default, skip_serializing_if = "Option::is_none")]
1510 pub extensions: Option<HashMap<String, serde_json::Value>>,
1511}
1512
1513#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1515pub struct LoggingCapability {}
1516
1517#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1519#[serde(rename_all = "camelCase")]
1520pub struct TasksCapability {
1521 #[serde(default, skip_serializing_if = "Option::is_none")]
1523 pub list: Option<TasksListCapability>,
1524 #[serde(default, skip_serializing_if = "Option::is_none")]
1526 pub cancel: Option<TasksCancelCapability>,
1527 #[serde(default, skip_serializing_if = "Option::is_none")]
1529 pub requests: Option<TasksRequestsCapability>,
1530}
1531
1532#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1534pub struct TasksListCapability {}
1535
1536#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1538pub struct TasksCancelCapability {}
1539
1540#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1542#[serde(rename_all = "camelCase")]
1543pub struct TasksRequestsCapability {
1544 #[serde(default, skip_serializing_if = "Option::is_none")]
1546 pub tools: Option<TasksToolsRequestsCapability>,
1547}
1548
1549#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1551#[serde(rename_all = "camelCase")]
1552pub struct TasksToolsRequestsCapability {
1553 #[serde(default, skip_serializing_if = "Option::is_none")]
1555 pub call: Option<TasksToolsCallCapability>,
1556}
1557
1558#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1560pub struct TasksToolsCallCapability {}
1561
1562#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1563#[serde(rename_all = "camelCase")]
1564pub struct ToolsCapability {
1565 #[serde(default)]
1566 pub list_changed: bool,
1567}
1568
1569#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1570#[serde(rename_all = "camelCase")]
1571pub struct ResourcesCapability {
1572 #[serde(default)]
1573 pub subscribe: bool,
1574 #[serde(default)]
1575 pub list_changed: bool,
1576}
1577
1578#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1579#[serde(rename_all = "camelCase")]
1580pub struct PromptsCapability {
1581 #[serde(default)]
1582 pub list_changed: bool,
1583}
1584
1585#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1590pub struct ListToolsParams {
1591 #[serde(default, skip_serializing_if = "Option::is_none")]
1592 pub cursor: Option<String>,
1593 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1595 pub meta: Option<RequestMeta>,
1596}
1597
1598#[derive(Debug, Clone, Serialize, Deserialize)]
1599#[serde(rename_all = "camelCase")]
1600pub struct ListToolsResult {
1601 pub tools: Vec<ToolDefinition>,
1602 #[serde(default, skip_serializing_if = "Option::is_none")]
1603 pub next_cursor: Option<String>,
1604 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1606 pub meta: Option<Value>,
1607}
1608
1609#[derive(Debug, Clone, Serialize, Deserialize)]
1611#[serde(rename_all = "camelCase")]
1612pub struct ToolDefinition {
1613 pub name: String,
1614 #[serde(skip_serializing_if = "Option::is_none")]
1616 pub title: Option<String>,
1617 #[serde(skip_serializing_if = "Option::is_none")]
1618 pub description: Option<String>,
1619 pub input_schema: Value,
1620 #[serde(skip_serializing_if = "Option::is_none")]
1622 pub output_schema: Option<Value>,
1623 #[serde(skip_serializing_if = "Option::is_none")]
1625 pub icons: Option<Vec<ToolIcon>>,
1626 #[serde(skip_serializing_if = "Option::is_none")]
1629 pub annotations: Option<ToolAnnotations>,
1630 #[serde(skip_serializing_if = "Option::is_none")]
1632 pub execution: Option<ToolExecution>,
1633 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1635 pub meta: Option<Value>,
1636}
1637
1638#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1640#[serde(rename_all = "lowercase")]
1641#[non_exhaustive]
1642pub enum IconTheme {
1643 Light,
1645 Dark,
1647}
1648
1649#[derive(Debug, Clone, Serialize, Deserialize)]
1651#[serde(rename_all = "camelCase")]
1652pub struct ToolIcon {
1653 pub src: String,
1655 #[serde(skip_serializing_if = "Option::is_none")]
1657 pub mime_type: Option<String>,
1658 #[serde(skip_serializing_if = "Option::is_none")]
1660 pub sizes: Option<Vec<String>>,
1661 #[serde(skip_serializing_if = "Option::is_none")]
1663 pub theme: Option<IconTheme>,
1664}
1665
1666#[derive(Debug, Clone, Serialize, Deserialize)]
1669#[serde(rename_all = "camelCase")]
1670pub struct ToolAnnotations {
1671 #[serde(skip_serializing_if = "Option::is_none")]
1673 pub title: Option<String>,
1674 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1676 pub read_only_hint: bool,
1677 #[serde(default = "default_true", skip_serializing_if = "is_true")]
1680 pub destructive_hint: bool,
1681 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1684 pub idempotent_hint: bool,
1685 #[serde(default = "default_true", skip_serializing_if = "is_true")]
1687 pub open_world_hint: bool,
1688}
1689
1690impl Default for ToolAnnotations {
1691 fn default() -> Self {
1692 Self {
1693 title: None,
1694 read_only_hint: false,
1695 destructive_hint: true,
1696 idempotent_hint: false,
1697 open_world_hint: true,
1698 }
1699 }
1700}
1701
1702impl ToolAnnotations {
1703 pub fn is_read_only(&self) -> bool {
1705 self.read_only_hint
1706 }
1707
1708 pub fn is_destructive(&self) -> bool {
1710 self.destructive_hint
1711 }
1712
1713 pub fn is_idempotent(&self) -> bool {
1715 self.idempotent_hint
1716 }
1717
1718 pub fn is_open_world(&self) -> bool {
1720 self.open_world_hint
1721 }
1722}
1723
1724impl ToolDefinition {
1725 pub fn is_read_only(&self) -> bool {
1729 self.annotations.as_ref().is_some_and(|a| a.read_only_hint)
1730 }
1731
1732 pub fn is_destructive(&self) -> bool {
1736 self.annotations.as_ref().is_none_or(|a| a.destructive_hint)
1737 }
1738
1739 pub fn is_idempotent(&self) -> bool {
1743 self.annotations.as_ref().is_some_and(|a| a.idempotent_hint)
1744 }
1745
1746 pub fn is_open_world(&self) -> bool {
1750 self.annotations.as_ref().is_none_or(|a| a.open_world_hint)
1751 }
1752}
1753
1754fn default_true() -> bool {
1755 true
1756}
1757
1758fn is_true(v: &bool) -> bool {
1759 *v
1760}
1761
1762#[derive(Debug, Clone, Serialize, Deserialize)]
1763pub struct CallToolParams {
1764 pub name: String,
1765 #[serde(default)]
1766 pub arguments: Value,
1767 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1769 pub meta: Option<RequestMeta>,
1770 #[serde(default, skip_serializing_if = "Option::is_none")]
1772 pub task: Option<TaskRequestParams>,
1773}
1774
1775#[derive(Debug, Clone, Serialize, Deserialize)]
1796#[serde(rename_all = "camelCase")]
1797pub struct CallToolResult {
1798 pub content: Vec<Content>,
1800 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1802 pub is_error: bool,
1803 #[serde(default, skip_serializing_if = "Option::is_none")]
1805 pub structured_content: Option<Value>,
1806 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1808 pub meta: Option<Value>,
1809}
1810
1811impl CallToolResult {
1812 pub fn text(text: impl Into<String>) -> Self {
1816 Self {
1817 content: vec![Content::Text {
1818 text: text.into(),
1819 annotations: None,
1820 meta: None,
1821 }],
1822 is_error: false,
1823 structured_content: None,
1824 meta: None,
1825 }
1826 }
1827
1828 pub fn error(message: impl Into<String>) -> Self {
1833 Self {
1834 content: vec![Content::Text {
1835 text: message.into(),
1836 annotations: None,
1837 meta: None,
1838 }],
1839 is_error: true,
1840 structured_content: None,
1841 meta: None,
1842 }
1843 }
1844
1845 pub fn json(value: Value) -> Self {
1853 let text = serde_json::to_string_pretty(&value).unwrap_or_default();
1854 Self {
1855 content: vec![Content::Text {
1856 text,
1857 annotations: None,
1858 meta: None,
1859 }],
1860 is_error: false,
1861 structured_content: Some(value),
1862 meta: None,
1863 }
1864 }
1865
1866 pub fn from_serialize(
1898 value: &impl serde::Serialize,
1899 ) -> std::result::Result<Self, crate::error::Error> {
1900 let json_value = serde_json::to_value(value)
1901 .map_err(|e| crate::error::Error::tool(format!("Serialization failed: {}", e)))?;
1902 Ok(Self::json(json_value))
1903 }
1904
1905 pub fn from_list<T: serde::Serialize>(
1932 key: &str,
1933 items: &[T],
1934 ) -> std::result::Result<Self, crate::error::Error> {
1935 Self::from_serialize(&serde_json::json!({ key: items, "count": items.len() }))
1936 }
1937
1938 pub fn image(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1953 Self {
1954 content: vec![Content::Image {
1955 data: data.into(),
1956 mime_type: mime_type.into(),
1957 annotations: None,
1958 meta: None,
1959 }],
1960 is_error: false,
1961 structured_content: None,
1962 meta: None,
1963 }
1964 }
1965
1966 pub fn audio(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
1981 Self {
1982 content: vec![Content::Audio {
1983 data: data.into(),
1984 mime_type: mime_type.into(),
1985 annotations: None,
1986 meta: None,
1987 }],
1988 is_error: false,
1989 structured_content: None,
1990 meta: None,
1991 }
1992 }
1993
1994 pub fn resource_link(uri: impl Into<String>, name: impl Into<String>) -> Self {
2011 Self {
2012 content: vec![Content::ResourceLink {
2013 uri: uri.into(),
2014 name: name.into(),
2015 title: None,
2016 description: None,
2017 mime_type: None,
2018 size: None,
2019 icons: None,
2020 annotations: None,
2021 meta: None,
2022 }],
2023 is_error: false,
2024 structured_content: None,
2025 meta: None,
2026 }
2027 }
2028
2029 pub fn resource_link_with_meta(
2031 uri: impl Into<String>,
2032 name: impl Into<String>,
2033 description: Option<String>,
2034 mime_type: Option<String>,
2035 ) -> Self {
2036 Self {
2037 content: vec![Content::ResourceLink {
2038 uri: uri.into(),
2039 name: name.into(),
2040 title: None,
2041 description,
2042 mime_type,
2043 size: None,
2044 icons: None,
2045 annotations: None,
2046 meta: None,
2047 }],
2048 is_error: false,
2049 structured_content: None,
2050 meta: None,
2051 }
2052 }
2053
2054 pub fn resource(resource: ResourceContent) -> Self {
2056 Self {
2057 content: vec![Content::Resource {
2058 resource,
2059 annotations: None,
2060 meta: None,
2061 }],
2062 is_error: false,
2063 structured_content: None,
2064 meta: None,
2065 }
2066 }
2067
2068 pub fn all_text(&self) -> String {
2082 self.content.iter().filter_map(|c| c.as_text()).collect()
2083 }
2084
2085 pub fn first_text(&self) -> Option<&str> {
2098 self.content.iter().find_map(|c| c.as_text())
2099 }
2100
2101 pub fn as_json(&self) -> Option<Result<Value, serde_json::Error>> {
2118 if let Some(ref sc) = self.structured_content {
2119 return Some(Ok(sc.clone()));
2120 }
2121 self.first_text().map(serde_json::from_str)
2122 }
2123
2124 pub fn deserialize<T: DeserializeOwned>(&self) -> Option<Result<T, serde_json::Error>> {
2144 if let Some(ref sc) = self.structured_content {
2145 return Some(serde_json::from_value(sc.clone()));
2146 }
2147 self.first_text().map(serde_json::from_str)
2148 }
2149}
2150
2151#[derive(Debug, Clone, Serialize, Deserialize)]
2156#[serde(tag = "type", rename_all = "snake_case")]
2157#[non_exhaustive]
2158pub enum Content {
2159 Text {
2161 text: String,
2163 #[serde(skip_serializing_if = "Option::is_none")]
2165 annotations: Option<ContentAnnotations>,
2166 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2168 meta: Option<Value>,
2169 },
2170 Image {
2172 data: String,
2174 #[serde(rename = "mimeType")]
2176 mime_type: String,
2177 #[serde(skip_serializing_if = "Option::is_none")]
2179 annotations: Option<ContentAnnotations>,
2180 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2182 meta: Option<Value>,
2183 },
2184 Audio {
2186 data: String,
2188 #[serde(rename = "mimeType")]
2190 mime_type: String,
2191 #[serde(skip_serializing_if = "Option::is_none")]
2193 annotations: Option<ContentAnnotations>,
2194 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2196 meta: Option<Value>,
2197 },
2198 Resource {
2200 resource: ResourceContent,
2202 #[serde(skip_serializing_if = "Option::is_none")]
2204 annotations: Option<ContentAnnotations>,
2205 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2207 meta: Option<Value>,
2208 },
2209 ResourceLink {
2211 uri: String,
2213 name: String,
2215 #[serde(default, skip_serializing_if = "Option::is_none")]
2217 title: Option<String>,
2218 #[serde(skip_serializing_if = "Option::is_none")]
2220 description: Option<String>,
2221 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
2223 mime_type: Option<String>,
2224 #[serde(default, skip_serializing_if = "Option::is_none")]
2226 size: Option<u64>,
2227 #[serde(default, skip_serializing_if = "Option::is_none")]
2229 icons: Option<Vec<ToolIcon>>,
2230 #[serde(skip_serializing_if = "Option::is_none")]
2231 annotations: Option<ContentAnnotations>,
2232 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2234 meta: Option<Value>,
2235 },
2236}
2237
2238#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2240pub struct ContentAnnotations {
2241 #[serde(skip_serializing_if = "Option::is_none")]
2243 pub audience: Option<Vec<ContentRole>>,
2244 #[serde(skip_serializing_if = "Option::is_none")]
2246 pub priority: Option<f64>,
2247 #[serde(rename = "lastModified", skip_serializing_if = "Option::is_none")]
2249 pub last_modified: Option<String>,
2250}
2251
2252impl Content {
2253 pub fn text(text: impl Into<String>) -> Self {
2279 Content::Text {
2280 text: text.into(),
2281 annotations: None,
2282 meta: None,
2283 }
2284 }
2285
2286 pub fn as_text(&self) -> Option<&str> {
2299 match self {
2300 Content::Text { text, .. } => Some(text),
2301 _ => None,
2302 }
2303 }
2304}
2305
2306#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
2310#[serde(rename_all = "lowercase")]
2311#[non_exhaustive]
2312pub enum ContentRole {
2313 User,
2315 Assistant,
2317}
2318
2319#[derive(Debug, Clone, Serialize, Deserialize)]
2323#[serde(rename_all = "camelCase")]
2324pub struct ResourceContent {
2325 pub uri: String,
2327 #[serde(skip_serializing_if = "Option::is_none")]
2329 pub mime_type: Option<String>,
2330 #[serde(skip_serializing_if = "Option::is_none")]
2332 pub text: Option<String>,
2333 #[serde(skip_serializing_if = "Option::is_none")]
2335 pub blob: Option<String>,
2336 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2338 pub meta: Option<Value>,
2339}
2340
2341#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2346pub struct ListResourcesParams {
2347 #[serde(default, skip_serializing_if = "Option::is_none")]
2348 pub cursor: Option<String>,
2349 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2351 pub meta: Option<RequestMeta>,
2352}
2353
2354#[derive(Debug, Clone, Serialize, Deserialize)]
2355#[serde(rename_all = "camelCase")]
2356pub struct ListResourcesResult {
2357 pub resources: Vec<ResourceDefinition>,
2358 #[serde(default, skip_serializing_if = "Option::is_none")]
2359 pub next_cursor: Option<String>,
2360 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2362 pub meta: Option<Value>,
2363}
2364
2365#[derive(Debug, Clone, Serialize, Deserialize)]
2366#[serde(rename_all = "camelCase")]
2367pub struct ResourceDefinition {
2368 pub uri: String,
2369 pub name: String,
2370 #[serde(skip_serializing_if = "Option::is_none")]
2372 pub title: Option<String>,
2373 #[serde(skip_serializing_if = "Option::is_none")]
2374 pub description: Option<String>,
2375 #[serde(skip_serializing_if = "Option::is_none")]
2376 pub mime_type: Option<String>,
2377 #[serde(skip_serializing_if = "Option::is_none")]
2379 pub icons: Option<Vec<ToolIcon>>,
2380 #[serde(skip_serializing_if = "Option::is_none")]
2382 pub size: Option<u64>,
2383 #[serde(skip_serializing_if = "Option::is_none")]
2385 pub annotations: Option<ContentAnnotations>,
2386 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2388 pub meta: Option<Value>,
2389}
2390
2391#[derive(Debug, Clone, Serialize, Deserialize)]
2392pub struct ReadResourceParams {
2393 pub uri: String,
2394 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2396 pub meta: Option<RequestMeta>,
2397}
2398
2399#[derive(Debug, Clone, Serialize, Deserialize)]
2400pub struct ReadResourceResult {
2401 pub contents: Vec<ResourceContent>,
2402 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2404 pub meta: Option<Value>,
2405}
2406
2407impl ReadResourceResult {
2408 pub fn text(uri: impl Into<String>, content: impl Into<String>) -> Self {
2418 Self {
2419 contents: vec![ResourceContent {
2420 uri: uri.into(),
2421 mime_type: Some("text/plain".to_string()),
2422 text: Some(content.into()),
2423 blob: None,
2424 meta: None,
2425 }],
2426 meta: None,
2427 }
2428 }
2429
2430 pub fn text_with_mime(
2444 uri: impl Into<String>,
2445 content: impl Into<String>,
2446 mime_type: impl Into<String>,
2447 ) -> Self {
2448 Self {
2449 contents: vec![ResourceContent {
2450 uri: uri.into(),
2451 mime_type: Some(mime_type.into()),
2452 text: Some(content.into()),
2453 blob: None,
2454 meta: None,
2455 }],
2456 meta: None,
2457 }
2458 }
2459
2460 pub fn json<T: serde::Serialize>(uri: impl Into<String>, value: &T) -> Self {
2474 let json_string =
2475 serde_json::to_string_pretty(value).unwrap_or_else(|_| "null".to_string());
2476 Self {
2477 contents: vec![ResourceContent {
2478 uri: uri.into(),
2479 mime_type: Some("application/json".to_string()),
2480 text: Some(json_string),
2481 blob: None,
2482 meta: None,
2483 }],
2484 meta: None,
2485 }
2486 }
2487
2488 pub fn blob(uri: impl Into<String>, bytes: &[u8]) -> Self {
2499 use base64::Engine;
2500 let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
2501 Self {
2502 contents: vec![ResourceContent {
2503 uri: uri.into(),
2504 mime_type: Some("application/octet-stream".to_string()),
2505 text: None,
2506 blob: Some(encoded),
2507 meta: None,
2508 }],
2509 meta: None,
2510 }
2511 }
2512
2513 pub fn blob_with_mime(
2524 uri: impl Into<String>,
2525 bytes: &[u8],
2526 mime_type: impl Into<String>,
2527 ) -> Self {
2528 use base64::Engine;
2529 let encoded = base64::engine::general_purpose::STANDARD.encode(bytes);
2530 Self {
2531 contents: vec![ResourceContent {
2532 uri: uri.into(),
2533 mime_type: Some(mime_type.into()),
2534 text: None,
2535 blob: Some(encoded),
2536 meta: None,
2537 }],
2538 meta: None,
2539 }
2540 }
2541
2542 pub fn first_text(&self) -> Option<&str> {
2555 self.contents.first().and_then(|c| c.text.as_deref())
2556 }
2557
2558 pub fn first_uri(&self) -> Option<&str> {
2571 self.contents.first().map(|c| c.uri.as_str())
2572 }
2573
2574 pub fn as_json(&self) -> Option<Result<Value, serde_json::Error>> {
2589 self.first_text().map(serde_json::from_str)
2590 }
2591
2592 pub fn deserialize<T: DeserializeOwned>(&self) -> Option<Result<T, serde_json::Error>> {
2611 self.first_text().map(serde_json::from_str)
2612 }
2613}
2614
2615#[derive(Debug, Clone, Deserialize)]
2616pub struct SubscribeResourceParams {
2617 pub uri: String,
2618 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2620 pub meta: Option<RequestMeta>,
2621}
2622
2623#[derive(Debug, Clone, Deserialize)]
2624pub struct UnsubscribeResourceParams {
2625 pub uri: String,
2626 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2628 pub meta: Option<RequestMeta>,
2629}
2630
2631#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2633pub struct ListResourceTemplatesParams {
2634 #[serde(default)]
2636 pub cursor: Option<String>,
2637 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2639 pub meta: Option<RequestMeta>,
2640}
2641
2642#[derive(Debug, Clone, Serialize, Deserialize)]
2644#[serde(rename_all = "camelCase")]
2645pub struct ListResourceTemplatesResult {
2646 pub resource_templates: Vec<ResourceTemplateDefinition>,
2648 #[serde(skip_serializing_if = "Option::is_none")]
2650 pub next_cursor: Option<String>,
2651 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2653 pub meta: Option<Value>,
2654}
2655
2656#[derive(Debug, Clone, Serialize, Deserialize)]
2672#[serde(rename_all = "camelCase")]
2673pub struct ResourceTemplateDefinition {
2674 pub uri_template: String,
2676 pub name: String,
2678 #[serde(skip_serializing_if = "Option::is_none")]
2680 pub title: Option<String>,
2681 #[serde(skip_serializing_if = "Option::is_none")]
2683 pub description: Option<String>,
2684 #[serde(skip_serializing_if = "Option::is_none")]
2686 pub mime_type: Option<String>,
2687 #[serde(skip_serializing_if = "Option::is_none")]
2689 pub icons: Option<Vec<ToolIcon>>,
2690 #[serde(skip_serializing_if = "Option::is_none")]
2692 pub annotations: Option<ContentAnnotations>,
2693 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2695 pub arguments: Vec<PromptArgument>,
2696 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2698 pub meta: Option<Value>,
2699}
2700
2701#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2706pub struct ListPromptsParams {
2707 #[serde(default, skip_serializing_if = "Option::is_none")]
2708 pub cursor: Option<String>,
2709 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2711 pub meta: Option<RequestMeta>,
2712}
2713
2714#[derive(Debug, Clone, Serialize, Deserialize)]
2715#[serde(rename_all = "camelCase")]
2716pub struct ListPromptsResult {
2717 pub prompts: Vec<PromptDefinition>,
2718 #[serde(default, skip_serializing_if = "Option::is_none")]
2719 pub next_cursor: Option<String>,
2720 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2722 pub meta: Option<Value>,
2723}
2724
2725#[derive(Debug, Clone, Serialize, Deserialize)]
2726pub struct PromptDefinition {
2727 pub name: String,
2728 #[serde(skip_serializing_if = "Option::is_none")]
2730 pub title: Option<String>,
2731 #[serde(skip_serializing_if = "Option::is_none")]
2732 pub description: Option<String>,
2733 #[serde(skip_serializing_if = "Option::is_none")]
2735 pub icons: Option<Vec<ToolIcon>>,
2736 #[serde(default, skip_serializing_if = "Vec::is_empty")]
2737 pub arguments: Vec<PromptArgument>,
2738 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2740 pub meta: Option<Value>,
2741}
2742
2743#[derive(Debug, Clone, Serialize, Deserialize)]
2744pub struct PromptArgument {
2745 pub name: String,
2746 #[serde(skip_serializing_if = "Option::is_none")]
2747 pub description: Option<String>,
2748 #[serde(default)]
2749 pub required: bool,
2750}
2751
2752#[derive(Debug, Clone, Serialize, Deserialize)]
2753pub struct GetPromptParams {
2754 pub name: String,
2755 #[serde(default)]
2756 pub arguments: std::collections::HashMap<String, String>,
2757 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2759 pub meta: Option<RequestMeta>,
2760}
2761
2762#[derive(Debug, Clone, Serialize, Deserialize)]
2763pub struct GetPromptResult {
2828 #[serde(default, skip_serializing_if = "Option::is_none")]
2829 pub description: Option<String>,
2830 pub messages: Vec<PromptMessage>,
2831 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2833 pub meta: Option<Value>,
2834}
2835
2836impl GetPromptResult {
2837 pub fn user_message(text: impl Into<String>) -> Self {
2847 Self {
2848 description: None,
2849 messages: vec![PromptMessage {
2850 role: PromptRole::User,
2851 content: Content::Text {
2852 text: text.into(),
2853 annotations: None,
2854 meta: None,
2855 },
2856 meta: None,
2857 }],
2858 meta: None,
2859 }
2860 }
2861
2862 pub fn user_message_with_description(
2875 text: impl Into<String>,
2876 description: impl Into<String>,
2877 ) -> Self {
2878 Self {
2879 description: Some(description.into()),
2880 messages: vec![PromptMessage {
2881 role: PromptRole::User,
2882 content: Content::Text {
2883 text: text.into(),
2884 annotations: None,
2885 meta: None,
2886 },
2887 meta: None,
2888 }],
2889 meta: None,
2890 }
2891 }
2892
2893 pub fn assistant_message(text: impl Into<String>) -> Self {
2903 Self {
2904 description: None,
2905 messages: vec![PromptMessage {
2906 role: PromptRole::Assistant,
2907 content: Content::Text {
2908 text: text.into(),
2909 annotations: None,
2910 meta: None,
2911 },
2912 meta: None,
2913 }],
2914 meta: None,
2915 }
2916 }
2917
2918 pub fn builder() -> GetPromptResultBuilder {
2933 GetPromptResultBuilder::new()
2934 }
2935
2936 pub fn first_message_text(&self) -> Option<&str> {
2950 self.messages.first().and_then(|m| m.content.as_text())
2951 }
2952
2953 pub fn as_json(&self) -> Option<Result<Value, serde_json::Error>> {
2968 self.first_message_text().map(serde_json::from_str)
2969 }
2970
2971 pub fn deserialize<T: DeserializeOwned>(&self) -> Option<Result<T, serde_json::Error>> {
2990 self.first_message_text().map(serde_json::from_str)
2991 }
2992}
2993
2994#[derive(Debug, Clone, Default)]
2996pub struct GetPromptResultBuilder {
2997 description: Option<String>,
2998 messages: Vec<PromptMessage>,
2999}
3000
3001impl GetPromptResultBuilder {
3002 pub fn new() -> Self {
3004 Self::default()
3005 }
3006
3007 pub fn description(mut self, description: impl Into<String>) -> Self {
3009 self.description = Some(description.into());
3010 self
3011 }
3012
3013 pub fn user(mut self, text: impl Into<String>) -> Self {
3015 self.messages.push(PromptMessage {
3016 role: PromptRole::User,
3017 content: Content::Text {
3018 text: text.into(),
3019 annotations: None,
3020 meta: None,
3021 },
3022 meta: None,
3023 });
3024 self
3025 }
3026
3027 pub fn assistant(mut self, text: impl Into<String>) -> Self {
3029 self.messages.push(PromptMessage {
3030 role: PromptRole::Assistant,
3031 content: Content::Text {
3032 text: text.into(),
3033 annotations: None,
3034 meta: None,
3035 },
3036 meta: None,
3037 });
3038 self
3039 }
3040
3041 pub fn build(self) -> GetPromptResult {
3043 GetPromptResult {
3044 description: self.description,
3045 messages: self.messages,
3046 meta: None,
3047 }
3048 }
3049}
3050
3051#[derive(Debug, Clone, Serialize, Deserialize)]
3052pub struct PromptMessage {
3053 pub role: PromptRole,
3054 pub content: Content,
3055 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3057 pub meta: Option<Value>,
3058}
3059
3060#[derive(Debug, Clone, Serialize, Deserialize)]
3061#[serde(rename_all = "lowercase")]
3062#[non_exhaustive]
3063pub enum PromptRole {
3064 User,
3065 Assistant,
3066}
3067
3068#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
3074#[serde(rename_all = "camelCase")]
3075#[non_exhaustive]
3076pub enum TaskSupportMode {
3077 Required,
3079 Optional,
3081 #[default]
3083 Forbidden,
3084}
3085
3086#[derive(Debug, Clone, Serialize, Deserialize)]
3088#[serde(rename_all = "camelCase")]
3089pub struct ToolExecution {
3090 #[serde(default, skip_serializing_if = "Option::is_none")]
3092 pub task_support: Option<TaskSupportMode>,
3093}
3094
3095#[derive(Debug, Clone, Serialize, Deserialize)]
3097#[serde(rename_all = "camelCase")]
3098pub struct TaskRequestParams {
3099 #[serde(default, skip_serializing_if = "Option::is_none")]
3101 pub ttl: Option<u64>,
3102}
3103
3104#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
3106#[serde(rename_all = "snake_case")]
3107#[non_exhaustive]
3108pub enum TaskStatus {
3109 Working,
3111 InputRequired,
3113 Completed,
3115 Failed,
3117 Cancelled,
3119}
3120
3121impl std::fmt::Display for TaskStatus {
3122 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3123 match self {
3124 TaskStatus::Working => write!(f, "working"),
3125 TaskStatus::InputRequired => write!(f, "input_required"),
3126 TaskStatus::Completed => write!(f, "completed"),
3127 TaskStatus::Failed => write!(f, "failed"),
3128 TaskStatus::Cancelled => write!(f, "cancelled"),
3129 }
3130 }
3131}
3132
3133impl TaskStatus {
3134 pub fn is_terminal(&self) -> bool {
3136 matches!(
3137 self,
3138 TaskStatus::Completed | TaskStatus::Failed | TaskStatus::Cancelled
3139 )
3140 }
3141}
3142
3143#[derive(Debug, Clone, Serialize, Deserialize)]
3145#[serde(rename_all = "camelCase")]
3146pub struct TaskObject {
3147 pub task_id: String,
3149 pub status: TaskStatus,
3151 #[serde(skip_serializing_if = "Option::is_none")]
3153 pub status_message: Option<String>,
3154 pub created_at: String,
3156 pub last_updated_at: String,
3158 pub ttl: Option<u64>,
3160 #[serde(skip_serializing_if = "Option::is_none")]
3162 pub poll_interval: Option<u64>,
3163 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3165 pub meta: Option<Value>,
3166}
3167
3168#[deprecated(note = "Use TaskObject instead")]
3170pub type TaskInfo = TaskObject;
3171
3172#[derive(Debug, Clone, Serialize, Deserialize)]
3174#[serde(rename_all = "camelCase")]
3175pub struct CreateTaskResult {
3176 pub task: TaskObject,
3178 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3180 pub meta: Option<Value>,
3181}
3182
3183#[derive(Debug, Clone, Default, Deserialize)]
3185#[serde(rename_all = "camelCase")]
3186pub struct ListTasksParams {
3187 #[serde(default)]
3189 pub status: Option<TaskStatus>,
3190 #[serde(default)]
3192 pub cursor: Option<String>,
3193 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3195 pub meta: Option<RequestMeta>,
3196}
3197
3198#[derive(Debug, Clone, Serialize, Deserialize)]
3200#[serde(rename_all = "camelCase")]
3201pub struct ListTasksResult {
3202 pub tasks: Vec<TaskObject>,
3204 #[serde(skip_serializing_if = "Option::is_none")]
3206 pub next_cursor: Option<String>,
3207}
3208
3209#[derive(Debug, Clone, Deserialize)]
3211#[serde(rename_all = "camelCase")]
3212pub struct GetTaskInfoParams {
3213 pub task_id: String,
3215 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3217 pub meta: Option<RequestMeta>,
3218}
3219
3220#[derive(Debug, Clone, Deserialize)]
3222#[serde(rename_all = "camelCase")]
3223pub struct GetTaskResultParams {
3224 pub task_id: String,
3226 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3228 pub meta: Option<RequestMeta>,
3229}
3230
3231#[derive(Debug, Clone, Deserialize)]
3233#[serde(rename_all = "camelCase")]
3234pub struct CancelTaskParams {
3235 pub task_id: String,
3237 #[serde(default)]
3239 pub reason: Option<String>,
3240 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3242 pub meta: Option<RequestMeta>,
3243}
3244
3245#[derive(Debug, Clone, Serialize, Deserialize)]
3250#[serde(rename_all = "camelCase")]
3251pub struct TaskStatusParams {
3252 pub task_id: String,
3254 pub status: TaskStatus,
3256 #[serde(skip_serializing_if = "Option::is_none")]
3258 pub status_message: Option<String>,
3259 pub created_at: String,
3261 pub last_updated_at: String,
3263 pub ttl: Option<u64>,
3265 #[serde(skip_serializing_if = "Option::is_none")]
3267 pub poll_interval: Option<u64>,
3268 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3270 pub meta: Option<Value>,
3271}
3272
3273pub type TaskStatusChangedParams = TaskStatusParams;
3275
3276#[derive(Debug, Clone, Serialize, Deserialize)]
3282#[serde(rename_all = "camelCase")]
3283pub struct ElicitFormParams {
3284 #[serde(default, skip_serializing_if = "Option::is_none")]
3286 pub mode: Option<ElicitMode>,
3287 pub message: String,
3289 pub requested_schema: ElicitFormSchema,
3291 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3293 pub meta: Option<RequestMeta>,
3294}
3295
3296#[derive(Debug, Clone, Serialize, Deserialize)]
3317#[serde(rename_all = "camelCase")]
3318pub struct ElicitUrlParams {
3319 #[serde(default, skip_serializing_if = "Option::is_none")]
3321 pub mode: Option<ElicitMode>,
3322 pub elicitation_id: String,
3324 pub message: String,
3326 pub url: String,
3328 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3330 pub meta: Option<RequestMeta>,
3331}
3332
3333#[derive(Debug, Clone, Serialize, Deserialize)]
3335#[serde(untagged)]
3336#[non_exhaustive]
3337pub enum ElicitRequestParams {
3338 Form(ElicitFormParams),
3339 Url(ElicitUrlParams),
3340}
3341
3342#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
3344#[serde(rename_all = "lowercase")]
3345#[non_exhaustive]
3346pub enum ElicitMode {
3347 Form,
3349 Url,
3351}
3352
3353#[derive(Debug, Clone, Serialize, Deserialize)]
3393pub struct ElicitFormSchema {
3394 #[serde(rename = "type")]
3396 pub schema_type: String,
3397 pub properties: std::collections::HashMap<String, PrimitiveSchemaDefinition>,
3399 #[serde(default, skip_serializing_if = "Vec::is_empty")]
3401 pub required: Vec<String>,
3402}
3403
3404impl ElicitFormSchema {
3405 pub fn new() -> Self {
3407 Self {
3408 schema_type: "object".to_string(),
3409 properties: std::collections::HashMap::new(),
3410 required: Vec::new(),
3411 }
3412 }
3413
3414 pub fn string_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
3416 self.properties.insert(
3417 name.to_string(),
3418 PrimitiveSchemaDefinition::String(StringSchema {
3419 schema_type: "string".to_string(),
3420 title: None,
3421 description: description.map(|s| s.to_string()),
3422 format: None,
3423 pattern: None,
3424 min_length: None,
3425 max_length: None,
3426 default: None,
3427 }),
3428 );
3429 if required {
3430 self.required.push(name.to_string());
3431 }
3432 self
3433 }
3434
3435 pub fn string_field_with_default(
3437 mut self,
3438 name: &str,
3439 description: Option<&str>,
3440 required: bool,
3441 default: &str,
3442 ) -> Self {
3443 self.properties.insert(
3444 name.to_string(),
3445 PrimitiveSchemaDefinition::String(StringSchema {
3446 schema_type: "string".to_string(),
3447 title: None,
3448 description: description.map(|s| s.to_string()),
3449 format: None,
3450 pattern: None,
3451 min_length: None,
3452 max_length: None,
3453 default: Some(default.to_string()),
3454 }),
3455 );
3456 if required {
3457 self.required.push(name.to_string());
3458 }
3459 self
3460 }
3461
3462 pub fn integer_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
3464 self.properties.insert(
3465 name.to_string(),
3466 PrimitiveSchemaDefinition::Integer(IntegerSchema {
3467 schema_type: "integer".to_string(),
3468 title: None,
3469 description: description.map(|s| s.to_string()),
3470 minimum: None,
3471 maximum: None,
3472 default: None,
3473 }),
3474 );
3475 if required {
3476 self.required.push(name.to_string());
3477 }
3478 self
3479 }
3480
3481 pub fn integer_field_with_default(
3483 mut self,
3484 name: &str,
3485 description: Option<&str>,
3486 required: bool,
3487 default: i64,
3488 ) -> Self {
3489 self.properties.insert(
3490 name.to_string(),
3491 PrimitiveSchemaDefinition::Integer(IntegerSchema {
3492 schema_type: "integer".to_string(),
3493 title: None,
3494 description: description.map(|s| s.to_string()),
3495 minimum: None,
3496 maximum: None,
3497 default: Some(default),
3498 }),
3499 );
3500 if required {
3501 self.required.push(name.to_string());
3502 }
3503 self
3504 }
3505
3506 pub fn number_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
3508 self.properties.insert(
3509 name.to_string(),
3510 PrimitiveSchemaDefinition::Number(NumberSchema {
3511 schema_type: "number".to_string(),
3512 title: None,
3513 description: description.map(|s| s.to_string()),
3514 minimum: None,
3515 maximum: None,
3516 default: None,
3517 }),
3518 );
3519 if required {
3520 self.required.push(name.to_string());
3521 }
3522 self
3523 }
3524
3525 pub fn number_field_with_default(
3527 mut self,
3528 name: &str,
3529 description: Option<&str>,
3530 required: bool,
3531 default: f64,
3532 ) -> Self {
3533 self.properties.insert(
3534 name.to_string(),
3535 PrimitiveSchemaDefinition::Number(NumberSchema {
3536 schema_type: "number".to_string(),
3537 title: None,
3538 description: description.map(|s| s.to_string()),
3539 minimum: None,
3540 maximum: None,
3541 default: Some(default),
3542 }),
3543 );
3544 if required {
3545 self.required.push(name.to_string());
3546 }
3547 self
3548 }
3549
3550 pub fn boolean_field(mut self, name: &str, description: Option<&str>, required: bool) -> Self {
3552 self.properties.insert(
3553 name.to_string(),
3554 PrimitiveSchemaDefinition::Boolean(BooleanSchema {
3555 schema_type: "boolean".to_string(),
3556 title: None,
3557 description: description.map(|s| s.to_string()),
3558 default: None,
3559 }),
3560 );
3561 if required {
3562 self.required.push(name.to_string());
3563 }
3564 self
3565 }
3566
3567 pub fn boolean_field_with_default(
3569 mut self,
3570 name: &str,
3571 description: Option<&str>,
3572 required: bool,
3573 default: bool,
3574 ) -> Self {
3575 self.properties.insert(
3576 name.to_string(),
3577 PrimitiveSchemaDefinition::Boolean(BooleanSchema {
3578 schema_type: "boolean".to_string(),
3579 title: None,
3580 description: description.map(|s| s.to_string()),
3581 default: Some(default),
3582 }),
3583 );
3584 if required {
3585 self.required.push(name.to_string());
3586 }
3587 self
3588 }
3589
3590 pub fn enum_field(
3592 mut self,
3593 name: &str,
3594 description: Option<&str>,
3595 options: Vec<String>,
3596 required: bool,
3597 ) -> Self {
3598 self.properties.insert(
3599 name.to_string(),
3600 PrimitiveSchemaDefinition::SingleSelectEnum(SingleSelectEnumSchema {
3601 schema_type: "string".to_string(),
3602 title: None,
3603 description: description.map(|s| s.to_string()),
3604 enum_values: options,
3605 default: None,
3606 }),
3607 );
3608 if required {
3609 self.required.push(name.to_string());
3610 }
3611 self
3612 }
3613
3614 pub fn enum_field_with_default(
3616 mut self,
3617 name: &str,
3618 description: Option<&str>,
3619 required: bool,
3620 options: &[&str],
3621 default: &str,
3622 ) -> Self {
3623 self.properties.insert(
3624 name.to_string(),
3625 PrimitiveSchemaDefinition::SingleSelectEnum(SingleSelectEnumSchema {
3626 schema_type: "string".to_string(),
3627 title: None,
3628 description: description.map(|s| s.to_string()),
3629 enum_values: options.iter().map(|s| s.to_string()).collect(),
3630 default: Some(default.to_string()),
3631 }),
3632 );
3633 if required {
3634 self.required.push(name.to_string());
3635 }
3636 self
3637 }
3638
3639 pub fn raw_field(mut self, name: &str, schema: serde_json::Value, required: bool) -> Self {
3643 self.properties
3644 .insert(name.to_string(), PrimitiveSchemaDefinition::Raw(schema));
3645 if required {
3646 self.required.push(name.to_string());
3647 }
3648 self
3649 }
3650}
3651
3652impl Default for ElicitFormSchema {
3653 fn default() -> Self {
3654 Self::new()
3655 }
3656}
3657
3658#[derive(Debug, Clone, Serialize, Deserialize)]
3660#[serde(untagged)]
3661#[non_exhaustive]
3662pub enum PrimitiveSchemaDefinition {
3663 String(StringSchema),
3665 Integer(IntegerSchema),
3667 Number(NumberSchema),
3669 Boolean(BooleanSchema),
3671 SingleSelectEnum(SingleSelectEnumSchema),
3673 MultiSelectEnum(MultiSelectEnumSchema),
3675 Raw(serde_json::Value),
3677}
3678
3679#[derive(Debug, Clone, Serialize, Deserialize)]
3681#[serde(rename_all = "camelCase")]
3682pub struct StringSchema {
3683 #[serde(rename = "type")]
3684 pub schema_type: String,
3685 #[serde(skip_serializing_if = "Option::is_none")]
3687 pub title: Option<String>,
3688 #[serde(skip_serializing_if = "Option::is_none")]
3689 pub description: Option<String>,
3690 #[serde(skip_serializing_if = "Option::is_none")]
3691 pub format: Option<String>,
3692 #[serde(skip_serializing_if = "Option::is_none")]
3694 pub pattern: Option<String>,
3695 #[serde(skip_serializing_if = "Option::is_none")]
3696 pub min_length: Option<u64>,
3697 #[serde(skip_serializing_if = "Option::is_none")]
3698 pub max_length: Option<u64>,
3699 #[serde(skip_serializing_if = "Option::is_none")]
3701 pub default: Option<String>,
3702}
3703
3704#[derive(Debug, Clone, Serialize, Deserialize)]
3706#[serde(rename_all = "camelCase")]
3707pub struct IntegerSchema {
3708 #[serde(rename = "type")]
3709 pub schema_type: String,
3710 #[serde(skip_serializing_if = "Option::is_none")]
3712 pub title: Option<String>,
3713 #[serde(skip_serializing_if = "Option::is_none")]
3714 pub description: Option<String>,
3715 #[serde(skip_serializing_if = "Option::is_none")]
3716 pub minimum: Option<i64>,
3717 #[serde(skip_serializing_if = "Option::is_none")]
3718 pub maximum: Option<i64>,
3719 #[serde(skip_serializing_if = "Option::is_none")]
3721 pub default: Option<i64>,
3722}
3723
3724#[derive(Debug, Clone, Serialize, Deserialize)]
3726#[serde(rename_all = "camelCase")]
3727pub struct NumberSchema {
3728 #[serde(rename = "type")]
3729 pub schema_type: String,
3730 #[serde(skip_serializing_if = "Option::is_none")]
3732 pub title: Option<String>,
3733 #[serde(skip_serializing_if = "Option::is_none")]
3734 pub description: Option<String>,
3735 #[serde(skip_serializing_if = "Option::is_none")]
3736 pub minimum: Option<f64>,
3737 #[serde(skip_serializing_if = "Option::is_none")]
3738 pub maximum: Option<f64>,
3739 #[serde(skip_serializing_if = "Option::is_none")]
3741 pub default: Option<f64>,
3742}
3743
3744#[derive(Debug, Clone, Serialize, Deserialize)]
3746#[serde(rename_all = "camelCase")]
3747pub struct BooleanSchema {
3748 #[serde(rename = "type")]
3749 pub schema_type: String,
3750 #[serde(skip_serializing_if = "Option::is_none")]
3752 pub title: Option<String>,
3753 #[serde(skip_serializing_if = "Option::is_none")]
3754 pub description: Option<String>,
3755 #[serde(skip_serializing_if = "Option::is_none")]
3757 pub default: Option<bool>,
3758}
3759
3760#[derive(Debug, Clone, Serialize, Deserialize)]
3762#[serde(rename_all = "camelCase")]
3763pub struct SingleSelectEnumSchema {
3764 #[serde(rename = "type")]
3765 pub schema_type: String,
3766 #[serde(skip_serializing_if = "Option::is_none")]
3768 pub title: Option<String>,
3769 #[serde(skip_serializing_if = "Option::is_none")]
3770 pub description: Option<String>,
3771 #[serde(rename = "enum")]
3772 pub enum_values: Vec<String>,
3773 #[serde(skip_serializing_if = "Option::is_none")]
3775 pub default: Option<String>,
3776}
3777
3778#[derive(Debug, Clone, Serialize, Deserialize)]
3780#[serde(rename_all = "camelCase")]
3781pub struct MultiSelectEnumSchema {
3782 #[serde(rename = "type")]
3783 pub schema_type: String,
3784 #[serde(skip_serializing_if = "Option::is_none")]
3786 pub title: Option<String>,
3787 #[serde(skip_serializing_if = "Option::is_none")]
3788 pub description: Option<String>,
3789 pub items: MultiSelectEnumItems,
3790 #[serde(skip_serializing_if = "Option::is_none")]
3791 pub unique_items: Option<bool>,
3792 #[serde(skip_serializing_if = "Option::is_none")]
3794 pub default: Option<Vec<String>>,
3795}
3796
3797#[derive(Debug, Clone, Serialize, Deserialize)]
3799pub struct MultiSelectEnumItems {
3800 #[serde(rename = "type")]
3801 pub schema_type: String,
3802 #[serde(rename = "enum")]
3803 pub enum_values: Vec<String>,
3804}
3805
3806#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
3808#[serde(rename_all = "lowercase")]
3809#[non_exhaustive]
3810pub enum ElicitAction {
3811 Accept,
3813 Decline,
3815 Cancel,
3817}
3818
3819#[derive(Debug, Clone, Serialize, Deserialize)]
3821pub struct ElicitResult {
3822 pub action: ElicitAction,
3824 #[serde(default, skip_serializing_if = "Option::is_none")]
3826 pub content: Option<std::collections::HashMap<String, ElicitFieldValue>>,
3827 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3829 pub meta: Option<Value>,
3830}
3831
3832impl ElicitResult {
3833 pub fn accept(content: std::collections::HashMap<String, ElicitFieldValue>) -> Self {
3835 Self {
3836 action: ElicitAction::Accept,
3837 content: Some(content),
3838 meta: None,
3839 }
3840 }
3841
3842 pub fn decline() -> Self {
3844 Self {
3845 action: ElicitAction::Decline,
3846 content: None,
3847 meta: None,
3848 }
3849 }
3850
3851 pub fn cancel() -> Self {
3853 Self {
3854 action: ElicitAction::Cancel,
3855 content: None,
3856 meta: None,
3857 }
3858 }
3859}
3860
3861#[derive(Debug, Clone, Serialize, Deserialize)]
3863#[serde(untagged)]
3864#[non_exhaustive]
3865pub enum ElicitFieldValue {
3866 String(String),
3867 Number(f64),
3868 Integer(i64),
3869 Boolean(bool),
3870 StringArray(Vec<String>),
3871}
3872
3873#[derive(Debug, Clone, Serialize, Deserialize)]
3875#[serde(rename_all = "camelCase")]
3876pub struct ElicitationCompleteParams {
3877 pub elicitation_id: String,
3879 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3881 pub meta: Option<Value>,
3882}
3883
3884#[derive(Debug, Clone, Default, Serialize, Deserialize)]
3889pub struct EmptyResult {}
3890
3891impl McpRequest {
3896 pub fn from_jsonrpc(req: &JsonRpcRequest) -> Result<Self, crate::error::Error> {
3898 let params = req
3899 .params
3900 .clone()
3901 .unwrap_or(Value::Object(Default::default()));
3902
3903 match req.method.as_str() {
3904 "initialize" => {
3905 let p: InitializeParams = serde_json::from_value(params)?;
3906 Ok(McpRequest::Initialize(p))
3907 }
3908 "tools/list" => {
3909 let p: ListToolsParams = serde_json::from_value(params).unwrap_or_default();
3910 Ok(McpRequest::ListTools(p))
3911 }
3912 "tools/call" => {
3913 let p: CallToolParams = serde_json::from_value(params)?;
3914 Ok(McpRequest::CallTool(p))
3915 }
3916 "resources/list" => {
3917 let p: ListResourcesParams = serde_json::from_value(params).unwrap_or_default();
3918 Ok(McpRequest::ListResources(p))
3919 }
3920 "resources/templates/list" => {
3921 let p: ListResourceTemplatesParams =
3922 serde_json::from_value(params).unwrap_or_default();
3923 Ok(McpRequest::ListResourceTemplates(p))
3924 }
3925 "resources/read" => {
3926 let p: ReadResourceParams = serde_json::from_value(params)?;
3927 Ok(McpRequest::ReadResource(p))
3928 }
3929 "resources/subscribe" => {
3930 let p: SubscribeResourceParams = serde_json::from_value(params)?;
3931 Ok(McpRequest::SubscribeResource(p))
3932 }
3933 "resources/unsubscribe" => {
3934 let p: UnsubscribeResourceParams = serde_json::from_value(params)?;
3935 Ok(McpRequest::UnsubscribeResource(p))
3936 }
3937 "prompts/list" => {
3938 let p: ListPromptsParams = serde_json::from_value(params).unwrap_or_default();
3939 Ok(McpRequest::ListPrompts(p))
3940 }
3941 "prompts/get" => {
3942 let p: GetPromptParams = serde_json::from_value(params)?;
3943 Ok(McpRequest::GetPrompt(p))
3944 }
3945 "tasks/list" => {
3946 let p: ListTasksParams = serde_json::from_value(params).unwrap_or_default();
3947 Ok(McpRequest::ListTasks(p))
3948 }
3949 "tasks/get" => {
3950 let p: GetTaskInfoParams = serde_json::from_value(params)?;
3951 Ok(McpRequest::GetTaskInfo(p))
3952 }
3953 "tasks/result" => {
3954 let p: GetTaskResultParams = serde_json::from_value(params)?;
3955 Ok(McpRequest::GetTaskResult(p))
3956 }
3957 "tasks/cancel" => {
3958 let p: CancelTaskParams = serde_json::from_value(params)?;
3959 Ok(McpRequest::CancelTask(p))
3960 }
3961 "ping" => Ok(McpRequest::Ping),
3962 "logging/setLevel" => {
3963 let p: SetLogLevelParams = serde_json::from_value(params)?;
3964 Ok(McpRequest::SetLoggingLevel(p))
3965 }
3966 "completion/complete" => {
3967 let p: CompleteParams = serde_json::from_value(params)?;
3968 Ok(McpRequest::Complete(p))
3969 }
3970 method => Ok(McpRequest::Unknown {
3971 method: method.to_string(),
3972 params: req.params.clone(),
3973 }),
3974 }
3975 }
3976}
3977
3978impl McpNotification {
3979 pub fn from_jsonrpc(notif: &JsonRpcNotification) -> Result<Self, crate::error::Error> {
3981 let params = notif
3982 .params
3983 .clone()
3984 .unwrap_or(Value::Object(Default::default()));
3985
3986 match notif.method.as_str() {
3987 notifications::INITIALIZED => Ok(McpNotification::Initialized),
3988 notifications::CANCELLED => {
3989 let p: CancelledParams = serde_json::from_value(params)?;
3990 Ok(McpNotification::Cancelled(p))
3991 }
3992 notifications::PROGRESS => {
3993 let p: ProgressParams = serde_json::from_value(params)?;
3994 Ok(McpNotification::Progress(p))
3995 }
3996 notifications::ROOTS_LIST_CHANGED => Ok(McpNotification::RootsListChanged),
3997 method => Ok(McpNotification::Unknown {
3998 method: method.to_string(),
3999 params: notif.params.clone(),
4000 }),
4001 }
4002 }
4003}
4004
4005#[cfg(test)]
4006mod tests {
4007 use super::*;
4008
4009 #[test]
4010 fn test_content_text_constructor() {
4011 let content = Content::text("hello world");
4012 assert_eq!(content.as_text(), Some("hello world"));
4013
4014 match &content {
4016 Content::Text {
4017 text, annotations, ..
4018 } => {
4019 assert_eq!(text, "hello world");
4020 assert!(annotations.is_none());
4021 }
4022 _ => panic!("expected Content::Text"),
4023 }
4024
4025 let content = Content::text(String::from("owned"));
4027 assert_eq!(content.as_text(), Some("owned"));
4028 }
4029
4030 #[test]
4031 fn test_elicit_form_schema_builder() {
4032 let schema = ElicitFormSchema::new()
4033 .string_field("name", Some("Your name"), true)
4034 .number_field("age", Some("Your age"), false)
4035 .boolean_field("agree", Some("Do you agree?"), true)
4036 .enum_field(
4037 "color",
4038 Some("Favorite color"),
4039 vec!["red".to_string(), "green".to_string(), "blue".to_string()],
4040 false,
4041 );
4042
4043 assert_eq!(schema.schema_type, "object");
4044 assert_eq!(schema.properties.len(), 4);
4045 assert_eq!(schema.required.len(), 2);
4046 assert!(schema.required.contains(&"name".to_string()));
4047 assert!(schema.required.contains(&"agree".to_string()));
4048 }
4049
4050 #[test]
4051 fn test_elicit_form_schema_serialization() {
4052 let schema = ElicitFormSchema::new().string_field("username", Some("Enter username"), true);
4053
4054 let json = serde_json::to_value(&schema).unwrap();
4055 assert_eq!(json["type"], "object");
4056 assert!(json["properties"]["username"]["type"] == "string");
4057 assert!(
4058 json["required"]
4059 .as_array()
4060 .unwrap()
4061 .contains(&serde_json::json!("username"))
4062 );
4063 }
4064
4065 #[test]
4066 fn test_elicit_result_accept() {
4067 let mut content = std::collections::HashMap::new();
4068 content.insert(
4069 "name".to_string(),
4070 ElicitFieldValue::String("Alice".to_string()),
4071 );
4072 content.insert("age".to_string(), ElicitFieldValue::Integer(30));
4073
4074 let result = ElicitResult::accept(content);
4075 assert_eq!(result.action, ElicitAction::Accept);
4076 assert!(result.content.is_some());
4077 }
4078
4079 #[test]
4080 fn test_elicit_result_decline() {
4081 let result = ElicitResult::decline();
4082 assert_eq!(result.action, ElicitAction::Decline);
4083 assert!(result.content.is_none());
4084 }
4085
4086 #[test]
4087 fn test_elicit_result_cancel() {
4088 let result = ElicitResult::cancel();
4089 assert_eq!(result.action, ElicitAction::Cancel);
4090 assert!(result.content.is_none());
4091 }
4092
4093 #[test]
4094 fn test_elicit_mode_serialization() {
4095 assert_eq!(
4096 serde_json::to_string(&ElicitMode::Form).unwrap(),
4097 "\"form\""
4098 );
4099 assert_eq!(serde_json::to_string(&ElicitMode::Url).unwrap(), "\"url\"");
4100 }
4101
4102 #[test]
4103 fn test_elicit_action_serialization() {
4104 assert_eq!(
4105 serde_json::to_string(&ElicitAction::Accept).unwrap(),
4106 "\"accept\""
4107 );
4108 assert_eq!(
4109 serde_json::to_string(&ElicitAction::Decline).unwrap(),
4110 "\"decline\""
4111 );
4112 assert_eq!(
4113 serde_json::to_string(&ElicitAction::Cancel).unwrap(),
4114 "\"cancel\""
4115 );
4116 }
4117
4118 #[test]
4119 fn test_elicitation_capability() {
4120 let cap = ElicitationCapability {
4121 form: Some(ElicitationFormCapability {}),
4122 url: None,
4123 };
4124
4125 let json = serde_json::to_value(&cap).unwrap();
4126 assert!(json["form"].is_object());
4127 assert!(json.get("url").is_none());
4128 }
4129
4130 #[test]
4131 fn test_client_capabilities_with_elicitation() {
4132 let caps = ClientCapabilities {
4133 roots: None,
4134 sampling: None,
4135 elicitation: Some(ElicitationCapability {
4136 form: Some(ElicitationFormCapability {}),
4137 url: Some(ElicitationUrlCapability {}),
4138 }),
4139 tasks: None,
4140 experimental: None,
4141 extensions: None,
4142 };
4143
4144 let json = serde_json::to_value(&caps).unwrap();
4145 assert!(json["elicitation"]["form"].is_object());
4146 assert!(json["elicitation"]["url"].is_object());
4147 }
4148
4149 #[test]
4150 fn test_elicit_url_params() {
4151 let params = ElicitUrlParams {
4152 mode: Some(ElicitMode::Url),
4153 elicitation_id: "abc123".to_string(),
4154 message: "Please authorize".to_string(),
4155 url: "https://example.com/auth".to_string(),
4156 meta: None,
4157 };
4158
4159 let json = serde_json::to_value(¶ms).unwrap();
4160 assert_eq!(json["mode"], "url");
4161 assert_eq!(json["elicitationId"], "abc123");
4162 assert_eq!(json["message"], "Please authorize");
4163 assert_eq!(json["url"], "https://example.com/auth");
4164 }
4165
4166 #[test]
4167 fn test_elicitation_complete_params() {
4168 let params = ElicitationCompleteParams {
4169 elicitation_id: "xyz789".to_string(),
4170 meta: None,
4171 };
4172
4173 let json = serde_json::to_value(¶ms).unwrap();
4174 assert_eq!(json["elicitationId"], "xyz789");
4175 }
4176
4177 #[test]
4178 fn test_root_new() {
4179 let root = Root::new("file:///home/user/project");
4180 assert_eq!(root.uri, "file:///home/user/project");
4181 assert!(root.name.is_none());
4182 }
4183
4184 #[test]
4185 fn test_root_with_name() {
4186 let root = Root::with_name("file:///home/user/project", "My Project");
4187 assert_eq!(root.uri, "file:///home/user/project");
4188 assert_eq!(root.name.as_deref(), Some("My Project"));
4189 }
4190
4191 #[test]
4192 fn test_root_serialization() {
4193 let root = Root::with_name("file:///workspace", "Workspace");
4194 let json = serde_json::to_value(&root).unwrap();
4195 assert_eq!(json["uri"], "file:///workspace");
4196 assert_eq!(json["name"], "Workspace");
4197 }
4198
4199 #[test]
4200 fn test_root_serialization_without_name() {
4201 let root = Root::new("file:///workspace");
4202 let json = serde_json::to_value(&root).unwrap();
4203 assert_eq!(json["uri"], "file:///workspace");
4204 assert!(json.get("name").is_none());
4205 }
4206
4207 #[test]
4208 fn test_root_deserialization() {
4209 let json = serde_json::json!({
4210 "uri": "file:///home/user",
4211 "name": "Home"
4212 });
4213 let root: Root = serde_json::from_value(json).unwrap();
4214 assert_eq!(root.uri, "file:///home/user");
4215 assert_eq!(root.name.as_deref(), Some("Home"));
4216 }
4217
4218 #[test]
4219 fn test_list_roots_result() {
4220 let result = ListRootsResult {
4221 roots: vec![
4222 Root::new("file:///project1"),
4223 Root::with_name("file:///project2", "Project 2"),
4224 ],
4225 meta: None,
4226 };
4227
4228 let json = serde_json::to_value(&result).unwrap();
4229 let roots = json["roots"].as_array().unwrap();
4230 assert_eq!(roots.len(), 2);
4231 assert_eq!(roots[0]["uri"], "file:///project1");
4232 assert_eq!(roots[1]["name"], "Project 2");
4233 }
4234
4235 #[test]
4236 fn test_roots_capability_serialization() {
4237 let cap = RootsCapability { list_changed: true };
4238 let json = serde_json::to_value(&cap).unwrap();
4239 assert_eq!(json["listChanged"], true);
4240 }
4241
4242 #[test]
4243 fn test_client_capabilities_with_roots() {
4244 let caps = ClientCapabilities {
4245 roots: Some(RootsCapability { list_changed: true }),
4246 sampling: None,
4247 elicitation: None,
4248 tasks: None,
4249 experimental: None,
4250 extensions: None,
4251 };
4252
4253 let json = serde_json::to_value(&caps).unwrap();
4254 assert_eq!(json["roots"]["listChanged"], true);
4255 }
4256
4257 #[test]
4258 fn test_roots_list_changed_notification_parsing() {
4259 let notif = JsonRpcNotification {
4260 jsonrpc: "2.0".to_string(),
4261 method: notifications::ROOTS_LIST_CHANGED.to_string(),
4262 params: None,
4263 };
4264
4265 let mcp_notif = McpNotification::from_jsonrpc(¬if).unwrap();
4266 assert!(matches!(mcp_notif, McpNotification::RootsListChanged));
4267 }
4268
4269 #[test]
4274 fn test_prompt_reference() {
4275 let ref_ = PromptReference::new("my-prompt");
4276 assert_eq!(ref_.ref_type, "ref/prompt");
4277 assert_eq!(ref_.name, "my-prompt");
4278
4279 let json = serde_json::to_value(&ref_).unwrap();
4280 assert_eq!(json["type"], "ref/prompt");
4281 assert_eq!(json["name"], "my-prompt");
4282 }
4283
4284 #[test]
4285 fn test_resource_reference() {
4286 let ref_ = ResourceReference::new("file:///path/to/file");
4287 assert_eq!(ref_.ref_type, "ref/resource");
4288 assert_eq!(ref_.uri, "file:///path/to/file");
4289
4290 let json = serde_json::to_value(&ref_).unwrap();
4291 assert_eq!(json["type"], "ref/resource");
4292 assert_eq!(json["uri"], "file:///path/to/file");
4293 }
4294
4295 #[test]
4296 fn test_completion_reference_prompt() {
4297 let ref_ = CompletionReference::prompt("test-prompt");
4298 let json = serde_json::to_value(&ref_).unwrap();
4299 assert_eq!(json["type"], "ref/prompt");
4300 assert_eq!(json["name"], "test-prompt");
4301 }
4302
4303 #[test]
4304 fn test_completion_reference_resource() {
4305 let ref_ = CompletionReference::resource("file:///test");
4306 let json = serde_json::to_value(&ref_).unwrap();
4307 assert_eq!(json["type"], "ref/resource");
4308 assert_eq!(json["uri"], "file:///test");
4309 }
4310
4311 #[test]
4312 fn test_completion_argument() {
4313 let arg = CompletionArgument::new("query", "SELECT * FROM");
4314 assert_eq!(arg.name, "query");
4315 assert_eq!(arg.value, "SELECT * FROM");
4316 }
4317
4318 #[test]
4319 fn test_complete_params_serialization() {
4320 let params = CompleteParams {
4321 reference: CompletionReference::prompt("sql-prompt"),
4322 argument: CompletionArgument::new("query", "SEL"),
4323 context: None,
4324 meta: None,
4325 };
4326
4327 let json = serde_json::to_value(¶ms).unwrap();
4328 assert_eq!(json["ref"]["type"], "ref/prompt");
4329 assert_eq!(json["ref"]["name"], "sql-prompt");
4330 assert_eq!(json["argument"]["name"], "query");
4331 assert_eq!(json["argument"]["value"], "SEL");
4332 assert!(json.get("context").is_none()); }
4334
4335 #[test]
4336 fn test_completion_new() {
4337 let completion = Completion::new(vec!["SELECT".to_string(), "SET".to_string()]);
4338 assert_eq!(completion.values.len(), 2);
4339 assert!(completion.total.is_none());
4340 assert!(completion.has_more.is_none());
4341 }
4342
4343 #[test]
4344 fn test_completion_with_pagination() {
4345 let completion =
4346 Completion::with_pagination(vec!["a".to_string(), "b".to_string()], 100, true);
4347 assert_eq!(completion.values.len(), 2);
4348 assert_eq!(completion.total, Some(100));
4349 assert_eq!(completion.has_more, Some(true));
4350 }
4351
4352 #[test]
4353 fn test_complete_result() {
4354 let result = CompleteResult::new(vec!["option1".to_string(), "option2".to_string()]);
4355 let json = serde_json::to_value(&result).unwrap();
4356 assert!(json["completion"]["values"].is_array());
4357 assert_eq!(json["completion"]["values"][0], "option1");
4358 }
4359
4360 #[test]
4365 fn test_model_hint() {
4366 let hint = ModelHint::new("claude-3-opus");
4367 assert_eq!(hint.name, Some("claude-3-opus".to_string()));
4368 }
4369
4370 #[test]
4371 fn test_model_preferences_builder() {
4372 let prefs = ModelPreferences::new()
4373 .speed(0.8)
4374 .intelligence(0.9)
4375 .cost(0.5)
4376 .hint("gpt-4")
4377 .hint("claude-3");
4378
4379 assert_eq!(prefs.speed_priority, Some(0.8));
4380 assert_eq!(prefs.intelligence_priority, Some(0.9));
4381 assert_eq!(prefs.cost_priority, Some(0.5));
4382 assert_eq!(prefs.hints.len(), 2);
4383 }
4384
4385 #[test]
4386 fn test_model_preferences_clamping() {
4387 let prefs = ModelPreferences::new().speed(1.5).cost(-0.5);
4388
4389 assert_eq!(prefs.speed_priority, Some(1.0)); assert_eq!(prefs.cost_priority, Some(0.0)); }
4392
4393 #[test]
4394 fn test_include_context_serialization() {
4395 assert_eq!(
4396 serde_json::to_string(&IncludeContext::AllServers).unwrap(),
4397 "\"allServers\""
4398 );
4399 assert_eq!(
4400 serde_json::to_string(&IncludeContext::ThisServer).unwrap(),
4401 "\"thisServer\""
4402 );
4403 assert_eq!(
4404 serde_json::to_string(&IncludeContext::None).unwrap(),
4405 "\"none\""
4406 );
4407 }
4408
4409 #[test]
4410 fn test_sampling_message_user() {
4411 let msg = SamplingMessage::user("Hello, how are you?");
4412 assert_eq!(msg.role, ContentRole::User);
4413 assert!(
4414 matches!(msg.content, SamplingContentOrArray::Single(SamplingContent::Text { ref text, .. }) if text == "Hello, how are you?")
4415 );
4416 }
4417
4418 #[test]
4419 fn test_sampling_message_assistant() {
4420 let msg = SamplingMessage::assistant("I'm doing well!");
4421 assert_eq!(msg.role, ContentRole::Assistant);
4422 }
4423
4424 #[test]
4425 fn test_sampling_content_text_serialization() {
4426 let content = SamplingContent::Text {
4427 text: "Hello".to_string(),
4428 annotations: None,
4429 meta: None,
4430 };
4431 let json = serde_json::to_value(&content).unwrap();
4432 assert_eq!(json["type"], "text");
4433 assert_eq!(json["text"], "Hello");
4434 }
4435
4436 #[test]
4437 fn test_sampling_content_image_serialization() {
4438 let content = SamplingContent::Image {
4439 data: "base64data".to_string(),
4440 mime_type: "image/png".to_string(),
4441 annotations: None,
4442 meta: None,
4443 };
4444 let json = serde_json::to_value(&content).unwrap();
4445 assert_eq!(json["type"], "image");
4446 assert_eq!(json["data"], "base64data");
4447 assert_eq!(json["mimeType"], "image/png");
4448 }
4449
4450 #[test]
4451 fn test_create_message_params() {
4452 let params = CreateMessageParams::new(
4453 vec![
4454 SamplingMessage::user("What is 2+2?"),
4455 SamplingMessage::assistant("4"),
4456 SamplingMessage::user("And 3+3?"),
4457 ],
4458 100,
4459 )
4460 .system_prompt("You are a math tutor")
4461 .temperature(0.7)
4462 .stop_sequence("END")
4463 .include_context(IncludeContext::ThisServer);
4464
4465 assert_eq!(params.messages.len(), 3);
4466 assert_eq!(params.max_tokens, 100);
4467 assert_eq!(
4468 params.system_prompt.as_deref(),
4469 Some("You are a math tutor")
4470 );
4471 assert_eq!(params.temperature, Some(0.7));
4472 assert_eq!(params.stop_sequences.len(), 1);
4473 assert_eq!(params.include_context, Some(IncludeContext::ThisServer));
4474 }
4475
4476 #[test]
4477 fn test_create_message_params_serialization() {
4478 let params = CreateMessageParams::new(vec![SamplingMessage::user("Hello")], 50);
4479
4480 let json = serde_json::to_value(¶ms).unwrap();
4481 assert!(json["messages"].is_array());
4482 assert_eq!(json["maxTokens"], 50);
4483 }
4484
4485 #[test]
4486 fn test_create_message_result_deserialization() {
4487 let json = serde_json::json!({
4488 "content": {
4489 "type": "text",
4490 "text": "The answer is 42"
4491 },
4492 "model": "claude-3-opus",
4493 "role": "assistant",
4494 "stopReason": "end_turn"
4495 });
4496
4497 let result: CreateMessageResult = serde_json::from_value(json).unwrap();
4498 assert_eq!(result.model, "claude-3-opus");
4499 assert_eq!(result.role, ContentRole::Assistant);
4500 assert_eq!(result.stop_reason.as_deref(), Some("end_turn"));
4501 }
4502
4503 #[test]
4504 fn test_completions_capability_serialization() {
4505 let cap = CompletionsCapability {};
4506 let json = serde_json::to_value(&cap).unwrap();
4507 assert!(json.is_object());
4508 }
4509
4510 #[test]
4511 fn test_server_capabilities_with_completions() {
4512 let caps = ServerCapabilities {
4513 completions: Some(CompletionsCapability {}),
4514 ..Default::default()
4515 };
4516
4517 let json = serde_json::to_value(&caps).unwrap();
4518 assert!(json["completions"].is_object());
4519 }
4520
4521 #[test]
4522 fn test_content_resource_link_serialization() {
4523 let content = Content::ResourceLink {
4524 uri: "file:///test.txt".to_string(),
4525 name: "test.txt".to_string(),
4526 title: None,
4527 description: Some("A test file".to_string()),
4528 mime_type: Some("text/plain".to_string()),
4529 size: None,
4530 icons: None,
4531 annotations: None,
4532 meta: None,
4533 };
4534 let json = serde_json::to_value(&content).unwrap();
4535 assert_eq!(json["type"], "resource_link");
4536 assert_eq!(json["uri"], "file:///test.txt");
4537 assert_eq!(json["name"], "test.txt");
4538 assert_eq!(json["description"], "A test file");
4539 assert_eq!(json["mimeType"], "text/plain");
4540 }
4541
4542 #[test]
4543 fn test_call_tool_result_resource_link() {
4544 let result = CallToolResult::resource_link("file:///output.json", "output.json");
4545 assert_eq!(result.content.len(), 1);
4546 assert!(!result.is_error);
4547 match &result.content[0] {
4548 Content::ResourceLink { uri, .. } => assert_eq!(uri, "file:///output.json"),
4549 _ => panic!("Expected ResourceLink content"),
4550 }
4551 }
4552
4553 #[test]
4554 fn test_call_tool_result_image() {
4555 let result = CallToolResult::image("base64data", "image/png");
4556 assert_eq!(result.content.len(), 1);
4557 match &result.content[0] {
4558 Content::Image {
4559 data, mime_type, ..
4560 } => {
4561 assert_eq!(data, "base64data");
4562 assert_eq!(mime_type, "image/png");
4563 }
4564 _ => panic!("Expected Image content"),
4565 }
4566 }
4567
4568 #[test]
4569 fn test_call_tool_result_audio() {
4570 let result = CallToolResult::audio("audiodata", "audio/wav");
4571 assert_eq!(result.content.len(), 1);
4572 match &result.content[0] {
4573 Content::Audio {
4574 data, mime_type, ..
4575 } => {
4576 assert_eq!(data, "audiodata");
4577 assert_eq!(mime_type, "audio/wav");
4578 }
4579 _ => panic!("Expected Audio content"),
4580 }
4581 }
4582
4583 #[test]
4584 fn test_sampling_tool_serialization() {
4585 let tool = SamplingTool {
4586 name: "get_weather".to_string(),
4587 title: None,
4588 description: Some("Get current weather".to_string()),
4589 input_schema: serde_json::json!({
4590 "type": "object",
4591 "properties": {
4592 "location": { "type": "string" }
4593 }
4594 }),
4595 output_schema: None,
4596 icons: None,
4597 annotations: None,
4598 execution: None,
4599 };
4600 let json = serde_json::to_value(&tool).unwrap();
4601 assert_eq!(json["name"], "get_weather");
4602 assert_eq!(json["description"], "Get current weather");
4603 assert!(json["inputSchema"]["properties"]["location"].is_object());
4604 }
4605
4606 #[test]
4607 fn test_tool_choice_modes() {
4608 let auto = ToolChoice::auto();
4609 assert_eq!(auto.mode, "auto");
4610 assert!(auto.name.is_none());
4611
4612 let required = ToolChoice::required();
4613 assert_eq!(required.mode, "required");
4614
4615 let none = ToolChoice::none();
4616 assert_eq!(none.mode, "none");
4617
4618 let tool = ToolChoice::tool("get_weather");
4619 assert_eq!(tool.mode, "tool");
4620 assert_eq!(tool.name.as_deref(), Some("get_weather"));
4621
4622 let json = serde_json::to_value(&auto).unwrap();
4624 assert_eq!(json["mode"], "auto");
4625 assert!(json.get("name").is_none());
4626
4627 let json = serde_json::to_value(&tool).unwrap();
4628 assert_eq!(json["mode"], "tool");
4629 assert_eq!(json["name"], "get_weather");
4630 }
4631
4632 #[test]
4633 fn test_sampling_content_tool_use() {
4634 let content = SamplingContent::ToolUse {
4635 id: "tool_123".to_string(),
4636 name: "get_weather".to_string(),
4637 input: serde_json::json!({"location": "San Francisco"}),
4638 meta: None,
4639 };
4640 let json = serde_json::to_value(&content).unwrap();
4641 assert_eq!(json["type"], "tool_use");
4642 assert_eq!(json["id"], "tool_123");
4643 assert_eq!(json["name"], "get_weather");
4644 assert_eq!(json["input"]["location"], "San Francisco");
4645 }
4646
4647 #[test]
4648 fn test_sampling_content_tool_result() {
4649 let content = SamplingContent::ToolResult {
4650 tool_use_id: "tool_123".to_string(),
4651 content: vec![SamplingContent::Text {
4652 text: "72F, sunny".to_string(),
4653 annotations: None,
4654 meta: None,
4655 }],
4656 structured_content: None,
4657 is_error: None,
4658 meta: None,
4659 };
4660 let json = serde_json::to_value(&content).unwrap();
4661 assert_eq!(json["type"], "tool_result");
4662 assert_eq!(json["toolUseId"], "tool_123");
4663 assert_eq!(json["content"][0]["type"], "text");
4664 }
4665
4666 #[test]
4667 fn test_sampling_content_or_array_single() {
4668 let json = serde_json::json!({
4669 "type": "text",
4670 "text": "Hello"
4671 });
4672 let content: SamplingContentOrArray = serde_json::from_value(json).unwrap();
4673 let items = content.items();
4674 assert_eq!(items.len(), 1);
4675 match items[0] {
4676 SamplingContent::Text { text, .. } => assert_eq!(text, "Hello"),
4677 _ => panic!("Expected text content"),
4678 }
4679 }
4680
4681 #[test]
4682 fn test_sampling_content_or_array_multiple() {
4683 let json = serde_json::json!([
4684 { "type": "text", "text": "Hello" },
4685 { "type": "text", "text": "World" }
4686 ]);
4687 let content: SamplingContentOrArray = serde_json::from_value(json).unwrap();
4688 let items = content.items();
4689 assert_eq!(items.len(), 2);
4690 }
4691
4692 #[test]
4693 fn test_create_message_params_with_tools() {
4694 let tool = SamplingTool {
4695 name: "calculator".to_string(),
4696 title: None,
4697 description: Some("Do math".to_string()),
4698 input_schema: serde_json::json!({"type": "object"}),
4699 output_schema: None,
4700 icons: None,
4701 annotations: None,
4702 execution: None,
4703 };
4704 let params = CreateMessageParams::new(vec![], 100)
4705 .tools(vec![tool])
4706 .tool_choice(ToolChoice::auto());
4707
4708 let json = serde_json::to_value(¶ms).unwrap();
4709 assert!(json["tools"].is_array());
4710 assert_eq!(json["tools"][0]["name"], "calculator");
4711 assert_eq!(json["toolChoice"]["mode"], "auto");
4712 }
4713
4714 #[test]
4715 fn test_create_message_result_content_items() {
4716 let result = CreateMessageResult {
4717 content: SamplingContentOrArray::Array(vec![
4718 SamplingContent::Text {
4719 text: "First".to_string(),
4720 annotations: None,
4721 meta: None,
4722 },
4723 SamplingContent::Text {
4724 text: "Second".to_string(),
4725 annotations: None,
4726 meta: None,
4727 },
4728 ]),
4729 model: "test".to_string(),
4730 role: ContentRole::Assistant,
4731 stop_reason: None,
4732 meta: None,
4733 };
4734 let items = result.content_items();
4735 assert_eq!(items.len(), 2);
4736 }
4737
4738 #[test]
4739 fn test_sampling_content_as_text() {
4740 let text_content = SamplingContent::Text {
4741 text: "Hello".to_string(),
4742 annotations: None,
4743 meta: None,
4744 };
4745 assert_eq!(text_content.as_text(), Some("Hello"));
4746
4747 let image_content = SamplingContent::Image {
4748 data: "base64data".to_string(),
4749 mime_type: "image/png".to_string(),
4750 annotations: None,
4751 meta: None,
4752 };
4753 assert_eq!(image_content.as_text(), None);
4754
4755 let audio_content = SamplingContent::Audio {
4756 data: "base64audio".to_string(),
4757 mime_type: "audio/wav".to_string(),
4758 annotations: None,
4759 meta: None,
4760 };
4761 assert_eq!(audio_content.as_text(), None);
4762 }
4763
4764 #[test]
4765 fn test_create_message_result_first_text_single() {
4766 let result = CreateMessageResult {
4767 content: SamplingContentOrArray::Single(SamplingContent::Text {
4768 text: "Hello, world!".to_string(),
4769 annotations: None,
4770 meta: None,
4771 }),
4772 model: "test".to_string(),
4773 role: ContentRole::Assistant,
4774 stop_reason: None,
4775 meta: None,
4776 };
4777 assert_eq!(result.first_text(), Some("Hello, world!"));
4778 }
4779
4780 #[test]
4781 fn test_create_message_result_first_text_array() {
4782 let result = CreateMessageResult {
4783 content: SamplingContentOrArray::Array(vec![
4784 SamplingContent::Text {
4785 text: "First".to_string(),
4786 annotations: None,
4787 meta: None,
4788 },
4789 SamplingContent::Text {
4790 text: "Second".to_string(),
4791 annotations: None,
4792 meta: None,
4793 },
4794 ]),
4795 model: "test".to_string(),
4796 role: ContentRole::Assistant,
4797 stop_reason: None,
4798 meta: None,
4799 };
4800 assert_eq!(result.first_text(), Some("First"));
4801 }
4802
4803 #[test]
4804 fn test_create_message_result_first_text_skips_non_text() {
4805 let result = CreateMessageResult {
4806 content: SamplingContentOrArray::Array(vec![
4807 SamplingContent::Image {
4808 data: "base64data".to_string(),
4809 mime_type: "image/png".to_string(),
4810 annotations: None,
4811 meta: None,
4812 },
4813 SamplingContent::Text {
4814 text: "After image".to_string(),
4815 annotations: None,
4816 meta: None,
4817 },
4818 ]),
4819 model: "test".to_string(),
4820 role: ContentRole::Assistant,
4821 stop_reason: None,
4822 meta: None,
4823 };
4824 assert_eq!(result.first_text(), Some("After image"));
4825 }
4826
4827 #[test]
4828 fn test_create_message_result_first_text_none() {
4829 let result = CreateMessageResult {
4830 content: SamplingContentOrArray::Single(SamplingContent::Image {
4831 data: "base64data".to_string(),
4832 mime_type: "image/png".to_string(),
4833 annotations: None,
4834 meta: None,
4835 }),
4836 model: "test".to_string(),
4837 role: ContentRole::Assistant,
4838 stop_reason: None,
4839 meta: None,
4840 };
4841 assert_eq!(result.first_text(), None);
4842 }
4843
4844 #[test]
4845 fn test_tool_annotations_accessors() {
4846 let annotations = ToolAnnotations {
4847 read_only_hint: true,
4848 destructive_hint: false,
4849 idempotent_hint: true,
4850 open_world_hint: false,
4851 ..Default::default()
4852 };
4853
4854 assert!(annotations.is_read_only());
4855 assert!(!annotations.is_destructive());
4856 assert!(annotations.is_idempotent());
4857 assert!(!annotations.is_open_world());
4858 }
4859
4860 #[test]
4861 fn test_tool_annotations_defaults() {
4862 let annotations = ToolAnnotations::default();
4864
4865 assert!(!annotations.is_read_only());
4866 assert!(annotations.is_destructive());
4867 assert!(!annotations.is_idempotent());
4868 assert!(annotations.is_open_world());
4869 }
4870
4871 #[test]
4872 fn test_tool_annotations_serde_defaults() {
4873 let annotations: ToolAnnotations = serde_json::from_str("{}").unwrap();
4876
4877 assert!(!annotations.is_read_only());
4878 assert!(annotations.is_destructive());
4879 assert!(!annotations.is_idempotent());
4880 assert!(annotations.is_open_world());
4881 }
4882
4883 #[test]
4884 fn test_tool_definition_accessors_with_annotations() {
4885 let def = ToolDefinition {
4886 name: "test".to_string(),
4887 title: None,
4888 description: None,
4889 input_schema: serde_json::json!({"type": "object"}),
4890 output_schema: None,
4891 icons: None,
4892 annotations: Some(ToolAnnotations {
4893 read_only_hint: true,
4894 idempotent_hint: true,
4895 destructive_hint: false,
4896 open_world_hint: false,
4897 ..Default::default()
4898 }),
4899 execution: None,
4900 meta: None,
4901 };
4902
4903 assert!(def.is_read_only());
4904 assert!(!def.is_destructive());
4905 assert!(def.is_idempotent());
4906 assert!(!def.is_open_world());
4907 }
4908
4909 #[test]
4910 fn test_tool_definition_accessors_without_annotations() {
4911 let def = ToolDefinition {
4912 name: "test".to_string(),
4913 title: None,
4914 description: None,
4915 input_schema: serde_json::json!({"type": "object"}),
4916 output_schema: None,
4917 icons: None,
4918 annotations: None,
4919 execution: None,
4920 meta: None,
4921 };
4922
4923 assert!(!def.is_read_only());
4925 assert!(def.is_destructive());
4926 assert!(!def.is_idempotent());
4927 assert!(def.is_open_world());
4928 }
4929
4930 #[test]
4931 fn test_call_tool_result_from_list() {
4932 #[derive(serde::Serialize)]
4933 struct Item {
4934 name: String,
4935 }
4936
4937 let items = vec![
4938 Item {
4939 name: "a".to_string(),
4940 },
4941 Item {
4942 name: "b".to_string(),
4943 },
4944 Item {
4945 name: "c".to_string(),
4946 },
4947 ];
4948
4949 let result = CallToolResult::from_list("items", &items).unwrap();
4950 assert!(!result.is_error);
4951
4952 let structured = result.structured_content.unwrap();
4953 assert_eq!(structured["count"], 3);
4954 assert_eq!(structured["items"].as_array().unwrap().len(), 3);
4955 assert_eq!(structured["items"][0]["name"], "a");
4956 }
4957
4958 #[test]
4959 fn test_call_tool_result_from_list_empty() {
4960 let items: Vec<String> = vec![];
4961 let result = CallToolResult::from_list("results", &items).unwrap();
4962 assert!(!result.is_error);
4963
4964 let structured = result.structured_content.unwrap();
4965 assert_eq!(structured["count"], 0);
4966 assert_eq!(structured["results"].as_array().unwrap().len(), 0);
4967 }
4968
4969 #[test]
4974 fn test_call_tool_result_as_json() {
4975 let result = CallToolResult::json(serde_json::json!({"key": "value"}));
4976 let value = result.as_json().unwrap().unwrap();
4977 assert_eq!(value["key"], "value");
4978 }
4979
4980 #[test]
4981 fn test_call_tool_result_as_json_from_text() {
4982 let result = CallToolResult::text(r#"{"key": "value"}"#);
4983 let value = result.as_json().unwrap().unwrap();
4984 assert_eq!(value["key"], "value");
4985 }
4986
4987 #[test]
4988 fn test_call_tool_result_as_json_none() {
4989 let result = CallToolResult::text("not json");
4990 let parsed = result.as_json().unwrap();
4991 assert!(parsed.is_err());
4992 }
4993
4994 #[test]
4995 fn test_call_tool_result_deserialize() {
4996 #[derive(Debug, serde::Deserialize, PartialEq)]
4997 struct Output {
4998 key: String,
4999 }
5000
5001 let result = CallToolResult::json(serde_json::json!({"key": "value"}));
5002 let output: Output = result.deserialize().unwrap().unwrap();
5003 assert_eq!(output.key, "value");
5004 }
5005
5006 #[test]
5007 fn test_call_tool_result_as_json_empty() {
5008 let result = CallToolResult {
5009 content: vec![],
5010 is_error: false,
5011 structured_content: None,
5012 meta: None,
5013 };
5014 assert!(result.as_json().is_none());
5015 }
5016
5017 #[test]
5018 fn test_call_tool_result_deserialize_from_text() {
5019 #[derive(Debug, serde::Deserialize, PartialEq)]
5020 struct Output {
5021 key: String,
5022 }
5023
5024 let result = CallToolResult::text(r#"{"key": "from_text"}"#);
5025 let output: Output = result.deserialize().unwrap().unwrap();
5026 assert_eq!(output.key, "from_text");
5027 }
5028
5029 #[test]
5030 fn test_read_resource_result_as_json() {
5031 let result = ReadResourceResult::json("data://config", &serde_json::json!({"port": 8080}));
5032 let value = result.as_json().unwrap().unwrap();
5033 assert_eq!(value["port"], 8080);
5034 }
5035
5036 #[test]
5037 fn test_read_resource_result_deserialize() {
5038 #[derive(Debug, serde::Deserialize, PartialEq)]
5039 struct Config {
5040 port: u16,
5041 }
5042
5043 let result = ReadResourceResult::json("data://config", &serde_json::json!({"port": 8080}));
5044 let config: Config = result.deserialize().unwrap().unwrap();
5045 assert_eq!(config.port, 8080);
5046 }
5047
5048 #[test]
5049 fn test_get_prompt_result_as_json() {
5050 let result = GetPromptResult::user_message(r#"{"action": "analyze"}"#);
5051 let value = result.as_json().unwrap().unwrap();
5052 assert_eq!(value["action"], "analyze");
5053 }
5054
5055 #[test]
5056 fn test_get_prompt_result_deserialize() {
5057 #[derive(Debug, serde::Deserialize, PartialEq)]
5058 struct Params {
5059 action: String,
5060 }
5061
5062 let result = GetPromptResult::user_message(r#"{"action": "analyze"}"#);
5063 let params: Params = result.deserialize().unwrap().unwrap();
5064 assert_eq!(params.action, "analyze");
5065 }
5066
5067 #[test]
5068 fn test_get_prompt_result_as_json_empty() {
5069 let result = GetPromptResult {
5070 description: None,
5071 messages: vec![],
5072 meta: None,
5073 };
5074 assert!(result.as_json().is_none());
5075 }
5076
5077 #[test]
5078 fn test_mcp_response_serde_roundtrip() {
5079 let response = McpResponse::CallTool(CallToolResult {
5081 content: vec![Content::text("hello")],
5082 structured_content: None,
5083 is_error: false,
5084 meta: None,
5085 });
5086 let json = serde_json::to_string(&response).unwrap();
5087 let deserialized: McpResponse = serde_json::from_str(&json).unwrap();
5088 match deserialized {
5089 McpResponse::CallTool(result) => {
5090 assert_eq!(result.content[0].as_text(), Some("hello"));
5091 }
5092 _ => panic!("expected CallTool variant"),
5093 }
5094
5095 let response = McpResponse::ListTools(ListToolsResult {
5097 tools: vec![],
5098 next_cursor: Some("cursor123".to_string()),
5099 meta: None,
5100 });
5101 let json = serde_json::to_string(&response).unwrap();
5102 let deserialized: McpResponse = serde_json::from_str(&json).unwrap();
5103 match deserialized {
5104 McpResponse::ListTools(result) => {
5105 assert_eq!(result.next_cursor.as_deref(), Some("cursor123"));
5106 }
5107 _ => panic!("expected ListTools variant"),
5108 }
5109 }
5110}