1use serde::{Deserialize, Serialize};
7use serde_json::Value;
8use std::fmt;
9
10pub use crate::MCP_PROTOCOL_VERSION;
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct JsonRpcRequest {
16 pub jsonrpc: String,
17 pub id: JsonRpcId,
18 pub method: String,
19 #[serde(skip_serializing_if = "Option::is_none")]
20 pub params: Option<Value>,
21}
22
23impl JsonRpcRequest {
24 pub fn new(id: JsonRpcId, method: impl Into<String>, params: Option<Value>) -> Self {
25 Self {
26 jsonrpc: "2.0".to_string(),
27 id,
28 method: method.into(),
29 params,
30 }
31 }
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct JsonRpcResponse {
37 pub jsonrpc: String,
38 pub id: JsonRpcId,
39 #[serde(flatten)]
40 pub payload: JsonRpcPayload,
41}
42
43impl JsonRpcResponse {
44 pub fn success(id: impl Into<JsonRpcId>, result: Value) -> Self {
46 Self {
47 jsonrpc: "2.0".to_string(),
48 id: id.into(),
49 payload: JsonRpcPayload::Success { result },
50 }
51 }
52
53 pub fn error(
55 id: impl Into<JsonRpcId>,
56 code: i32,
57 message: impl Into<String>,
58 data: Option<Value>,
59 ) -> Self {
60 Self {
61 jsonrpc: "2.0".to_string(),
62 id: id.into(),
63 payload: JsonRpcPayload::Error {
64 error: JsonRpcError {
65 code,
66 message: message.into(),
67 data,
68 },
69 },
70 }
71 }
72
73 pub fn result(&self) -> Option<&Value> {
75 match &self.payload {
76 JsonRpcPayload::Success { result } => Some(result),
77 JsonRpcPayload::Error { .. } => None,
78 }
79 }
80
81 pub fn is_success(&self) -> bool {
83 matches!(&self.payload, JsonRpcPayload::Success { .. })
84 }
85
86 pub fn is_error(&self) -> bool {
88 matches!(&self.payload, JsonRpcPayload::Error { .. })
89 }
90
91 pub fn error_info(&self) -> Option<&JsonRpcError> {
93 match &self.payload {
94 JsonRpcPayload::Success { .. } => None,
95 JsonRpcPayload::Error { error } => Some(error),
96 }
97 }
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct JsonRpcNotification {
103 pub jsonrpc: String,
104 pub method: String,
105 #[serde(skip_serializing_if = "Option::is_none")]
106 pub params: Option<Value>,
107}
108
109impl JsonRpcNotification {
110 pub fn new(method: impl Into<String>, params: Option<Value>) -> Self {
112 Self {
113 jsonrpc: "2.0".to_string(),
114 method: method.into(),
115 params,
116 }
117 }
118}
119
120#[derive(Debug, Clone)]
122pub enum ServerOutbound {
123 Request(JsonRpcRequest),
125 Notification(JsonRpcNotification),
127 Response(JsonRpcResponse),
129}
130
131impl ServerOutbound {
132 pub fn to_json(&self) -> Result<String, serde_json::Error> {
134 match self {
135 ServerOutbound::Request(r) => serde_json::to_string(r),
136 ServerOutbound::Notification(n) => serde_json::to_string(n),
137 ServerOutbound::Response(r) => serde_json::to_string(r),
138 }
139 }
140}
141
142#[derive(Debug, Clone)]
144pub enum ClientInbound {
145 Request(JsonRpcRequest),
147 Response(JsonRpcResponse),
149 Notification(JsonRpcNotification),
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize)]
156#[serde(untagged)]
157pub enum JsonRpcMessage {
158 Request(JsonRpcRequest),
159 Response(JsonRpcResponse),
160 Notification(JsonRpcNotification),
161}
162
163impl JsonRpcMessage {
164 pub fn parse(s: &str) -> Result<Self, serde_json::Error> {
166 serde_json::from_str(s)
167 }
168
169 pub fn into_client_inbound(self) -> ClientInbound {
171 match self {
172 JsonRpcMessage::Request(r) => ClientInbound::Request(r),
173 JsonRpcMessage::Response(r) => ClientInbound::Response(r),
174 JsonRpcMessage::Notification(n) => ClientInbound::Notification(n),
175 }
176 }
177}
178
179#[derive(Debug, Clone, Serialize, Deserialize)]
180#[serde(untagged)]
181pub enum JsonRpcPayload {
182 Success { result: Value },
183 Error { error: JsonRpcError },
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct JsonRpcError {
189 pub code: i32,
190 pub message: String,
191 #[serde(skip_serializing_if = "Option::is_none")]
192 pub data: Option<Value>,
193}
194
195impl fmt::Display for JsonRpcError {
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 write!(f, "JSON-RPC Error {}: {}", self.code, self.message)
198 }
199}
200
201impl std::error::Error for JsonRpcError {}
202
203pub mod error_codes {
205 pub const PARSE_ERROR: i32 = -32700;
207 pub const INVALID_REQUEST: i32 = -32600;
209 pub const METHOD_NOT_FOUND: i32 = -32601;
211 pub const INVALID_PARAMS: i32 = -32602;
213 pub const INTERNAL_ERROR: i32 = -32603;
215 pub const URL_ELICITATION_REQUIRED: i32 = -32042;
217}
218
219#[derive(Debug, Clone, Serialize, Deserialize)]
225pub struct Icon {
226 pub src: String,
229
230 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
232 pub mime_type: Option<String>,
233
234 #[serde(skip_serializing_if = "Option::is_none")]
237 pub sizes: Option<Vec<String>>,
238
239 #[serde(skip_serializing_if = "Option::is_none")]
241 pub theme: Option<IconTheme>,
242}
243
244#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
246#[serde(rename_all = "snake_case")]
247pub enum IconTheme {
248 Light,
249 Dark,
250}
251
252#[derive(Debug, Clone, Serialize, Deserialize)]
254pub struct BaseMetadata {
255 pub name: String,
257
258 #[serde(skip_serializing_if = "Option::is_none")]
260 pub title: Option<String>,
261}
262
263#[derive(Debug, Clone, Serialize, Deserialize, Default)]
265pub struct Annotations {
266 #[serde(skip_serializing_if = "Option::is_none")]
268 pub audience: Option<Vec<Role>>,
269
270 #[serde(skip_serializing_if = "Option::is_none")]
272 pub priority: Option<f64>,
273
274 #[serde(rename = "lastModified", skip_serializing_if = "Option::is_none")]
276 pub last_modified: Option<String>,
277}
278
279#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
281#[serde(rename_all = "snake_case")]
282pub enum Role {
283 User,
284 Assistant,
285}
286
287#[derive(Debug, Clone, Serialize, Deserialize)]
294pub struct Implementation {
295 pub name: String,
297
298 pub version: String,
300
301 #[serde(skip_serializing_if = "Option::is_none")]
303 pub title: Option<String>,
304
305 #[serde(skip_serializing_if = "Option::is_none")]
307 pub description: Option<String>,
308
309 #[serde(skip_serializing_if = "Option::is_none")]
311 pub icons: Option<Vec<Icon>>,
312
313 #[serde(rename = "websiteUrl", skip_serializing_if = "Option::is_none")]
315 pub website_url: Option<String>,
316}
317
318pub type McpServerInfo = Implementation;
320
321#[derive(Debug, Clone, Serialize, Deserialize, Default)]
323pub struct McpCapabilities {
324 #[serde(skip_serializing_if = "Option::is_none")]
325 pub tools: Option<Value>,
326 #[serde(skip_serializing_if = "Option::is_none")]
327 pub resources: Option<Value>,
328 #[serde(skip_serializing_if = "Option::is_none")]
329 pub prompts: Option<Value>,
330 #[serde(skip_serializing_if = "Option::is_none")]
331 pub logging: Option<Value>,
332 #[serde(skip_serializing_if = "Option::is_none")]
333 pub completions: Option<Value>,
334 #[serde(skip_serializing_if = "Option::is_none")]
335 pub elicitation: Option<Value>,
336 #[serde(skip_serializing_if = "Option::is_none")]
337 pub tasks: Option<Value>,
338 #[serde(skip_serializing_if = "Option::is_none")]
339 pub experimental: Option<Value>,
340}
341
342#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
348#[serde(untagged)]
349pub enum JsonRpcId {
350 String(String),
351 Number(i64),
352 Null,
353}
354
355impl From<i64> for JsonRpcId {
356 fn from(n: i64) -> Self {
357 JsonRpcId::Number(n)
358 }
359}
360
361impl From<String> for JsonRpcId {
362 fn from(s: String) -> Self {
363 JsonRpcId::String(s)
364 }
365}
366
367impl From<&str> for JsonRpcId {
368 fn from(s: &str) -> Self {
369 JsonRpcId::String(s.to_string())
370 }
371}
372
373impl From<Value> for JsonRpcId {
374 fn from(v: Value) -> Self {
375 match v {
376 Value::String(s) => JsonRpcId::String(s),
377 Value::Number(n) => JsonRpcId::Number(n.as_i64().unwrap_or(0)),
378 Value::Null => JsonRpcId::Null,
379 _ => JsonRpcId::Null,
380 }
381 }
382}
383
384impl From<JsonRpcId> for Value {
385 fn from(id: JsonRpcId) -> Self {
386 match id {
387 JsonRpcId::String(s) => Value::String(s),
388 JsonRpcId::Number(n) => Value::Number(n.into()),
389 JsonRpcId::Null => Value::Null,
390 }
391 }
392}
393
394impl fmt::Display for JsonRpcId {
395 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
396 match self {
397 JsonRpcId::String(s) => write!(f, "{}", s),
398 JsonRpcId::Number(n) => write!(f, "{}", n),
399 JsonRpcId::Null => write!(f, "null"),
400 }
401 }
402}
403
404#[derive(Debug, Clone, Serialize, Deserialize, Default)]
411pub struct ToolAnnotations {
412 #[serde(skip_serializing_if = "Option::is_none")]
414 pub title: Option<String>,
415
416 #[serde(rename = "readOnlyHint", skip_serializing_if = "Option::is_none")]
418 pub read_only_hint: Option<bool>,
419
420 #[serde(rename = "destructiveHint", skip_serializing_if = "Option::is_none")]
422 pub destructive_hint: Option<bool>,
423
424 #[serde(rename = "idempotentHint", skip_serializing_if = "Option::is_none")]
426 pub idempotent_hint: Option<bool>,
427
428 #[serde(rename = "openWorldHint", skip_serializing_if = "Option::is_none")]
430 pub open_world_hint: Option<bool>,
431}
432
433#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
435#[serde(rename_all = "snake_case")]
436pub enum TaskSupport {
437 #[default]
439 Forbidden,
440 Optional,
442 Required,
444}
445
446#[derive(Debug, Clone, Serialize, Deserialize, Default)]
448pub struct ToolExecution {
449 #[serde(rename = "taskSupport", skip_serializing_if = "Option::is_none")]
451 pub task_support: Option<TaskSupport>,
452}
453
454#[derive(Debug, Clone, Serialize, Deserialize)]
456pub struct McpToolDefinition {
457 pub name: String,
458
459 #[serde(skip_serializing_if = "Option::is_none")]
461 pub title: Option<String>,
462
463 #[serde(skip_serializing_if = "Option::is_none")]
464 pub description: Option<String>,
465
466 #[serde(skip_serializing_if = "Option::is_none")]
467 pub group: Option<String>,
468
469 #[serde(skip_serializing_if = "Option::is_none")]
471 pub icons: Option<Vec<Icon>>,
472
473 #[serde(rename = "inputSchema", default = "default_input_schema")]
474 pub input_schema: Value,
475
476 #[serde(rename = "outputSchema", skip_serializing_if = "Option::is_none")]
478 pub output_schema: Option<Value>,
479
480 #[serde(skip_serializing_if = "Option::is_none")]
482 pub execution: Option<ToolExecution>,
483
484 #[serde(skip_serializing_if = "Option::is_none")]
486 pub annotations: Option<ToolAnnotations>,
487
488 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
490 pub meta: Option<Value>,
491}
492
493fn default_input_schema() -> Value {
494 serde_json::json!({"type": "object"})
495}
496
497impl McpToolDefinition {
498 pub fn new(name: impl Into<String>) -> Self {
500 Self {
501 name: name.into(),
502 title: None,
503 description: None,
504 group: None,
505 icons: None,
506 input_schema: default_input_schema(),
507 output_schema: None,
508 execution: None,
509 annotations: None,
510 meta: None,
511 }
512 }
513
514 pub fn with_title(mut self, title: impl Into<String>) -> Self {
516 self.title = Some(title.into());
517 self
518 }
519
520 pub fn with_group(mut self, group: impl Into<String>) -> Self {
522 self.group = Some(group.into());
523 self
524 }
525
526 pub fn with_description(mut self, desc: impl Into<String>) -> Self {
528 self.description = Some(desc.into());
529 self
530 }
531
532 pub fn with_schema(mut self, schema: Value) -> Self {
534 self.input_schema = schema;
535 self
536 }
537
538 pub fn with_output_schema(mut self, schema: Value) -> Self {
540 self.output_schema = Some(schema);
541 self
542 }
543
544 pub fn with_annotations(mut self, annotations: ToolAnnotations) -> Self {
546 self.annotations = Some(annotations);
547 self
548 }
549
550 pub fn with_execution(mut self, execution: ToolExecution) -> Self {
552 self.execution = Some(execution);
553 self
554 }
555
556 pub fn description_or_default(&self) -> &str {
558 self.description.as_deref().unwrap_or("")
559 }
560
561 pub fn parameters(&self) -> Value {
563 self.input_schema.clone()
564 }
565}
566
567#[derive(Debug, Clone, Serialize, Deserialize, Default)]
569pub struct ToolInputSchema {
570 #[serde(rename = "type")]
571 pub schema_type: String,
572 #[serde(skip_serializing_if = "Option::is_none")]
573 pub properties: Option<Value>,
574 #[serde(skip_serializing_if = "Option::is_none")]
575 pub required: Option<Vec<String>>,
576}
577
578#[derive(Debug, Clone, Serialize, Deserialize, Default)]
580pub struct ListToolsParams {
581 #[serde(skip_serializing_if = "Option::is_none")]
582 pub cursor: Option<String>,
583}
584
585#[derive(Debug, Clone, Serialize, Deserialize)]
587pub struct ListToolsResult {
588 pub tools: Vec<McpToolDefinition>,
589 #[serde(skip_serializing_if = "Option::is_none")]
590 pub next_cursor: Option<String>,
591}
592
593#[derive(Debug, Clone, Serialize, Deserialize)]
595pub struct CallToolParams {
596 pub name: String,
597 #[serde(skip_serializing_if = "Option::is_none")]
598 pub arguments: Option<Value>,
599 #[serde(skip_serializing_if = "Option::is_none")]
601 pub task: Option<TaskMetadata>,
602 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
604 pub meta: Option<Value>,
605}
606
607#[derive(Debug, Clone, Serialize, Deserialize)]
609pub struct CallToolResult {
610 #[serde(default)]
612 pub content: Vec<ToolContent>,
613 #[serde(rename = "structuredContent", skip_serializing_if = "Option::is_none")]
615 pub structured_content: Option<Value>,
616 #[serde(rename = "isError", skip_serializing_if = "Option::is_none")]
618 pub is_error: Option<bool>,
619}
620
621#[derive(Debug, Clone, Serialize, Deserialize)]
623#[serde(tag = "type")]
624pub enum ToolContent {
625 #[serde(rename = "text")]
626 Text {
627 text: String,
628 #[serde(skip_serializing_if = "Option::is_none")]
629 annotations: Option<Annotations>,
630 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
631 meta: Option<Value>,
632 },
633 #[serde(rename = "image")]
634 Image {
635 data: String,
636 #[serde(rename = "mimeType")]
637 mime_type: String,
638 #[serde(skip_serializing_if = "Option::is_none")]
639 annotations: Option<Annotations>,
640 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
641 meta: Option<Value>,
642 },
643 #[serde(rename = "audio")]
644 Audio {
645 data: String,
646 #[serde(rename = "mimeType")]
647 mime_type: String,
648 #[serde(skip_serializing_if = "Option::is_none")]
649 annotations: Option<Annotations>,
650 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
651 meta: Option<Value>,
652 },
653 #[serde(rename = "resource")]
654 Resource {
655 uri: String,
656 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
657 mime_type: Option<String>,
658 },
659 #[serde(rename = "resource_link")]
660 ResourceLink {
661 uri: String,
662 name: String,
663 #[serde(skip_serializing_if = "Option::is_none")]
664 title: Option<String>,
665 #[serde(skip_serializing_if = "Option::is_none")]
666 description: Option<String>,
667 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
668 mime_type: Option<String>,
669 #[serde(skip_serializing_if = "Option::is_none")]
670 annotations: Option<Annotations>,
671 },
672}
673
674impl ToolContent {
675 pub fn text(text: impl Into<String>) -> Self {
677 Self::Text {
678 text: text.into(),
679 annotations: None,
680 meta: None,
681 }
682 }
683
684 pub fn image(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
686 Self::Image {
687 data: data.into(),
688 mime_type: mime_type.into(),
689 annotations: None,
690 meta: None,
691 }
692 }
693
694 pub fn audio(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
696 Self::Audio {
697 data: data.into(),
698 mime_type: mime_type.into(),
699 annotations: None,
700 meta: None,
701 }
702 }
703
704 pub fn resource(uri: impl Into<String>, mime_type: Option<String>) -> Self {
706 Self::Resource {
707 uri: uri.into(),
708 mime_type,
709 }
710 }
711
712 pub fn as_text(&self) -> Option<&str> {
714 match self {
715 Self::Text { text, .. } => Some(text),
716 _ => None,
717 }
718 }
719
720 pub fn is_text(&self) -> bool {
722 matches!(self, Self::Text { .. })
723 }
724}
725
726#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
732#[serde(rename_all = "snake_case")]
733pub enum TaskStatus {
734 Working,
736 InputRequired,
738 Completed,
740 Failed,
742 Cancelled,
744}
745
746#[derive(Debug, Clone, Serialize, Deserialize, Default)]
748pub struct TaskMetadata {
749 #[serde(skip_serializing_if = "Option::is_none")]
751 pub ttl: Option<u64>,
752}
753
754#[derive(Debug, Clone, Serialize, Deserialize)]
756pub struct RelatedTaskMetadata {
757 #[serde(rename = "taskId")]
759 pub task_id: String,
760}
761
762#[derive(Debug, Clone, Serialize, Deserialize)]
764pub struct Task {
765 #[serde(rename = "taskId")]
767 pub task_id: String,
768
769 pub status: TaskStatus,
771
772 #[serde(rename = "statusMessage", skip_serializing_if = "Option::is_none")]
774 pub status_message: Option<String>,
775
776 #[serde(rename = "createdAt")]
778 pub created_at: String,
779
780 #[serde(rename = "lastUpdatedAt")]
782 pub last_updated_at: String,
783
784 pub ttl: Option<u64>,
786
787 #[serde(rename = "pollInterval", skip_serializing_if = "Option::is_none")]
789 pub poll_interval: Option<u64>,
790}
791
792#[derive(Debug, Clone, Serialize, Deserialize)]
794pub struct CreateTaskResult {
795 pub task: Task,
796}
797
798#[derive(Debug, Clone, Serialize, Deserialize)]
800pub struct GetTaskParams {
801 #[serde(rename = "taskId")]
803 pub task_id: String,
804}
805
806#[derive(Debug, Clone, Serialize, Deserialize)]
808pub struct GetTaskPayloadParams {
809 #[serde(rename = "taskId")]
811 pub task_id: String,
812}
813
814#[derive(Debug, Clone, Serialize, Deserialize)]
816pub struct CancelTaskParams {
817 #[serde(rename = "taskId")]
819 pub task_id: String,
820}
821
822#[derive(Debug, Clone, Serialize, Deserialize, Default)]
824pub struct ListTasksParams {
825 #[serde(skip_serializing_if = "Option::is_none")]
827 pub cursor: Option<String>,
828}
829
830#[derive(Debug, Clone, Serialize, Deserialize)]
832pub struct ListTasksResult {
833 pub tasks: Vec<Task>,
834 #[serde(rename = "nextCursor", skip_serializing_if = "Option::is_none")]
835 pub next_cursor: Option<String>,
836}
837
838#[derive(Debug, Clone, Serialize, Deserialize)]
840pub struct TaskStatusNotificationParams {
841 #[serde(rename = "taskId")]
843 pub task_id: String,
844
845 pub status: TaskStatus,
847
848 #[serde(rename = "statusMessage", skip_serializing_if = "Option::is_none")]
850 pub status_message: Option<String>,
851
852 #[serde(rename = "createdAt")]
854 pub created_at: String,
855
856 #[serde(rename = "lastUpdatedAt")]
858 pub last_updated_at: String,
859
860 pub ttl: Option<u64>,
862
863 #[serde(rename = "pollInterval", skip_serializing_if = "Option::is_none")]
865 pub poll_interval: Option<u64>,
866}
867
868#[derive(Debug, Clone, Serialize, Deserialize)]
874pub struct ElicitRequestFormParams {
875 #[serde(skip_serializing_if = "Option::is_none")]
877 pub mode: Option<String>,
878
879 pub message: String,
881
882 #[serde(rename = "requestedSchema")]
884 pub requested_schema: Value,
885
886 #[serde(skip_serializing_if = "Option::is_none")]
888 pub task: Option<TaskMetadata>,
889
890 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
892 pub meta: Option<Value>,
893}
894
895#[derive(Debug, Clone, Serialize, Deserialize)]
897pub struct ElicitRequestUrlParams {
898 pub mode: String,
900
901 pub message: String,
903
904 #[serde(rename = "elicitationId")]
906 pub elicitation_id: String,
907
908 pub url: String,
910
911 #[serde(skip_serializing_if = "Option::is_none")]
913 pub task: Option<TaskMetadata>,
914
915 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
917 pub meta: Option<Value>,
918}
919
920#[derive(Debug, Clone, Serialize, Deserialize)]
922#[serde(untagged)]
923pub enum ElicitRequestParams {
924 Form(ElicitRequestFormParams),
925 Url(ElicitRequestUrlParams),
926}
927
928#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
930#[serde(rename_all = "snake_case")]
931pub enum ElicitAction {
932 Accept,
934 Decline,
936 Cancel,
938}
939
940#[derive(Debug, Clone, Serialize, Deserialize)]
942pub struct ElicitResult {
943 pub action: ElicitAction,
945
946 #[serde(skip_serializing_if = "Option::is_none")]
948 pub content: Option<Value>,
949}
950
951#[derive(Debug, Clone, Serialize, Deserialize)]
953pub struct ElicitationCompleteParams {
954 #[serde(rename = "elicitationId")]
956 pub elicitation_id: String,
957}
958
959#[derive(Debug, Clone, Serialize, Deserialize)]
965pub struct StringSchema {
966 #[serde(rename = "type")]
967 pub schema_type: String, #[serde(skip_serializing_if = "Option::is_none")]
969 pub title: Option<String>,
970 #[serde(skip_serializing_if = "Option::is_none")]
971 pub description: Option<String>,
972 #[serde(rename = "minLength", skip_serializing_if = "Option::is_none")]
973 pub min_length: Option<u32>,
974 #[serde(rename = "maxLength", skip_serializing_if = "Option::is_none")]
975 pub max_length: Option<u32>,
976 #[serde(skip_serializing_if = "Option::is_none")]
977 pub format: Option<StringSchemaFormat>,
978 #[serde(skip_serializing_if = "Option::is_none")]
979 pub default: Option<String>,
980}
981
982#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
984#[serde(rename_all = "kebab-case")]
985pub enum StringSchemaFormat {
986 Email,
987 Uri,
988 Date,
989 DateTime,
990}
991
992#[derive(Debug, Clone, Serialize, Deserialize)]
994pub struct NumberSchema {
995 #[serde(rename = "type")]
996 pub schema_type: String, #[serde(skip_serializing_if = "Option::is_none")]
998 pub title: Option<String>,
999 #[serde(skip_serializing_if = "Option::is_none")]
1000 pub description: Option<String>,
1001 #[serde(skip_serializing_if = "Option::is_none")]
1002 pub minimum: Option<f64>,
1003 #[serde(skip_serializing_if = "Option::is_none")]
1004 pub maximum: Option<f64>,
1005 #[serde(skip_serializing_if = "Option::is_none")]
1006 pub default: Option<f64>,
1007}
1008
1009#[derive(Debug, Clone, Serialize, Deserialize)]
1011pub struct BooleanSchema {
1012 #[serde(rename = "type")]
1013 pub schema_type: String, #[serde(skip_serializing_if = "Option::is_none")]
1015 pub title: Option<String>,
1016 #[serde(skip_serializing_if = "Option::is_none")]
1017 pub description: Option<String>,
1018 #[serde(skip_serializing_if = "Option::is_none")]
1019 pub default: Option<bool>,
1020}
1021
1022#[derive(Debug, Clone, Serialize, Deserialize)]
1024pub struct TitledEnumOption {
1025 #[serde(rename = "const")]
1027 pub const_value: String,
1028 pub title: String,
1030}
1031
1032#[derive(Debug, Clone, Serialize, Deserialize)]
1034pub struct MultiSelectEnumItems {
1035 #[serde(rename = "type")]
1036 pub schema_type: String, #[serde(rename = "enum")]
1039 pub enum_values: Vec<String>,
1040}
1041
1042#[derive(Debug, Clone, Serialize, Deserialize)]
1044pub struct TitledMultiSelectEnumItems {
1045 #[serde(rename = "anyOf")]
1047 pub any_of: Vec<TitledEnumOption>,
1048}
1049
1050#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
1056#[serde(rename_all = "snake_case")]
1057pub enum ToolChoiceMode {
1058 #[default]
1060 Auto,
1061 Required,
1063 None,
1065}
1066
1067#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1069pub struct ToolChoice {
1070 #[serde(skip_serializing_if = "Option::is_none")]
1072 pub mode: Option<ToolChoiceMode>,
1073}
1074
1075#[derive(Debug, Clone, Serialize, Deserialize)]
1077pub struct ToolUseContent {
1078 pub id: String,
1080 pub name: String,
1082 pub input: Value,
1084 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1086 pub meta: Option<Value>,
1087}
1088
1089#[derive(Debug, Clone, Serialize, Deserialize)]
1091pub struct ToolResultContent {
1092 #[serde(rename = "toolUseId")]
1094 pub tool_use_id: String,
1095 pub content: Vec<ToolContent>,
1097 #[serde(rename = "structuredContent", skip_serializing_if = "Option::is_none")]
1099 pub structured_content: Option<Value>,
1100 #[serde(rename = "isError", skip_serializing_if = "Option::is_none")]
1102 pub is_error: Option<bool>,
1103 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1105 pub meta: Option<Value>,
1106}
1107
1108#[derive(Debug, Clone, Serialize, Deserialize)]
1110#[serde(tag = "type")]
1111pub enum SamplingContent {
1112 #[serde(rename = "text")]
1113 Text {
1114 text: String,
1115 #[serde(skip_serializing_if = "Option::is_none")]
1116 annotations: Option<Annotations>,
1117 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1118 meta: Option<Value>,
1119 },
1120 #[serde(rename = "image")]
1121 Image {
1122 data: String,
1123 #[serde(rename = "mimeType")]
1124 mime_type: String,
1125 #[serde(skip_serializing_if = "Option::is_none")]
1126 annotations: Option<Annotations>,
1127 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1128 meta: Option<Value>,
1129 },
1130 #[serde(rename = "audio")]
1131 Audio {
1132 data: String,
1133 #[serde(rename = "mimeType")]
1134 mime_type: String,
1135 #[serde(skip_serializing_if = "Option::is_none")]
1136 annotations: Option<Annotations>,
1137 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1138 meta: Option<Value>,
1139 },
1140 #[serde(rename = "tool_use")]
1141 ToolUse {
1142 id: String,
1143 name: String,
1144 input: Value,
1145 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1146 meta: Option<Value>,
1147 },
1148 #[serde(rename = "tool_result")]
1149 ToolResult {
1150 #[serde(rename = "toolUseId")]
1151 tool_use_id: String,
1152 content: Vec<ToolContent>,
1153 #[serde(rename = "structuredContent", skip_serializing_if = "Option::is_none")]
1154 structured_content: Option<Value>,
1155 #[serde(rename = "isError", skip_serializing_if = "Option::is_none")]
1156 is_error: Option<bool>,
1157 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1158 meta: Option<Value>,
1159 },
1160}
1161
1162#[derive(Debug, Clone, Serialize, Deserialize)]
1164pub struct SamplingMessage {
1165 pub role: Role,
1166 pub content: Vec<SamplingContent>,
1167 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1168 pub meta: Option<Value>,
1169}
1170
1171#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1173pub struct ModelHint {
1174 #[serde(skip_serializing_if = "Option::is_none")]
1176 pub name: Option<String>,
1177}
1178
1179#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1181pub struct ModelPreferences {
1182 #[serde(skip_serializing_if = "Option::is_none")]
1184 pub hints: Option<Vec<ModelHint>>,
1185
1186 #[serde(rename = "costPriority", skip_serializing_if = "Option::is_none")]
1188 pub cost_priority: Option<f64>,
1189
1190 #[serde(rename = "speedPriority", skip_serializing_if = "Option::is_none")]
1192 pub speed_priority: Option<f64>,
1193
1194 #[serde(
1196 rename = "intelligencePriority",
1197 skip_serializing_if = "Option::is_none"
1198 )]
1199 pub intelligence_priority: Option<f64>,
1200}
1201
1202#[derive(Debug, Clone, Serialize, Deserialize)]
1204pub struct CreateMessageParams {
1205 pub messages: Vec<SamplingMessage>,
1206
1207 #[serde(rename = "modelPreferences", skip_serializing_if = "Option::is_none")]
1209 pub model_preferences: Option<ModelPreferences>,
1210
1211 #[serde(rename = "systemPrompt", skip_serializing_if = "Option::is_none")]
1213 pub system_prompt: Option<String>,
1214
1215 #[serde(rename = "includeContext", skip_serializing_if = "Option::is_none")]
1217 pub include_context: Option<String>,
1218
1219 #[serde(skip_serializing_if = "Option::is_none")]
1220 pub temperature: Option<f64>,
1221
1222 #[serde(rename = "maxTokens")]
1224 pub max_tokens: u32,
1225
1226 #[serde(rename = "stopSequences", skip_serializing_if = "Option::is_none")]
1227 pub stop_sequences: Option<Vec<String>>,
1228
1229 #[serde(skip_serializing_if = "Option::is_none")]
1231 pub metadata: Option<Value>,
1232
1233 #[serde(skip_serializing_if = "Option::is_none")]
1235 pub tools: Option<Vec<McpToolDefinition>>,
1236
1237 #[serde(rename = "toolChoice", skip_serializing_if = "Option::is_none")]
1239 pub tool_choice: Option<ToolChoice>,
1240
1241 #[serde(skip_serializing_if = "Option::is_none")]
1243 pub task: Option<TaskMetadata>,
1244
1245 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1247 pub meta: Option<Value>,
1248}
1249
1250#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1252#[serde(rename_all = "camelCase")]
1253pub enum StopReason {
1254 EndTurn,
1256 StopSequence,
1258 MaxTokens,
1260 ToolUse,
1262 #[serde(untagged)]
1264 Other(String),
1265}
1266
1267#[derive(Debug, Clone, Serialize, Deserialize)]
1269pub struct CreateMessageResult {
1270 pub role: Role,
1271 pub content: Vec<SamplingContent>,
1272 pub model: String,
1274 #[serde(rename = "stopReason", skip_serializing_if = "Option::is_none")]
1276 pub stop_reason: Option<String>,
1277 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1278 pub meta: Option<Value>,
1279}
1280
1281#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1287#[serde(rename_all = "snake_case")]
1288pub enum LoggingLevel {
1289 Debug,
1290 Info,
1291 Notice,
1292 Warning,
1293 Error,
1294 Critical,
1295 Alert,
1296 Emergency,
1297}
1298
1299#[derive(Debug, Clone, Serialize, Deserialize)]
1301pub struct SetLevelParams {
1302 pub level: LoggingLevel,
1304}
1305
1306#[derive(Debug, Clone, Serialize, Deserialize)]
1308pub struct LoggingMessageParams {
1309 pub level: LoggingLevel,
1311 #[serde(skip_serializing_if = "Option::is_none")]
1313 pub logger: Option<String>,
1314 pub data: Value,
1316}
1317
1318#[derive(Debug, Clone, Serialize, Deserialize)]
1324pub struct ProgressNotificationParams {
1325 #[serde(rename = "progressToken")]
1327 pub progress_token: ProgressToken,
1328
1329 pub progress: f64,
1331
1332 #[serde(skip_serializing_if = "Option::is_none")]
1334 pub total: Option<f64>,
1335
1336 #[serde(skip_serializing_if = "Option::is_none")]
1338 pub message: Option<String>,
1339}
1340
1341#[derive(Debug, Clone, Serialize, Deserialize)]
1343#[serde(untagged)]
1344pub enum ProgressToken {
1345 String(String),
1346 Number(i64),
1347}
1348
1349#[derive(Debug, Clone, Serialize, Deserialize)]
1355pub struct Root {
1356 pub uri: String,
1358
1359 #[serde(skip_serializing_if = "Option::is_none")]
1361 pub name: Option<String>,
1362
1363 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
1365 pub meta: Option<Value>,
1366}
1367
1368#[derive(Debug, Clone, Serialize, Deserialize)]
1370pub struct ListRootsResult {
1371 pub roots: Vec<Root>,
1372}
1373
1374#[derive(Debug, Clone, Serialize, Deserialize)]
1380pub struct PromptReference {
1381 #[serde(rename = "type")]
1382 pub ref_type: String, pub name: String,
1384 #[serde(skip_serializing_if = "Option::is_none")]
1385 pub title: Option<String>,
1386}
1387
1388#[derive(Debug, Clone, Serialize, Deserialize)]
1390pub struct ResourceTemplateReference {
1391 #[serde(rename = "type")]
1392 pub ref_type: String, pub uri: String,
1394}
1395
1396#[derive(Debug, Clone, Serialize, Deserialize)]
1398pub struct CompleteParams {
1399 pub r#ref: Value, pub argument: CompleteArgument,
1401 #[serde(skip_serializing_if = "Option::is_none")]
1402 pub context: Option<CompleteContext>,
1403}
1404
1405#[derive(Debug, Clone, Serialize, Deserialize)]
1407pub struct CompleteArgument {
1408 pub name: String,
1410 pub value: String,
1412}
1413
1414#[derive(Debug, Clone, Serialize, Deserialize)]
1416pub struct CompleteContext {
1417 #[serde(skip_serializing_if = "Option::is_none")]
1419 pub arguments: Option<Value>,
1420}
1421
1422#[derive(Debug, Clone, Serialize, Deserialize)]
1424pub struct CompleteResult {
1425 pub completion: CompletionData,
1426}
1427
1428#[derive(Debug, Clone, Serialize, Deserialize)]
1430pub struct CompletionData {
1431 pub values: Vec<String>,
1433 #[serde(skip_serializing_if = "Option::is_none")]
1435 pub total: Option<u32>,
1436 #[serde(rename = "hasMore", skip_serializing_if = "Option::is_none")]
1438 pub has_more: Option<bool>,
1439}
1440
1441#[cfg(test)]
1442mod tests {
1443 use super::*;
1444
1445 #[test]
1446 fn test_jsonrpc_request_serialization() {
1447 let req = JsonRpcRequest::new(JsonRpcId::Number(1), "tools/list", None);
1448
1449 let json = serde_json::to_string(&req).unwrap();
1450 assert!(json.contains(r#""jsonrpc":"2.0""#));
1451 assert!(json.contains(r#""id":1"#));
1452 assert!(json.contains(r#""method":"tools/list""#));
1453 }
1454
1455 #[test]
1456 fn test_jsonrpc_response_success() {
1457 let json = r#"{"jsonrpc":"2.0","id":1,"result":{"tools":[]}}"#;
1458 let resp: JsonRpcResponse = serde_json::from_str(json).unwrap();
1459
1460 assert!(matches!(resp.payload, JsonRpcPayload::Success { .. }));
1461 }
1462
1463 #[test]
1464 fn test_jsonrpc_response_error() {
1465 let json =
1466 r#"{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"Method not found"}}"#;
1467 let resp: JsonRpcResponse = serde_json::from_str(json).unwrap();
1468
1469 assert!(matches!(resp.payload, JsonRpcPayload::Error { .. }));
1470 }
1471
1472 #[test]
1473 fn test_tool_content_text() {
1474 let content = ToolContent::text("Hello, world!");
1475 assert_eq!(content.as_text(), Some("Hello, world!"));
1476
1477 let json = serde_json::to_string(&content).unwrap();
1478 assert!(json.contains(r#""type":"text""#));
1479 assert!(json.contains(r#""text":"Hello, world!""#));
1480 }
1481
1482 #[test]
1483 fn test_jsonrpc_id_display() {
1484 assert_eq!(JsonRpcId::Number(42).to_string(), "42");
1485 assert_eq!(JsonRpcId::String("test".to_string()).to_string(), "test");
1486 assert_eq!(JsonRpcId::Null.to_string(), "null");
1487 }
1488
1489 #[test]
1490 fn test_mcp_tool_deserialization() {
1491 let json = r#"{
1492 "name": "test_tool",
1493 "description": "A test tool",
1494 "input_schema": {
1495 "type": "object",
1496 "properties": {
1497 "name": {"type": "string"}
1498 },
1499 "required": ["name"]
1500 }
1501 }"#;
1502
1503 let tool: McpToolDefinition = serde_json::from_str(json).unwrap();
1504 assert_eq!(tool.name, "test_tool");
1505 assert_eq!(tool.description, Some("A test tool".to_string()));
1506 assert_eq!(tool.input_schema["type"], "object");
1507 }
1508}