How the MCP Server Handles Environment Variable Configuration: Precedence, Auth, and Airflow Connection

The MCP server in call518/mcp-airflow-api reads runtime configuration from environment variables with a strict precedence hierarchy—command-line arguments override environment variables, which override hardcoded defaults—split across server settings, authentication, and Airflow API connection parameters.

The mcp-airflow-api repository implements a flexible configuration system that allows operators to deploy the Multi-Chat-Protocol server in diverse environments, from local STDIO debugging to production HTTP deployments. Understanding how environment variables interact with CLI flags and default values is essential for secure, reliable deployments.

Configuration Categories and Environment Variables

The server organizes configuration into three distinct concerns, each managed through specific environment variables with sensible defaults.

Server-Side Settings

Located in src/mcp_airflow_api/mcp_main.py (lines 313-335), these variables control the transport layer and logging:

  • MCP_LOG_LEVEL — Controls verbosity; defaults to "INFO"
  • FASTMCP_TYPE — Transport protocol; defaults to "stdio" (alternative: "streamable-http")
  • FASTMCP_HOST — Bind address for HTTP mode; defaults to "127.0.0.1"
  • FASTMCP_PORT — Listen port for HTTP mode; defaults to 8000

Authentication Settings

Also handled in mcp_main.py (lines 338-445), these enable optional static token verification for HTTP transports:

  • REMOTE_AUTH_ENABLE — Boolean flag parsed by _parse_bool_env(); defaults to false
  • REMOTE_SECRET_KEY — Required when auth is enabled; defaults to empty string ""

Airflow API Connection Settings

Defined in src/mcp_airflow_api/functions.py (lines 51-63, 94-95), these credentials target the upstream Airflow instance:

  • AIRFLOW_API_BASE_URL — Primary endpoint URL; falls back to legacy AIRFLOW_API_URL if empty
  • AIRFLOW_API_VERSION — API version string; defaults to "v1"
  • AIRFLOW_API_USERNAME — Basic Auth or JWT username
  • AIRFLOW_API_PASSWORD — Basic Auth password or JWT secret

Precedence Logic: CLI Overrides Environment

The entry-point main() function implements a simple but effective precedence pattern. Each configuration value resolves using:

value = args.option or os.getenv("ENV_VAR", default)

This means command-line arguments take highest priority, followed by environment variables, then hardcoded defaults.

In src/mcp_airflow_api/mcp_main.py (lines 312-324), the log level demonstrates this hierarchy:

log_level = args.log_level or os.getenv("MCP_LOG_LEVEL", "INFO")

If you pass --log-level DEBUG, it overrides MCP_LOG_LEVEL=WARNING. If neither is provided, the server uses "INFO".

Server Transport Configuration

The transport layer configuration determines how clients connect to the MCP server. The code in mcp_main.py (lines 329-336) reads:

fastmcp_type = args.type or os.getenv("FASTMCP_TYPE", "stdio")
fastmcp_host = args.host or os.getenv("FASTMCP_HOST", "127.0.0.1")
fastmcp_port = int(args.port or os.getenv("FASTMCP_PORT", "8000"))

These values are passed directly to FastMCP.run() (lines 376-381) to initialize either STDIO or HTTP transport. When using streamable-http, the server binds to the specified host and port; with stdio, these network settings are ignored.

Authentication Enablement and Token Verification

Remote authentication is controlled by a custom truthy parser _parse_bool_env() (lines 38-43) that recognizes "true", "1", "yes", and "on" case-insensitively.

When REMOTE_AUTH_ENABLE is truthy and FASTMCP_TYPE is streamable-http, the server:

  1. Validates that fastmcp provides StaticTokenVerifier
  2. Requires a non-empty REMOTE_SECRET_KEY
  3. Builds a static token verifier via _build_static_token_auth() (lines 666-671)

If authentication is disabled or the transport is STDIO, the server logs a warning and proceeds without token verification, allowing unrestricted local access.

Airflow API Connection Resolution

All Airflow interactions flow through airflow_request() in functions.py. The URL construction is version-aware and supports legacy configuration:

base_url = get_api_base_url()  # AIRFLOW_API_BASE_URL or AIRFLOW_API_URL fallback

version = get_api_version()    # AIRFLOW_API_VERSION, default "v1"

full_url = f"{base_url}/{version}{path}"

The base URL extraction (lines 51-59) prioritizes AIRFLOW_API_BASE_URL, falling back to the legacy AIRFLOW_API_URL if the primary variable is empty. The version defaults to "v1" (lines 61-64), but setting AIRFLOW_API_VERSION=v2 triggers JWT token authentication instead of Basic Auth.

Credentials are extracted from AIRFLOW_API_USERNAME and AIRFLOW_API_PASSWORD (lines 94-95). For API v2, get_jwt_token() automatically obtains a Bearer token; for v1, the credentials are encoded as Basic Auth headers.

Logging Configuration

The selected log level applies globally via logging.getLogger().setLevel() and propagates to the module-specific logger. The server explicitly suppresses noisy aiohttp logs at the WARNING level (lines 315-319) to prevent log flooding during HTTP transport operations.

Practical Configuration Examples

Example 1: Production HTTP Deployment with Environment Variables Only

export MCP_LOG_LEVEL=DEBUG
export FASTMCP_TYPE=streamable-http
export FASTMCP_HOST=0.0.0.0
export FASTMCP_PORT=8080
export REMOTE_AUTH_ENABLE=true
export REMOTE_SECRET_KEY=super-secret-key
export AIRFLOW_API_BASE_URL=http://airflow.example.com/api
export AIRFLOW_API_VERSION=v2
export AIRFLOW_API_USERNAME=admin
export AIRFLOW_API_PASSWORD=admin-pwd

python -m mcp_airflow_api

This configuration starts the server in HTTP mode on all interfaces, enforces static token authentication, and communicates with an Airflow v2 endpoint using JWT tokens.

Example 2: CLI Override During Development

MCP_LOG_LEVEL=INFO FASTMCP_PORT=9000 \
    python -m mcp_airflow_api --log-level DEBUG --port 12345

Result:

  • Log level: DEBUG (CLI flag wins over environment)
  • Port: 12345 (CLI flag wins over FASTMCP_PORT)
  • Other settings: Inherited from environment or defaults

Example 3: Local STDIO Testing Without Authentication

export REMOTE_AUTH_ENABLE=false
python -m mcp_airflow_api --type stdio

The server runs with simple STDIO transport, printing a warning that authentication is disabled, suitable for local debugging and integration testing.

Summary

  • Precedence is strict: CLI arguments override environment variables, which override defaults.
  • Transport flexibility: Use FASTMCP_TYPE to switch between stdio (default) and streamable-http.
  • Authentication conditional: REMOTE_AUTH_ENABLE only affects HTTP transport; requires REMOTE_SECRET_KEY when active.
  • Airflow connectivity: Configure via AIRFLOW_API_BASE_URL, version-aware with automatic JWT handling for v2.
  • Source locations: Configuration parsing lives in src/mcp_airflow_api/mcp_main.py (server/auth) and src/mcp_airflow_api/functions.py (Airflow connection).

Frequently Asked Questions

What is the exact precedence order for configuration values?

Command-line arguments take absolute precedence. If a CLI flag is omitted, the server checks the corresponding environment variable. If the environment variable is unset or empty, it falls back to the hardcoded default defined in the source code. This pattern is implemented consistently in src/mcp_airflow_api/mcp_main.py using args.option or os.getenv("VAR", default).

Can I enable authentication for STDIO transport?

No. The authentication logic explicitly checks that FASTMCP_TYPE is set to streamable-http before enabling StaticTokenVerifier. If you set REMOTE_AUTH_ENABLE=true while using STDIO, the server logs a warning and continues without token verification, as implemented in mcp_main.py lines 338-445.

Which Airflow API environment variables are mandatory?

AIRFLOW_API_BASE_URL (or the legacy AIRFLOW_API_URL) must be supplied—the default is an empty string that will cause connection failures. AIRFLOW_API_USERNAME and AIRFLOW_API_PASSWORD are technically optional depending on your Airflow configuration, but the code in functions.py (lines 94-95) expects them for both Basic Auth and JWT flows.

How does the server handle boolean environment variables?

The helper function _parse_bool_env() in mcp_main.py (lines 38-43) parses boolean flags case-insensitively, accepting "true", "1", "yes", and "on" as truthy values. Any other value (including empty strings) evaluates to false, making the default REMOTE_AUTH_ENABLE=false behavior safe and predictable.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →