remote_mcp_kernel/
config.rs

1//! Configuration management for MCP OAuth server
2//!
3//! This module provides environment variable loading functions following
4//! the principle of single responsibility and making configuration
5//! explicit and testable.
6
7use std::env;
8
9/// Server configuration values
10pub fn get_server_host() -> String {
11    env::var("MCP_HOST").unwrap_or_else(|_| "localhost".to_string())
12}
13
14pub fn get_server_port() -> Result<u16, ConfigError> {
15    env::var("MCP_PORT")
16        .unwrap_or_else(|_| "8080".to_string())
17        .parse::<u16>()
18        .map_err(|_| ConfigError::InvalidPort)
19}
20
21pub fn get_server_bind_address() -> Result<String, ConfigError> {
22    let port = get_server_port()?;
23    Ok(env::var("MCP_BIND_ADDRESS").unwrap_or_else(|_| format!("0.0.0.0:{}", port)))
24}
25
26pub fn get_server_name() -> String {
27    "MCP OAuth Server".to_string()
28}
29
30pub fn get_server_version() -> String {
31    env!("CARGO_PKG_VERSION").to_string()
32}
33
34pub fn get_server_description() -> String {
35    "MCP server with OAuth authentication capabilities".to_string()
36}
37
38/// GitHub OAuth configuration values
39pub fn get_github_client_id() -> Result<String, ConfigError> {
40    env::var("GITHUB_CLIENT_ID").map_err(|_| ConfigError::MissingGitHubClientId)
41}
42
43pub fn get_github_client_secret() -> Result<String, ConfigError> {
44    env::var("GITHUB_CLIENT_SECRET").map_err(|_| ConfigError::MissingGitHubClientSecret)
45}
46
47pub fn get_github_scope() -> String {
48    env::var("GITHUB_SCOPE").unwrap_or_else(|_| "read:user".to_string())
49}
50
51/// AWS Cognito OAuth configuration values
52pub fn get_cognito_client_id() -> Result<String, ConfigError> {
53    env::var("COGNITO_CLIENT_ID").map_err(|_| ConfigError::MissingCognitoClientId)
54}
55
56pub fn get_cognito_client_secret() -> Option<String> {
57    env::var("COGNITO_CLIENT_SECRET").ok()
58}
59
60pub fn get_cognito_scope() -> String {
61    env::var("COGNITO_SCOPE").unwrap_or_else(|_| "openid email profile phone".to_string())
62}
63
64pub fn get_cognito_domain() -> Result<String, ConfigError> {
65    let domain = env::var("COGNITO_DOMAIN").map_err(|_| ConfigError::MissingCognitoDomain)?;
66
67    // If domain already contains dots, assume it's already a full domain
68    if domain.contains('.') {
69        Ok(domain)
70    } else {
71        // Construct full domain from short format
72        let region = get_cognito_region()?;
73        Ok(format!("{}.auth.{}.amazoncognito.com", domain, region))
74    }
75}
76
77pub fn get_cognito_region() -> Result<String, ConfigError> {
78    env::var("AWS_REGION").map_err(|_| ConfigError::MissingCognitoRegion)
79}
80
81pub fn get_cognito_user_pool_id() -> Result<String, ConfigError> {
82    env::var("COGNITO_USER_POOL_ID").map_err(|_| ConfigError::MissingCognitoUserPoolId)
83}
84
85/// Logging configuration values
86pub fn get_logging_level() -> String {
87    env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string())
88}
89
90pub fn get_logging_format() -> String {
91    env::var("LOG_FORMAT").unwrap_or_else(|_| "json".to_string())
92}
93
94/// OAuth provider configuration values
95pub fn get_oauth_provider_config()
96-> oauth_provider_rs::http_integration::config::OAuthProviderConfig {
97    oauth_provider_rs::http_integration::config::OAuthProviderConfig::default()
98}
99
100/// GitHub OAuth provider configuration
101pub fn get_github_oauth_provider_config()
102-> Result<oauth_provider_rs::providers::provider_trait::OAuthProviderConfig, ConfigError> {
103    Ok(
104        oauth_provider_rs::providers::provider_trait::OAuthProviderConfig::with_oauth_config(
105            get_github_client_id()?,
106            get_github_client_secret()?,
107            // redirect_uri will be determined dynamically from request headers
108            "".to_string(),
109            "read:user".to_string(),
110            "github".to_string(),
111        ),
112    )
113}
114
115/// Cognito OAuth provider configuration
116pub fn get_cognito_oauth_provider_config()
117-> Result<oauth_provider_rs::providers::provider_trait::OAuthProviderConfig, ConfigError> {
118    Ok(
119        oauth_provider_rs::providers::provider_trait::OAuthProviderConfig::with_oauth_config(
120            get_cognito_client_id()?,
121            get_cognito_client_secret().unwrap_or_default(),
122            // redirect_uri will be determined dynamically from request headers
123            "".to_string(),
124            get_cognito_scope(),
125            "cognito".to_string(),
126        ),
127    )
128}
129
130/// Get server bind address as SocketAddr
131pub fn get_bind_socket_addr() -> Result<std::net::SocketAddr, ConfigError> {
132    get_server_bind_address()?
133        .parse()
134        .map_err(|_| ConfigError::InvalidBindAddress)
135}
136
137/// Configuration errors
138#[derive(Debug, thiserror::Error)]
139pub enum ConfigError {
140    #[error("Missing GITHUB_CLIENT_ID environment variable")]
141    MissingGitHubClientId,
142    #[error("Missing GITHUB_CLIENT_SECRET environment variable")]
143    MissingGitHubClientSecret,
144    #[error("Missing COGNITO_CLIENT_ID environment variable")]
145    MissingCognitoClientId,
146    #[error("Missing COGNITO_DOMAIN environment variable")]
147    MissingCognitoDomain,
148    #[error("Missing AWS_REGION environment variable")]
149    MissingCognitoRegion,
150    #[error("Missing COGNITO_USER_POOL_ID environment variable")]
151    MissingCognitoUserPoolId,
152    #[error("Invalid port number")]
153    InvalidPort,
154    #[error("Invalid bind address")]
155    InvalidBindAddress,
156}
157
158#[cfg(test)]
159mod tests {
160    use super::*;
161
162    #[test]
163    fn test_server_defaults() {
164        // Test default server configuration
165        assert_eq!(get_server_name(), "MCP OAuth Server");
166        assert_eq!(
167            get_server_description(),
168            "MCP server with OAuth authentication capabilities"
169        );
170        assert_eq!(get_github_scope(), "read:user");
171        assert_eq!(get_cognito_scope(), "openid email profile phone");
172        assert_eq!(get_logging_level(), "info");
173    }
174
175    #[test]
176    fn test_missing_github_config() {
177        unsafe {
178            env::remove_var("GITHUB_CLIENT_ID");
179            env::remove_var("GITHUB_CLIENT_SECRET");
180        }
181
182        let result = get_github_oauth_provider_config();
183        assert!(result.is_err());
184    }
185
186    #[test]
187    fn test_missing_cognito_config() {
188        unsafe {
189            env::remove_var("COGNITO_CLIENT_ID");
190            env::remove_var("COGNITO_DOMAIN");
191            env::remove_var("AWS_REGION");
192            env::remove_var("COGNITO_USER_POOL_ID");
193        }
194
195        let result = get_cognito_oauth_provider_config();
196        assert!(result.is_err());
197    }
198}