Skip to main content
Glama
config.py6.27 kB
"""Configuration management for KDB MCP service.""" import os import yaml import json from typing import Any, Dict from pathlib import Path from dotenv import load_dotenv # Load environment variables load_dotenv() def load_config(config_path: str) -> Dict[str, Any]: """ Load configuration from YAML or JSON file. Args: config_path: Path to configuration file Returns: Configuration dictionary """ config_file = Path(config_path) # Check if config file exists if not config_file.exists(): # Try to find config in common locations common_paths = [ Path("config/kdb_config.yaml"), Path("config/kdb_config.json"), Path("kdb_config.yaml"), Path("kdb_config.json"), Path.home() / ".kdb-mcp" / "config.yaml", Path.home() / ".kdb-mcp" / "config.json" ] for path in common_paths: if path.exists(): config_file = path break else: # Return default configuration if no config file found return get_default_config() # Load configuration based on file extension if config_file.suffix in ['.yaml', '.yml']: with open(config_file, 'r') as f: config = yaml.safe_load(f) elif config_file.suffix == '.json': with open(config_file, 'r') as f: config = json.load(f) else: raise ValueError(f"Unsupported config file format: {config_file.suffix}") # Process environment variable substitutions config = process_env_vars(config) # Validate configuration validate_config(config) return config def process_env_vars(config: Any) -> Any: """ Recursively process environment variable substitutions in config. Environment variables can be referenced using ${VAR_NAME} or ${VAR_NAME:default} Args: config: Configuration dictionary or value Returns: Processed configuration """ if isinstance(config, dict): return {k: process_env_vars(v) for k, v in config.items()} elif isinstance(config, list): return [process_env_vars(item) for item in config] elif isinstance(config, str): # Check for environment variable pattern if config.startswith('${') and config.endswith('}'): var_content = config[2:-1] if ':' in var_content: var_name, default = var_content.split(':', 1) return os.getenv(var_name, default) else: return os.getenv(var_content, config) return config else: return config def validate_config(config: Dict[str, Any]): """ Validate configuration structure. Args: config: Configuration dictionary Raises: ValueError: If configuration is invalid """ if 'databases' not in config: raise ValueError("Configuration must include 'databases' section") databases = config['databases'] if not isinstance(databases, dict): raise ValueError("'databases' must be a dictionary") for db_name, db_config in databases.items(): # Validate required fields if 'host' not in db_config: raise ValueError(f"Database '{db_name}' missing required field 'host'") if 'port' not in db_config: raise ValueError(f"Database '{db_name}' missing required field 'port'") # Validate port is a number try: port = int(db_config['port']) if port < 1 or port > 65535: raise ValueError(f"Database '{db_name}' port must be between 1 and 65535") except (TypeError, ValueError): raise ValueError(f"Database '{db_name}' port must be a valid integer") def get_default_config() -> Dict[str, Any]: """ Get default configuration. Returns: Default configuration dictionary """ return { "databases": { "default": { "host": os.getenv("KDB_HOST", "localhost"), "port": int(os.getenv("KDB_PORT", "5000")), "username": os.getenv("KDB_USERNAME", ""), "password": os.getenv("KDB_PASSWORD", ""), "pool_size": int(os.getenv("KDB_POOL_SIZE", "5")), "description": "Default KDB+ database" } }, "logging": { "level": os.getenv("LOG_LEVEL", "INFO"), "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s" }, "server": { "name": "kdb-mcp-server", "version": "0.1.0" } } def save_config(config: Dict[str, Any], config_path: str): """ Save configuration to file. Args: config: Configuration dictionary config_path: Path to save configuration """ config_file = Path(config_path) config_file.parent.mkdir(parents=True, exist_ok=True) if config_file.suffix in ['.yaml', '.yml']: with open(config_file, 'w') as f: yaml.dump(config, f, default_flow_style=False, sort_keys=False) elif config_file.suffix == '.json': with open(config_file, 'w') as f: json.dump(config, f, indent=2) else: raise ValueError(f"Unsupported config file format: {config_file.suffix}") def merge_configs(*configs: Dict[str, Any]) -> Dict[str, Any]: """ Merge multiple configuration dictionaries. Later configs override earlier ones. Args: *configs: Configuration dictionaries to merge Returns: Merged configuration """ result = {} for config in configs: result = deep_merge(result, config) return result def deep_merge(dict1: Dict[str, Any], dict2: Dict[str, Any]) -> Dict[str, Any]: """ Deep merge two dictionaries. Args: dict1: Base dictionary dict2: Dictionary to merge in (overrides dict1) Returns: Merged dictionary """ result = dict1.copy() for key, value in dict2.items(): if key in result and isinstance(result[key], dict) and isinstance(value, dict): result[key] = deep_merge(result[key], value) else: result[key] = value return result

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/riteshsonawala/kdb-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server