Skip to main content
Glama

MCP Context Forge Gateway

by SPRIME01
Apache 2.0
run-gunicorn-v2.sh15.6 kB
#!/usr/bin/env bash #─────────────────────────────────────────────────────────────────────────────── # Script : run-gunicorn.sh # Author : Mihai Criveti # Purpose: Launch the MCP Gateway API under Gunicorn with optional TLS support # # Description: # This script provides a robust way to launch a production API server using # Gunicorn with the following features: # # - Portable Python detection across different distros (python vs python3) # - Virtual environment handling (activates project venv if available) # - Configurable via environment variables for CI/CD pipelines # - Optional TLS/SSL support for secure connections # - Database initialization before server start # - Comprehensive error handling and user feedback # # Environment Variables: # PYTHON : Path to Python interpreter (optional) # VIRTUAL_ENV : Path to active virtual environment (auto-detected) # GUNICORN_WORKERS : Number of worker processes (default: 2 × CPU cores + 1) # GUNICORN_TIMEOUT : Worker timeout in seconds (default: 600) # GUNICORN_MAX_REQUESTS : Max requests per worker before restart (default: 1000) # GUNICORN_MAX_REQUESTS_JITTER : Random jitter for max requests (default: 100) # SSL : Enable TLS/SSL (true/false, default: false) # CERT_FILE : Path to SSL certificate (default: certs/cert.pem) # KEY_FILE : Path to SSL private key (default: certs/key.pem) # # Usage: # ./run-gunicorn.sh # Run with defaults # SSL=true ./run-gunicorn.sh # Run with TLS enabled # GUNICORN_WORKERS=16 ./run-gunicorn.sh # Run with 16 workers #─────────────────────────────────────────────────────────────────────────────── # Exit immediately on error, undefined variable, or pipe failure set -euo pipefail #──────────────────────────────────────────────────────────────────────────────── # SECTION 1: Script Location Detection # Determine the absolute path to this script's directory for relative path resolution #──────────────────────────────────────────────────────────────────────────────── SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # Change to script directory to ensure relative paths work correctly # This ensures gunicorn.config.py and cert paths resolve properly cd "${SCRIPT_DIR}" || { echo "❌ FATAL: Cannot change to script directory: ${SCRIPT_DIR}" exit 1 } #──────────────────────────────────────────────────────────────────────────────── # SECTION 2: Virtual Environment Activation # Check if a virtual environment is already active. If not, try to activate one # from known locations. This ensures dependencies are properly isolated. #──────────────────────────────────────────────────────────────────────────────── if [[ -z "${VIRTUAL_ENV:-}" ]]; then # Check for virtual environment in user's home directory (preferred location) if [[ -f "${HOME}/.venv/mcpgateway/bin/activate" ]]; then echo "🔧 Activating virtual environment: ${HOME}/.venv/mcpgateway" # shellcheck disable=SC1090 source "${HOME}/.venv/mcpgateway/bin/activate" # Check for virtual environment in script directory (development setup) elif [[ -f "${SCRIPT_DIR}/.venv/bin/activate" ]]; then echo "🔧 Activating virtual environment in script directory" # shellcheck disable=SC1090 source "${SCRIPT_DIR}/.venv/bin/activate" # No virtual environment found - warn but continue else echo "⚠️ WARNING: No virtual environment found!" echo " This may lead to dependency conflicts." echo " Consider creating a virtual environment with:" echo " python3 -m venv ~/.venv/mcpgateway" # Optional: Uncomment the following lines to enforce virtual environment usage # echo "❌ FATAL: Virtual environment required for production deployments" # echo " This ensures consistent dependency versions." # exit 1 fi else echo "✓ Virtual environment already active: ${VIRTUAL_ENV}" fi #──────────────────────────────────────────────────────────────────────────────── # SECTION 3: Python Interpreter Detection # Locate a suitable Python interpreter with the following precedence: # 1. User-provided PYTHON environment variable # 2. 'python' binary in active virtual environment # 3. 'python3' binary on system PATH # 4. 'python' binary on system PATH #──────────────────────────────────────────────────────────────────────────────── if [[ -z "${PYTHON:-}" ]]; then # If virtual environment is active, prefer its Python binary if [[ -n "${VIRTUAL_ENV:-}" && -x "${VIRTUAL_ENV}/bin/python" ]]; then PYTHON="${VIRTUAL_ENV}/bin/python" echo "🐍 Using Python from virtual environment" # Otherwise, search for Python in system PATH else # Try python3 first (more common on modern systems) if command -v python3 &> /dev/null; then PYTHON="$(command -v python3)" echo "🐍 Found system Python3: ${PYTHON}" # Fall back to python if python3 not found elif command -v python &> /dev/null; then PYTHON="$(command -v python)" echo "🐍 Found system Python: ${PYTHON}" # No Python found at all else PYTHON="" fi fi fi # Verify Python interpreter exists and is executable if [[ -z "${PYTHON}" ]] || [[ ! -x "${PYTHON}" ]]; then echo "❌ FATAL: Could not locate a Python interpreter!" echo " Searched for: python3, python" echo " Please install Python 3.x or set the PYTHON environment variable." echo " Example: PYTHON=/usr/bin/python3.9 $0" exit 1 fi # Display Python version for debugging PY_VERSION="$("${PYTHON}" --version 2>&1)" echo "📋 Python version: ${PY_VERSION}" # Verify this is Python 3.x (not Python 2.x) if ! "${PYTHON}" -c "import sys; sys.exit(0 if sys.version_info[0] >= 3 else 1)" 2>/dev/null; then echo "❌ FATAL: Python 3.x is required, but Python 2.x was found!" echo " Please install Python 3.x or update the PYTHON environment variable." exit 1 fi #──────────────────────────────────────────────────────────────────────────────── # SECTION 4: Display Application Banner # Show a fancy ASCII art banner for the MCP Gateway #──────────────────────────────────────────────────────────────────────────────── cat <<'EOF' ███╗ ███╗ ██████╗██████╗ ██████╗ █████╗ ████████╗███████╗██╗ ██╗ █████╗ ██╗ ██╗ ████╗ ████║██╔════╝██╔══██╗ ██╔════╝ ██╔══██╗╚══██╔══╝██╔════╝██║ ██║██╔══██╗╚██╗ ██╔╝ ██╔████╔██║██║ ██████╔╝ ██║ ███╗███████║ ██║ █████╗ ██║ █╗ ██║███████║ ╚████╔╝ ██║╚██╔╝██║██║ ██╔═══╝ ██║ ██║██╔══██║ ██║ ██╔══╝ ██║███╗██║██╔══██║ ╚██╔╝ ██║ ╚═╝ ██║╚██████╗██║ ╚██████╔╝██║ ██║ ██║ ███████╗╚███╔███╔╝██║ ██║ ██║ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝ EOF #──────────────────────────────────────────────────────────────────────────────── # SECTION 5: Configure Gunicorn Settings # Set up Gunicorn parameters with sensible defaults that can be overridden # via environment variables for different deployment scenarios #──────────────────────────────────────────────────────────────────────────────── # Number of worker processes (adjust based on CPU cores and expected load) # Default: 2 × CPU cores + 1 (automatically detected) if [[ -z "${GUNICORN_WORKERS:-}" ]]; then # Try to detect CPU count if command -v nproc &>/dev/null; then CPU_COUNT=$(nproc) elif command -v sysctl &>/dev/null && sysctl -n hw.ncpu &>/dev/null; then CPU_COUNT=$(sysctl -n hw.ncpu) else CPU_COUNT=4 # Fallback to reasonable default fi GUNICORN_WORKERS=$((CPU_COUNT * 2 + 1)) fi # Worker timeout in seconds (increase for long-running requests) GUNICORN_TIMEOUT=${GUNICORN_TIMEOUT:-600} # Maximum requests a worker will process before restarting (prevents memory leaks) GUNICORN_MAX_REQUESTS=${GUNICORN_MAX_REQUESTS:-1000} # Random jitter for max requests (prevents all workers restarting simultaneously) GUNICORN_MAX_REQUESTS_JITTER=${GUNICORN_MAX_REQUESTS_JITTER:-100} echo "📊 Gunicorn Configuration:" echo " Workers: ${GUNICORN_WORKERS}" echo " Timeout: ${GUNICORN_TIMEOUT}s" echo " Max Requests: ${GUNICORN_MAX_REQUESTS} (±${GUNICORN_MAX_REQUESTS_JITTER})" #──────────────────────────────────────────────────────────────────────────────── # SECTION 6: Configure TLS/SSL Settings # Handle optional TLS configuration for secure HTTPS connections #──────────────────────────────────────────────────────────────────────────────── # SSL/TLS configuration SSL=${SSL:-false} # Enable/disable SSL (default: false) CERT_FILE=${CERT_FILE:-certs/cert.pem} # Path to SSL certificate file KEY_FILE=${KEY_FILE:-certs/key.pem} # Path to SSL private key file # Verify SSL settings if enabled if [[ "${SSL}" == "true" ]]; then echo "🔐 Configuring TLS/SSL..." # Verify certificate files exist if [[ ! -f "${CERT_FILE}" ]]; then echo "❌ FATAL: SSL certificate file not found: ${CERT_FILE}" exit 1 fi if [[ ! -f "${KEY_FILE}" ]]; then echo "❌ FATAL: SSL private key file not found: ${KEY_FILE}" exit 1 fi # Verify certificate and key files are readable if [[ ! -r "${CERT_FILE}" ]]; then echo "❌ FATAL: Cannot read SSL certificate file: ${CERT_FILE}" exit 1 fi if [[ ! -r "${KEY_FILE}" ]]; then echo "❌ FATAL: Cannot read SSL private key file: ${KEY_FILE}" exit 1 fi echo "✓ TLS enabled - using:" echo " Certificate: ${CERT_FILE}" echo " Private Key: ${KEY_FILE}" else echo "🔓 Running without TLS (HTTP only)" fi #──────────────────────────────────────────────────────────────────────────────── # SECTION 7: Database Initialization # Run database setup/migrations before starting the server #──────────────────────────────────────────────────────────────────────────────── echo "🗄️ Initializing database..." if ! "${PYTHON}" -m mcpgateway.db; then echo "❌ FATAL: Database initialization failed!" echo " Please check your database configuration and connection." exit 1 fi echo "✓ Database initialized successfully" #──────────────────────────────────────────────────────────────────────────────── # SECTION 8: Launch Gunicorn Server # Start the Gunicorn server with all configured options # Using 'exec' replaces this shell process with Gunicorn for cleaner process management #──────────────────────────────────────────────────────────────────────────────── echo "🚀 Starting Gunicorn server..." echo "─────────────────────────────────────────────────────────────────────" # Check if gunicorn is available if ! command -v gunicorn &> /dev/null; then echo "❌ FATAL: gunicorn command not found!" echo " Please install it with: pip install gunicorn" exit 1 fi # Build command array to handle spaces in paths properly cmd=( gunicorn -c gunicorn.config.py --worker-class uvicorn.workers.UvicornWorker --workers "${GUNICORN_WORKERS}" --timeout "${GUNICORN_TIMEOUT}" --max-requests "${GUNICORN_MAX_REQUESTS}" --max-requests-jitter "${GUNICORN_MAX_REQUESTS_JITTER}" --access-logfile - --error-logfile - ) # Add SSL arguments if enabled if [[ "${SSL}" == "true" ]]; then cmd+=( --certfile "${CERT_FILE}" --keyfile "${KEY_FILE}" ) fi # Add the application module cmd+=( "mcpgateway.main:app" ) # Launch Gunicorn with all configured options exec "${cmd[@]}"

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/SPRIME01/MCPContextForge'

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