pulseengine_mcp_cli/
config.rs1use crate::CliError;
4use pulseengine_mcp_protocol::{Implementation, ProtocolVersion, ServerCapabilities, ServerInfo};
5use serde::{Deserialize, Serialize};
6use std::env;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct DefaultLoggingConfig {
11 pub level: String,
12 pub format: LogFormat,
13 pub output: LogOutput,
14 pub structured: bool,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub enum LogFormat {
19 #[serde(rename = "json")]
20 Json,
21 #[serde(rename = "pretty")]
22 Pretty,
23 #[serde(rename = "compact")]
24 Compact,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub enum LogOutput {
29 #[serde(rename = "stdout")]
30 Stdout,
31 #[serde(rename = "stderr")]
32 Stderr,
33 #[serde(rename = "file")]
34 File(String),
35}
36
37impl Default for DefaultLoggingConfig {
38 fn default() -> Self {
39 Self {
40 level: "info".to_string(),
41 format: LogFormat::Pretty,
42 output: LogOutput::Stdout,
43 structured: true,
44 }
45 }
46}
47
48impl DefaultLoggingConfig {
49 pub fn initialize(&self) -> Result<(), CliError> {
50 use tracing_subscriber::{EnvFilter, fmt, prelude::*};
52
53 let level = env::var("RUST_LOG").unwrap_or_else(|_| self.level.clone());
54 let filter = EnvFilter::try_from_default_env()
55 .or_else(|_| EnvFilter::try_new(&level))
56 .map_err(|e| CliError::logging(format!("Invalid log level: {e}")))?;
57
58 match self.format {
59 LogFormat::Json => {
60 tracing_subscriber::registry()
61 .with(filter)
62 .with(fmt::layer().json())
63 .init();
64 }
65 LogFormat::Pretty => {
66 tracing_subscriber::registry()
67 .with(filter)
68 .with(fmt::layer().pretty())
69 .init();
70 }
71 LogFormat::Compact => {
72 tracing_subscriber::registry()
73 .with(filter)
74 .with(fmt::layer().compact())
75 .init();
76 }
77 }
78
79 Ok(())
80 }
81}
82
83pub fn create_server_info(name: Option<String>, version: Option<String>) -> ServerInfo {
85 ServerInfo {
86 protocol_version: ProtocolVersion::default(),
87 capabilities: ServerCapabilities::default(),
88 server_info: Implementation {
89 name: name.unwrap_or_else(|| env!("CARGO_PKG_NAME").to_string()),
90 version: version.unwrap_or_else(|| env!("CARGO_PKG_VERSION").to_string()),
91 },
92 instructions: None,
93 }
94}
95
96pub mod env_utils {
98 use std::env;
99 use std::str::FromStr;
100
101 pub fn get_env_or_default<T>(key: &str, default: T) -> T
103 where
104 T: FromStr + Clone,
105 {
106 env::var(key)
107 .ok()
108 .and_then(|v| v.parse().ok())
109 .unwrap_or(default)
110 }
111
112 pub fn get_required_env<T>(key: &str) -> Result<T, crate::CliError>
114 where
115 T: FromStr,
116 T::Err: std::fmt::Display,
117 {
118 env::var(key)
119 .map_err(|_| {
120 crate::CliError::configuration(format!(
121 "Missing required environment variable: {key}"
122 ))
123 })?
124 .parse()
125 .map_err(|e| crate::CliError::configuration(format!("Invalid value for {key}: {e}")))
126 }
127}