Skip to main content

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}