remote-mcp-kernel 0.1.0-alpha.6

A microkernel-based MCP (Model Context Protocol) server with OAuth authentication and multiple transport protocols
Documentation
//! Configuration management for MCP OAuth server
//!
//! This module provides environment variable loading functions following
//! the principle of single responsibility and making configuration
//! explicit and testable.

use std::env;

/// Server configuration values
pub fn get_server_host() -> String {
    env::var("MCP_HOST").unwrap_or_else(|_| "localhost".to_string())
}

pub fn get_server_port() -> Result<u16, ConfigError> {
    env::var("MCP_PORT")
        .unwrap_or_else(|_| "8080".to_string())
        .parse::<u16>()
        .map_err(|_| ConfigError::InvalidPort)
}

pub fn get_server_bind_address() -> Result<String, ConfigError> {
    let port = get_server_port()?;
    Ok(env::var("MCP_BIND_ADDRESS").unwrap_or_else(|_| format!("0.0.0.0:{}", port)))
}

pub fn get_server_name() -> String {
    "MCP OAuth Server".to_string()
}

pub fn get_server_version() -> String {
    env!("CARGO_PKG_VERSION").to_string()
}

pub fn get_server_description() -> String {
    "MCP server with OAuth authentication capabilities".to_string()
}

/// GitHub OAuth configuration values
pub fn get_github_client_id() -> Result<String, ConfigError> {
    env::var("GITHUB_CLIENT_ID").map_err(|_| ConfigError::MissingGitHubClientId)
}

pub fn get_github_client_secret() -> Result<String, ConfigError> {
    env::var("GITHUB_CLIENT_SECRET").map_err(|_| ConfigError::MissingGitHubClientSecret)
}

pub fn get_github_scope() -> String {
    env::var("GITHUB_SCOPE").unwrap_or_else(|_| "read:user".to_string())
}

/// AWS Cognito OAuth configuration values
pub fn get_cognito_client_id() -> Result<String, ConfigError> {
    env::var("COGNITO_CLIENT_ID").map_err(|_| ConfigError::MissingCognitoClientId)
}

pub fn get_cognito_client_secret() -> Option<String> {
    env::var("COGNITO_CLIENT_SECRET").ok()
}

pub fn get_cognito_scope() -> String {
    env::var("COGNITO_SCOPE").unwrap_or_else(|_| "openid email profile phone".to_string())
}

pub fn get_cognito_domain() -> Result<String, ConfigError> {
    let domain = env::var("COGNITO_DOMAIN").map_err(|_| ConfigError::MissingCognitoDomain)?;
    
    // If domain already contains dots, assume it's already a full domain
    if domain.contains('.') {
        Ok(domain)
    } else {
        // Construct full domain from short format
        let region = get_cognito_region()?;
        Ok(format!("{}.auth.{}.amazoncognito.com", domain, region))
    }
}

pub fn get_cognito_region() -> Result<String, ConfigError> {
    env::var("AWS_REGION").map_err(|_| ConfigError::MissingCognitoRegion)
}

pub fn get_cognito_user_pool_id() -> Result<String, ConfigError> {
    env::var("COGNITO_USER_POOL_ID").map_err(|_| ConfigError::MissingCognitoUserPoolId)
}

/// Logging configuration values
pub fn get_logging_level() -> String {
    env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string())
}

pub fn get_logging_format() -> String {
    env::var("LOG_FORMAT").unwrap_or_else(|_| "json".to_string())
}

/// OAuth provider configuration values
pub fn get_oauth_provider_config()
-> oauth_provider_rs::http_integration::config::OAuthProviderConfig {
    oauth_provider_rs::http_integration::config::OAuthProviderConfig::default()
}

/// GitHub OAuth provider configuration
pub fn get_github_oauth_provider_config()
-> Result<oauth_provider_rs::providers::provider_trait::OAuthProviderConfig, ConfigError> {
    Ok(
        oauth_provider_rs::providers::provider_trait::OAuthProviderConfig::with_oauth_config(
            get_github_client_id()?,
            get_github_client_secret()?,
            // redirect_uri will be determined dynamically from request headers
            "".to_string(),
            "read:user".to_string(),
            "github".to_string(),
        ),
    )
}

/// Cognito OAuth provider configuration
pub fn get_cognito_oauth_provider_config()
-> Result<oauth_provider_rs::providers::provider_trait::OAuthProviderConfig, ConfigError> {
    Ok(
        oauth_provider_rs::providers::provider_trait::OAuthProviderConfig::with_oauth_config(
            get_cognito_client_id()?,
            get_cognito_client_secret().unwrap_or_default(),
            // redirect_uri will be determined dynamically from request headers
            "".to_string(),
            get_cognito_scope(),
            "cognito".to_string(),
        ),
    )
}

/// Get server bind address as SocketAddr
pub fn get_bind_socket_addr() -> Result<std::net::SocketAddr, ConfigError> {
    get_server_bind_address()?
        .parse()
        .map_err(|_| ConfigError::InvalidBindAddress)
}

/// Configuration errors
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
    #[error("Missing GITHUB_CLIENT_ID environment variable")]
    MissingGitHubClientId,
    #[error("Missing GITHUB_CLIENT_SECRET environment variable")]
    MissingGitHubClientSecret,
    #[error("Missing COGNITO_CLIENT_ID environment variable")]
    MissingCognitoClientId,
    #[error("Missing COGNITO_DOMAIN environment variable")]
    MissingCognitoDomain,
    #[error("Missing AWS_REGION environment variable")]
    MissingCognitoRegion,
    #[error("Missing COGNITO_USER_POOL_ID environment variable")]
    MissingCognitoUserPoolId,
    #[error("Invalid port number")]
    InvalidPort,
    #[error("Invalid bind address")]
    InvalidBindAddress,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_server_defaults() {
        // Test default server configuration
        assert_eq!(get_server_name(), "MCP OAuth Server");
        assert_eq!(
            get_server_description(),
            "MCP server with OAuth authentication capabilities"
        );
        assert_eq!(get_github_scope(), "read:user");
        assert_eq!(get_cognito_scope(), "openid email profile phone");
        assert_eq!(get_logging_level(), "info");
    }

    #[test]
    fn test_missing_github_config() {
        unsafe {
            env::remove_var("GITHUB_CLIENT_ID");
            env::remove_var("GITHUB_CLIENT_SECRET");
        }

        let result = get_github_oauth_provider_config();
        assert!(result.is_err());
    }

    #[test]
    fn test_missing_cognito_config() {
        unsafe {
            env::remove_var("COGNITO_CLIENT_ID");
            env::remove_var("COGNITO_DOMAIN");
            env::remove_var("AWS_REGION");
            env::remove_var("COGNITO_USER_POOL_ID");
        }

        let result = get_cognito_oauth_provider_config();
        assert!(result.is_err());
    }
}