Skip to main content
Glama
__main__.py6.99 kB
"""Command-line interface for the Redshift Utils MCP Server. This module provides the main entry point for starting the server using Typer. It handles parsing command-line arguments, setting corresponding environment variables, performing a basic configuration pre-flight check, and running the FastMCP server instance defined in `server.py`. """ import logging import os import sys from typing import Optional, List, Dict from typing_extensions import Annotated import typer from redshift_utils_mcp.server import mcp from redshift_utils_mcp.utils.data_api import ( DataApiConfigError, ) logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", stream=sys.stderr, ) logging.getLogger("boto3").setLevel(logging.WARNING) logging.getLogger("botocore").setLevel(logging.WARNING) logger = logging.getLogger(__name__) app: typer.Typer = typer.Typer( name="redshift-utils-mcp-server", help="Runs the Redshift Utils MCP Server using AWS Data API.", add_completion=False, ) @app.command() def main( cluster_id: Annotated[ Optional[str], typer.Option( "--cluster-id", help="Redshift cluster identifier.", envvar="REDSHIFT_CLUSTER_ID", ), ] = None, database: Annotated[ Optional[str], typer.Option( "--database", help="Redshift database name.", envvar="REDSHIFT_DATABASE" ), ] = None, secret_arn: Annotated[ Optional[str], typer.Option( "--secret-arn", help="AWS Secrets Manager ARN for Redshift credentials.", envvar="REDSHIFT_SECRET_ARN", ), ] = None, region: Annotated[ Optional[str], typer.Option( "--region", help="AWS region for Data API and Secrets Manager.", envvar=["AWS_REGION", "AWS_DEFAULT_REGION"], ), ] = None, aws_profile: Annotated[ Optional[str], typer.Option( "--profile", help="AWS profile name to use.", envvar="AWS_PROFILE", ), ] = None, ): """Entry point for the Redshift Utils MCP Server. This function serves as the main command for the Typer CLI application. It orchestrates the configuration loading process and initiates the FastMCP server. Configuration values are sourced primarily from command-line options, falling back to environment variables if options are not provided. It performs a preliminary check for essential configuration variables before attempting to run the server. Args: cluster_id: Redshift cluster identifier. Reads from `--cluster-id` or `REDSHIFT_CLUSTER_ID`. database: Redshift database name. Reads from `--database` or `REDSHIFT_DATABASE`. secret_arn: AWS Secrets Manager ARN for Redshift credentials. Reads from `--secret-arn` or `REDSHIFT_SECRET_ARN`. region: AWS region for Data API and Secrets Manager. Reads from `--region` or `AWS_REGION`/`AWS_DEFAULT_REGION`. aws_profile: AWS profile name to use. Reads from `--profile` or `AWS_PROFILE`. """ logger.info("Configuring Redshift Utils MCP Server...") final_config: Dict[str, Optional[str]] = {} if cluster_id: os.environ["REDSHIFT_CLUSTER_ID"] = cluster_id final_config["cluster_id"] = cluster_id logger.info(f"Using Cluster ID from argument: {cluster_id}") else: final_config["cluster_id"] = os.environ.get("REDSHIFT_CLUSTER_ID") if database: os.environ["REDSHIFT_DATABASE"] = database final_config["database"] = database logger.info(f"Using Database from argument: {database}") else: final_config["database"] = os.environ.get("REDSHIFT_DATABASE") if secret_arn: os.environ["REDSHIFT_SECRET_ARN"] = secret_arn final_config["secret_arn"] = secret_arn logger.info(f"Using Secret ARN from argument: {secret_arn}") else: final_config["secret_arn"] = os.environ.get("REDSHIFT_SECRET_ARN") if region: os.environ["AWS_REGION"] = region final_config["region"] = region logger.info(f"Using AWS Region from argument/env: {region}") else: final_config["region"] = os.environ.get("AWS_REGION") or os.environ.get( "AWS_DEFAULT_REGION" ) if aws_profile: os.environ["AWS_PROFILE"] = aws_profile final_config["aws_profile"] = aws_profile logger.info(f"Using AWS Profile from argument/env: {aws_profile}") else: final_config["aws_profile"] = os.environ.get("AWS_PROFILE") missing_vars: List[str] = [] if not final_config.get("cluster_id"): missing_vars.append("REDSHIFT_CLUSTER_ID or --cluster-id") if not final_config.get("database"): missing_vars.append("REDSHIFT_DATABASE or --database") if not final_config.get("secret_arn"): missing_vars.append("REDSHIFT_SECRET_ARN or --secret-arn") if not final_config.get("region"): missing_vars.append("AWS_REGION/AWS_DEFAULT_REGION or --region") if missing_vars: # Use typer for more elegant error output typer.echo( typer.style( "Error: Missing required configuration!", fg=typer.colors.RED, bold=True ) ) typer.echo( "\nPlease provide the following configuration items either via command-line arguments or environment variables:" ) # Map description back to CLI option for clarity config_map = { "REDSHIFT_CLUSTER_ID": "--cluster-id", "REDSHIFT_DATABASE": "--database", "REDSHIFT_SECRET_ARN": "--secret-arn", "AWS_REGION/AWS_DEFAULT_REGION": "--region", } for var_desc in missing_vars: env_var_key = var_desc.split(" or ")[0] # Get the ENV VAR part cli_opt = config_map.get(env_var_key) message = f" - {typer.style(env_var_key, fg=typer.colors.YELLOW)} (Environment Variable)" if cli_opt: message += f" or {typer.style(cli_opt, fg=typer.colors.CYAN)} (Command-Line Argument)" typer.echo(message) typer.echo( f"\nFor example, set {typer.style('REDSHIFT_CLUSTER_ID', fg=typer.colors.YELLOW)} or use {typer.style('--cluster-id', fg=typer.colors.CYAN)}." ) raise typer.Exit(code=1) logger.info("Configuration loaded. Starting MCP server...") try: mcp.run() logger.info("MCP server finished.") except DataApiConfigError as e: logger.error(f"Configuration Error during server startup: {e}") raise typer.Exit(code=1) except Exception as e: logger.error( f"An unexpected error occurred while running the MCP server: {e}", exc_info=True, ) raise typer.Exit(code=1) if __name__ == "__main__": app()

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/vinodismyname/redshift-utils-mcp'

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