"""
Configuration management for DNAC MCP Server.
This module handles loading configuration from environment variables
and config files.
"""
import os
import json
import logging
from pathlib import Path
from typing import Dict, Any, Optional
logger = logging.getLogger(__name__)
def load_config(config_file: Optional[str] = None) -> Dict[str, Any]:
"""
Load configuration from environment variables or config file.
Priority:
1. Environment variables (DNAC_BASE_URL, DNAC_USERNAME, DNAC_PASSWORD)
2. Config file (if provided or found at default locations)
3. Empty config (credentials required per request)
Args:
config_file: Optional path to config file (JSON format)
Returns:
Configuration dictionary
Example config.json:
{
"base_url": "https://dnac.example.com",
"username": "admin",
"password": "password",
"version": "2.3.7.6",
"verify": true,
"max_results": 100
}
"""
config: Dict[str, Any] = {}
# Try to load from config file
if config_file or os.environ.get("DNAC_CONFIG_FILE"):
config_path = Path(config_file or os.environ["DNAC_CONFIG_FILE"])
if config_path.exists():
try:
with open(config_path, 'r') as f:
file_config = json.load(f)
config.update(file_config)
logger.info(f"Loaded configuration from {config_path}")
except Exception as e:
logger.warning(f"Failed to load config file {config_path}: {e}")
# Override with environment variables
env_mapping = {
"DNAC_BASE_URL": "base_url",
"DNAC_USERNAME": "username",
"DNAC_PASSWORD": "password",
"DNAC_VERSION": "version",
"DNAC_VERIFY": "verify",
"DNAC_MAX_RESULTS": "max_results"
}
for env_var, config_key in env_mapping.items():
value = os.environ.get(env_var)
if value is not None:
# Convert types
if config_key == "verify":
value = value.lower() in ("true", "1", "yes")
elif config_key == "max_results":
value = int(value)
config[config_key] = value
logger.debug(f"Loaded {config_key} from environment variable {env_var}")
# Log configuration (without sensitive data)
safe_config = {
k: ("***" if k in ("password",) else v)
for k, v in config.items()
}
logger.info(f"Final configuration: {safe_config}")
return config
def get_default_credentials() -> Dict[str, str]:
"""
Get default DNAC credentials from configuration.
Returns:
Dictionary with base_url, username, password if available
Raises:
ValueError: If required credentials are missing
"""
config = load_config()
required = ["base_url", "username", "password"]
missing = [key for key in required if key not in config]
if missing:
raise ValueError(
f"Missing required credentials: {', '.join(missing)}. "
f"Set environment variables: {', '.join([f'DNAC_{k.upper()}' for k in missing])}"
)
return {
"base_url": config["base_url"],
"username": config["username"],
"password": config["password"],
"version": config.get("version", "2.3.7.6"),
"verify": config.get("verify", True)
}