1use serde::{Deserialize, Serialize};
10use serde_json::Value;
11use std::collections::HashMap;
12
13#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
15#[serde(rename_all = "lowercase")]
16pub enum LogLevel {
17 Debug,
19 Info,
21 Notice,
23 Warning,
25 Error,
27 Critical,
29}
30
31impl LogLevel {
32 pub fn all() -> Vec<Self> {
34 vec![
35 Self::Debug,
36 Self::Info,
37 Self::Notice,
38 Self::Warning,
39 Self::Error,
40 Self::Critical,
41 ]
42 }
43
44 pub fn is_more_verbose_than(&self, other: &Self) -> bool {
46 self < other
47 }
48
49 pub fn is_less_verbose_than(&self, other: &Self) -> bool {
51 self > other
52 }
53}
54
55impl std::fmt::Display for LogLevel {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 let s = match self {
58 Self::Debug => "debug",
59 Self::Info => "info",
60 Self::Notice => "notice",
61 Self::Warning => "warning",
62 Self::Error => "error",
63 Self::Critical => "critical",
64 };
65 write!(f, "{}", s)
66 }
67}
68
69#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
71pub struct SetLevelRequest {
72 pub level: LogLevel,
74}
75
76impl SetLevelRequest {
77 pub fn new(level: LogLevel) -> Self {
79 Self { level }
80 }
81}
82
83#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
85pub struct LoggingNotification {
86 pub level: LogLevel,
88
89 pub data: Value,
91
92 #[serde(skip_serializing_if = "Option::is_none")]
94 pub logger: Option<String>,
95}
96
97impl LoggingNotification {
98 pub fn new(level: LogLevel, data: Value) -> Self {
100 Self {
101 level,
102 data,
103 logger: None,
104 }
105 }
106
107 pub fn with_logger(level: LogLevel, data: Value, logger: impl Into<String>) -> Self {
109 Self {
110 level,
111 data,
112 logger: Some(logger.into()),
113 }
114 }
115
116 pub fn debug(message: impl Into<String>) -> Self {
118 Self::new(LogLevel::Debug, Value::String(message.into()))
119 }
120
121 pub fn info(message: impl Into<String>) -> Self {
123 Self::new(LogLevel::Info, Value::String(message.into()))
124 }
125
126 pub fn notice(message: impl Into<String>) -> Self {
128 Self::new(LogLevel::Notice, Value::String(message.into()))
129 }
130
131 pub fn warning(message: impl Into<String>) -> Self {
133 Self::new(LogLevel::Warning, Value::String(message.into()))
134 }
135
136 pub fn error(message: impl Into<String>) -> Self {
138 Self::new(LogLevel::Error, Value::String(message.into()))
139 }
140
141 pub fn critical(message: impl Into<String>) -> Self {
143 Self::new(LogLevel::Critical, Value::String(message.into()))
144 }
145}
146
147#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
149pub struct ProgressNotification {
150 pub progress_token: ProgressToken,
152
153 pub progress: f64,
155
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub total: Option<u64>,
159}
160
161impl ProgressNotification {
162 pub fn new(progress_token: impl Into<ProgressToken>, progress: f64) -> Self {
164 Self {
165 progress_token: progress_token.into(),
166 progress,
167 total: None,
168 }
169 }
170
171 pub fn with_total(progress_token: impl Into<ProgressToken>, progress: f64, total: u64) -> Self {
173 Self {
174 progress_token: progress_token.into(),
175 progress,
176 total: Some(total),
177 }
178 }
179}
180
181#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
183#[serde(untagged)]
184pub enum ProgressToken {
185 String(String),
187 Number(i64),
189}
190
191impl From<String> for ProgressToken {
192 fn from(s: String) -> Self {
193 Self::String(s)
194 }
195}
196
197impl From<&str> for ProgressToken {
198 fn from(s: &str) -> Self {
199 Self::String(s.to_string())
200 }
201}
202
203impl From<i64> for ProgressToken {
204 fn from(n: i64) -> Self {
205 Self::Number(n)
206 }
207}
208
209impl From<i32> for ProgressToken {
210 fn from(n: i32) -> Self {
211 Self::Number(n as i64)
212 }
213}
214
215impl std::fmt::Display for ProgressToken {
216 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217 match self {
218 Self::String(s) => write!(f, "{}", s),
219 Self::Number(n) => write!(f, "{}", n),
220 }
221 }
222}
223
224#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
226pub struct ResourceUpdatedNotification {
227 pub uri: String,
229
230 #[serde(flatten)]
232 pub metadata: HashMap<String, Value>,
233}
234
235impl ResourceUpdatedNotification {
236 pub fn new(uri: impl Into<String>) -> Self {
238 Self {
239 uri: uri.into(),
240 metadata: HashMap::new(),
241 }
242 }
243
244 pub fn with_metadata(mut self, key: impl Into<String>, value: Value) -> Self {
246 self.metadata.insert(key.into(), value);
247 self
248 }
249}
250
251#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
253pub struct ResourceListChangedNotification {
254 #[serde(flatten)]
256 pub metadata: HashMap<String, Value>,
257}
258
259impl ResourceListChangedNotification {
260 pub fn new() -> Self {
262 Self::default()
263 }
264
265 pub fn with_metadata(mut self, key: impl Into<String>, value: Value) -> Self {
267 self.metadata.insert(key.into(), value);
268 self
269 }
270}
271
272#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
274pub struct ToolListChangedNotification {
275 #[serde(flatten)]
277 pub metadata: HashMap<String, Value>,
278}
279
280impl ToolListChangedNotification {
281 pub fn new() -> Self {
283 Self::default()
284 }
285
286 pub fn with_metadata(mut self, key: impl Into<String>, value: Value) -> Self {
288 self.metadata.insert(key.into(), value);
289 self
290 }
291}
292
293#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
295pub struct PromptListChangedNotification {
296 #[serde(flatten)]
298 pub metadata: HashMap<String, Value>,
299}
300
301impl PromptListChangedNotification {
302 pub fn new() -> Self {
304 Self::default()
305 }
306
307 pub fn with_metadata(mut self, key: impl Into<String>, value: Value) -> Self {
309 self.metadata.insert(key.into(), value);
310 self
311 }
312}
313
314#[cfg(test)]
315mod tests {
316 use super::*;
317 use serde_json::json;
318
319 #[test]
320 fn test_log_level_ordering() {
321 assert!(LogLevel::Debug < LogLevel::Info);
322 assert!(LogLevel::Info < LogLevel::Notice);
323 assert!(LogLevel::Notice < LogLevel::Warning);
324 assert!(LogLevel::Warning < LogLevel::Error);
325 assert!(LogLevel::Error < LogLevel::Critical);
326
327 assert!(LogLevel::Debug.is_more_verbose_than(&LogLevel::Error));
328 assert!(LogLevel::Error.is_less_verbose_than(&LogLevel::Debug));
329 }
330
331 #[test]
332 fn test_log_level_serialization() {
333 let levels = LogLevel::all();
334 let expected = ["debug", "info", "notice", "warning", "error", "critical"];
335
336 for (level, expected) in levels.iter().zip(expected.iter()) {
337 let json = serde_json::to_string(level).unwrap();
338 assert_eq!(json, format!("\"{}\"", expected));
339 assert_eq!(level.to_string(), *expected);
340 }
341 }
342
343 #[test]
344 fn test_set_level_request() {
345 let request = SetLevelRequest::new(LogLevel::Warning);
346 assert_eq!(request.level, LogLevel::Warning);
347
348 let json = serde_json::to_string(&request).unwrap();
349 let deserialized: SetLevelRequest = serde_json::from_str(&json).unwrap();
350 assert_eq!(request, deserialized);
351 }
352
353 #[test]
354 fn test_logging_notification() {
355 let notification = LoggingNotification::with_logger(
356 LogLevel::Info,
357 json!("This is a test message"),
358 "test_logger",
359 );
360
361 assert_eq!(notification.level, LogLevel::Info);
362 assert_eq!(notification.data, json!("This is a test message"));
363 assert_eq!(notification.logger, Some("test_logger".to_string()));
364 }
365
366 #[test]
367 fn test_logging_notification_helpers() {
368 let debug = LoggingNotification::debug("Debug message");
369 let info = LoggingNotification::info("Info message");
370 let warning = LoggingNotification::warning("Warning message");
371 let error = LoggingNotification::error("Error message");
372
373 assert_eq!(debug.level, LogLevel::Debug);
374 assert_eq!(info.level, LogLevel::Info);
375 assert_eq!(warning.level, LogLevel::Warning);
376 assert_eq!(error.level, LogLevel::Error);
377 }
378
379 #[test]
380 fn test_progress_notification() {
381 let progress = ProgressNotification::new("operation-1", 0.5);
382 assert_eq!(
383 progress.progress_token,
384 ProgressToken::String("operation-1".to_string())
385 );
386 assert_eq!(progress.progress, 0.5);
387 assert_eq!(progress.total, None);
388
389 let progress_with_total = ProgressNotification::with_total("operation-2", 0.75, 100);
390 assert_eq!(progress_with_total.total, Some(100));
391 }
392
393 #[test]
394 fn test_progress_token() {
395 let string_token = ProgressToken::from("test");
396 let number_token = ProgressToken::from(42i64);
397
398 assert_eq!(string_token.to_string(), "test");
399 assert_eq!(number_token.to_string(), "42");
400
401 let json_string = serde_json::to_string(&string_token).unwrap();
403 let json_number = serde_json::to_string(&number_token).unwrap();
404
405 assert_eq!(json_string, "\"test\"");
406 assert_eq!(json_number, "42");
407 }
408
409 #[test]
410 fn test_notification_with_metadata() {
411 let notification = ResourceUpdatedNotification::new("file:///test.txt")
412 .with_metadata("timestamp", json!("2024-01-01T00:00:00Z"))
413 .with_metadata("size", json!(1024));
414
415 assert_eq!(notification.uri, "file:///test.txt");
416 assert_eq!(
417 notification.metadata.get("timestamp"),
418 Some(&json!("2024-01-01T00:00:00Z"))
419 );
420 assert_eq!(notification.metadata.get("size"), Some(&json!(1024)));
421 }
422}