1pub mod core;
48pub mod initialization;
49pub mod logging;
50pub mod prompts;
51pub mod resources;
52pub mod sampling;
53pub mod tools;
54
55pub use core::*;
56pub use initialization::*;
57pub use logging::{
58 LogLevel, LoggingNotification, ProgressNotification,
59 PromptListChangedNotification as LoggingPromptListChangedNotification,
60 ResourceListChangedNotification as LoggingResourceListChangedNotification,
61 ResourceUpdatedNotification as LoggingResourceUpdatedNotification, SetLevelRequest,
62 ToolListChangedNotification as LoggingToolListChangedNotification,
63};
64pub use prompts::{
65 GetPromptRequest, GetPromptResponse, ListPromptsRequest, ListPromptsResponse,
66 MessageRole as PromptMessageRole, Prompt, PromptContent, PromptListChangedNotification,
67 PromptMessage, ResourceReference as PromptResourceReference,
68};
69pub use resources::{
70 ListResourcesRequest, ListResourcesResponse, ReadResourceRequest, ReadResourceResponse,
71 Resource, ResourceContent, ResourceListChangedNotification, ResourceUpdatedNotification,
72 SubscribeRequest, UnsubscribeRequest,
73};
74pub use sampling::{
75 CompleteRequest, CompleteResponse, CompletionArgument, CompletionResult, CostPriority,
76 IntelligencePriority, MessageRole, ModelPreferences, SamplingContent, SamplingMessage,
77 SpeedPriority, StopReason,
78};
79pub use tools::{
80 CallToolRequest, CallToolResponse, ListToolsRequest, ListToolsResponse,
81 ResourceReference as ToolResourceReference, Tool, ToolListChangedNotification, ToolResult,
82};
83
84use serde::{Deserialize, Serialize};
85use std::collections::HashMap;
86
87#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
92pub enum ProtocolVersion {
93 #[serde(rename = "2024-11-05")]
95 V2024_11_05,
96
97 #[serde(rename = "2025-03-26")]
99 V2025_03_26,
100
101 #[serde(untagged)]
104 Custom(String),
105}
106
107impl ProtocolVersion {
108 pub fn as_str(&self) -> &str {
110 match self {
111 Self::V2024_11_05 => "2024-11-05",
112 Self::V2025_03_26 => "2025-03-26",
113 Self::Custom(version) => version,
114 }
115 }
116
117 pub fn is_supported(&self) -> bool {
119 matches!(self, Self::V2024_11_05 | Self::V2025_03_26)
120 }
121
122 pub fn supported_versions() -> Vec<Self> {
124 vec![Self::V2024_11_05, Self::V2025_03_26]
125 }
126}
127
128impl Default for ProtocolVersion {
129 fn default() -> Self {
130 Self::V2025_03_26
131 }
132}
133
134impl std::fmt::Display for ProtocolVersion {
135 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136 write!(f, "{}", self.as_str())
137 }
138}
139
140#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
146pub struct Capabilities {
147 #[serde(flatten)]
149 pub standard: StandardCapabilities,
150
151 #[serde(flatten)]
153 pub custom: HashMap<String, serde_json::Value>,
154}
155
156#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
161pub struct StandardCapabilities {
162 #[serde(skip_serializing_if = "Option::is_none")]
164 pub tools: Option<ToolCapabilities>,
165
166 #[serde(skip_serializing_if = "Option::is_none")]
168 pub resources: Option<ResourceCapabilities>,
169
170 #[serde(skip_serializing_if = "Option::is_none")]
172 pub prompts: Option<PromptCapabilities>,
173
174 #[serde(skip_serializing_if = "Option::is_none")]
176 pub sampling: Option<SamplingCapabilities>,
177
178 #[serde(skip_serializing_if = "Option::is_none")]
180 pub logging: Option<LoggingCapabilities>,
181
182 #[serde(skip_serializing_if = "Option::is_none")]
184 pub roots: Option<RootsCapabilities>,
185}
186
187#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
189pub struct ToolCapabilities {
190 #[serde(skip_serializing_if = "Option::is_none")]
192 pub list_changed: Option<bool>,
193}
194
195#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
197pub struct ResourceCapabilities {
198 #[serde(skip_serializing_if = "Option::is_none")]
200 pub subscribe: Option<bool>,
201
202 #[serde(skip_serializing_if = "Option::is_none")]
204 pub list_changed: Option<bool>,
205}
206
207#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
209pub struct PromptCapabilities {
210 #[serde(skip_serializing_if = "Option::is_none")]
212 pub list_changed: Option<bool>,
213}
214
215#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
217pub struct SamplingCapabilities {
218 #[serde(skip_serializing_if = "Option::is_none")]
220 pub enabled: Option<bool>,
221}
222
223#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
225pub struct LoggingCapabilities {
226 #[serde(skip_serializing_if = "Option::is_none")]
228 pub level: Option<bool>,
229}
230
231#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
233pub struct RootsCapabilities {
234 #[serde(skip_serializing_if = "Option::is_none")]
236 pub list_changed: Option<bool>,
237}
238
239#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
244pub struct Implementation {
245 pub name: String,
247
248 pub version: String,
250
251 #[serde(flatten)]
253 pub metadata: HashMap<String, serde_json::Value>,
254}
255
256impl Implementation {
257 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
259 Self {
260 name: name.into(),
261 version: version.into(),
262 metadata: HashMap::new(),
263 }
264 }
265
266 pub fn with_metadata(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
268 self.metadata.insert(key.into(), value);
269 self
270 }
271}
272
273#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
278#[serde(untagged)]
279pub enum ProgressToken {
280 String(String),
282 Number(i64),
284}
285
286impl From<String> for ProgressToken {
287 fn from(s: String) -> Self {
288 Self::String(s)
289 }
290}
291
292impl From<&str> for ProgressToken {
293 fn from(s: &str) -> Self {
294 Self::String(s.to_string())
295 }
296}
297
298impl From<i64> for ProgressToken {
299 fn from(n: i64) -> Self {
300 Self::Number(n)
301 }
302}
303
304impl std::fmt::Display for ProgressToken {
305 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
306 match self {
307 Self::String(s) => write!(f, "{}", s),
308 Self::Number(n) => write!(f, "{}", n),
309 }
310 }
311}
312
313#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
317pub struct PaginationCursor {
318 pub cursor: String,
320}
321
322impl PaginationCursor {
323 pub fn new(cursor: impl Into<String>) -> Self {
325 Self {
326 cursor: cursor.into(),
327 }
328 }
329}
330
331impl From<String> for PaginationCursor {
332 fn from(cursor: String) -> Self {
333 Self::new(cursor)
334 }
335}
336
337impl From<&str> for PaginationCursor {
338 fn from(cursor: &str) -> Self {
339 Self::new(cursor)
340 }
341}
342
343#[cfg(test)]
344mod tests {
345 use super::*;
346 use serde_json;
347
348 #[test]
349 fn test_protocol_version_serialization() {
350 let version = ProtocolVersion::V2024_11_05;
351 let json = serde_json::to_string(&version).unwrap();
352 assert_eq!(json, "\"2024-11-05\"");
353
354 let deserialized: ProtocolVersion = serde_json::from_str(&json).unwrap();
355 assert_eq!(deserialized, version);
356 }
357
358 #[test]
359 fn test_protocol_version_custom() {
360 let custom = ProtocolVersion::Custom("2025-01-01".to_string());
361 assert_eq!(custom.as_str(), "2025-01-01");
362 assert!(!custom.is_supported());
363 }
364
365 #[test]
366 fn test_capabilities_serialization() {
367 let capabilities = Capabilities {
368 standard: StandardCapabilities {
369 tools: Some(ToolCapabilities {
370 list_changed: Some(true),
371 }),
372 resources: Some(ResourceCapabilities {
373 subscribe: Some(true),
374 list_changed: Some(false),
375 }),
376 ..Default::default()
377 },
378 custom: {
379 let mut custom = HashMap::new();
380 custom.insert("experimental".to_string(), serde_json::json!(true));
381 custom
382 },
383 };
384
385 let json = serde_json::to_value(&capabilities).unwrap();
386 let deserialized: Capabilities = serde_json::from_value(json).unwrap();
387 assert_eq!(deserialized, capabilities);
388 }
389
390 #[test]
391 fn test_implementation_creation() {
392 let impl_info = Implementation::new("mcp-probe", "0.1.0")
393 .with_metadata("platform", serde_json::json!("rust"));
394
395 assert_eq!(impl_info.name, "mcp-probe");
396 assert_eq!(impl_info.version, "0.1.0");
397 assert_eq!(
398 impl_info.metadata.get("platform").unwrap(),
399 &serde_json::json!("rust")
400 );
401 }
402
403 #[test]
404 fn test_progress_token_variants() {
405 let string_token = ProgressToken::from("progress-1");
406 let number_token = ProgressToken::from(42i64);
407
408 assert_eq!(string_token.to_string(), "progress-1");
409 assert_eq!(number_token.to_string(), "42");
410
411 let json_string = serde_json::to_string(&string_token).unwrap();
413 let json_number = serde_json::to_string(&number_token).unwrap();
414
415 assert_eq!(json_string, "\"progress-1\"");
416 assert_eq!(json_number, "42");
417 }
418}