adk_tool/mcp/manager/status.rs
1//! Server status tracking.
2//!
3//! Defines the [`ServerStatus`] enum representing the current lifecycle state
4//! of a managed MCP server.
5
6use serde::{Deserialize, Serialize};
7
8/// Current lifecycle state of a managed MCP server.
9///
10/// Transitions:
11/// - `Stopped` → `Running` (on successful start)
12/// - `Stopped` → `FailedToStart` (on start failure)
13/// - `Running` → `Stopped` (on manual stop or shutdown)
14/// - `Running` → `Crashed` (on health check failure or unexpected exit)
15/// - `Running` → `Restarting` (during restart)
16/// - `Crashed` → `Restarting` (on auto-restart)
17/// - `Restarting` → `Running` (on successful restart)
18/// - `Restarting` → `FailedToStart` (on restart failure)
19/// - `Disabled` (set at construction, no transitions out unless re-configured)
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
21pub enum ServerStatus {
22 /// The server process is running and the MCP connection is active.
23 Running,
24 /// The server has been stopped (manually or via shutdown).
25 Stopped,
26 /// The server process exited unexpectedly or a health check failed.
27 Crashed,
28 /// The server is in the process of being restarted.
29 Restarting,
30 /// The server configuration has `disabled: true`; it will not be started.
31 Disabled,
32 /// The server failed to start (spawn failure, handshake failure, or max restarts exceeded).
33 FailedToStart,
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39
40 #[test]
41 fn test_server_status_clone() {
42 let status = ServerStatus::Running;
43 let cloned = status;
44 assert_eq!(status, cloned);
45 }
46
47 #[test]
48 fn test_server_status_debug() {
49 let status = ServerStatus::Crashed;
50 let debug_str = format!("{status:?}");
51 assert_eq!(debug_str, "Crashed");
52 }
53
54 #[test]
55 fn test_server_status_eq() {
56 assert_eq!(ServerStatus::Running, ServerStatus::Running);
57 assert_ne!(ServerStatus::Running, ServerStatus::Stopped);
58 }
59
60 #[test]
61 fn test_server_status_hash() {
62 use std::collections::HashSet;
63 let mut set = HashSet::new();
64 set.insert(ServerStatus::Running);
65 set.insert(ServerStatus::Stopped);
66 set.insert(ServerStatus::Running); // duplicate
67 assert_eq!(set.len(), 2);
68 }
69
70 #[test]
71 fn test_server_status_serde_round_trip() {
72 let statuses = [
73 ServerStatus::Running,
74 ServerStatus::Stopped,
75 ServerStatus::Crashed,
76 ServerStatus::Restarting,
77 ServerStatus::Disabled,
78 ServerStatus::FailedToStart,
79 ];
80 for status in &statuses {
81 let json = serde_json::to_string(status).unwrap();
82 let deserialized: ServerStatus = serde_json::from_str(&json).unwrap();
83 assert_eq!(*status, deserialized);
84 }
85 }
86}