fastmcp_console/
detection.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
7pub enum DisplayContext {
8 Agent,
10 #[default]
12 Human,
13}
14
15impl DisplayContext {
16 #[must_use]
18 pub fn new_agent() -> Self {
19 Self::Agent
20 }
21
22 #[must_use]
24 pub fn new_human() -> Self {
25 Self::Human
26 }
27
28 #[must_use]
30 pub fn detect() -> Self {
31 if should_enable_rich() {
32 Self::Human
33 } else {
34 Self::Agent
35 }
36 }
37
38 #[must_use]
40 pub fn is_human(&self) -> bool {
41 matches!(self, Self::Human)
42 }
43
44 #[must_use]
46 pub fn is_agent(&self) -> bool {
47 matches!(self, Self::Agent)
48 }
49}
50
51#[must_use]
53pub fn is_agent_context() -> bool {
54 std::env::var("MCP_CLIENT").is_ok()
56 || std::env::var("CLAUDE_CODE").is_ok()
57 || std::env::var("CODEX_CLI").is_ok()
58 || std::env::var("CURSOR_SESSION").is_ok()
59 || std::env::var("CI").is_ok()
61 || std::env::var("AGENT_MODE").is_ok()
62 || std::env::var("FASTMCP_PLAIN").is_ok()
64 || std::env::var("NO_COLOR").is_ok()
65}
66
67#[must_use]
69pub fn should_enable_rich() -> bool {
70 use std::io::IsTerminal;
71
72 if std::env::var("FASTMCP_RICH").is_ok() {
74 return true;
75 }
76
77 if is_agent_context() {
79 return false;
80 }
81
82 std::io::stderr().is_terminal()
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn test_display_context_new_agent() {
92 let ctx = DisplayContext::new_agent();
93 assert!(ctx.is_agent());
94 assert!(!ctx.is_human());
95 }
96
97 #[test]
98 fn test_display_context_new_human() {
99 let ctx = DisplayContext::new_human();
100 assert!(ctx.is_human());
101 assert!(!ctx.is_agent());
102 }
103
104 #[test]
105 fn test_display_context_default_is_human() {
106 let ctx = DisplayContext::default();
107 assert!(ctx.is_human());
108 }
109
110 #[test]
111 fn test_display_context_equality() {
112 assert_eq!(DisplayContext::Agent, DisplayContext::Agent);
113 assert_eq!(DisplayContext::Human, DisplayContext::Human);
114 assert_ne!(DisplayContext::Agent, DisplayContext::Human);
115 }
116
117 #[test]
118 fn test_display_context_clone() {
119 let ctx = DisplayContext::Agent;
120 let cloned = ctx;
121 assert_eq!(ctx, cloned);
122 }
123
124 #[test]
125 fn test_display_context_debug() {
126 let ctx = DisplayContext::Agent;
127 let debug_str = format!("{:?}", ctx);
128 assert!(debug_str.contains("Agent"));
129 }
130
131 #[test]
136 fn display_context_copy_semantics() {
137 let ctx = DisplayContext::Agent;
138 let copied = ctx;
139 assert!(ctx.is_agent());
141 assert!(copied.is_agent());
142 }
143
144 #[test]
145 fn display_context_debug_human() {
146 let ctx = DisplayContext::Human;
147 let debug_str = format!("{ctx:?}");
148 assert!(debug_str.contains("Human"));
149 }
150
151 #[test]
152 fn detect_returns_valid_context() {
153 let ctx = DisplayContext::detect();
155 assert!(ctx.is_agent() || ctx.is_human());
156 }
157
158 #[test]
159 fn is_agent_context_and_should_enable_rich_are_consistent() {
160 if is_agent_context() {
163 if std::env::var("FASTMCP_RICH").is_err() {
165 assert!(!should_enable_rich());
166 }
167 }
168 }
169}