BrianLondon

airflow-dev-mcp

Community BrianLondon
Updated

MCP server to facilitate testing Airflow jobs directly from AI coding tools

airflow-dev-mcp

An MCP server that lets an AI coding assistant(Claude Code, Cursor, and other MCP clients) drive a development or local Airflowcluster through its REST API — trigger DAG runs, watch their status, read task logs,and diagnose parse errors, without leaving your editor.

It talks to Airflow over HTTP only. There's no dependency on your Airflow source tree,no filesystem access, and no local config files — everything is set through environmentvariables. It works against both Airflow 3.x (/api/v2, the default) andAirflow 2.x (/api/v1).

Meant for dev/local clusters. It's designed for the write-a-DAG / run-it / read-the-logsloop against a throwaway environment. Pointing it at a production cluster is not recommended.

Install & run

The package ships a single console command, airflow-dev-mcp, which starts the MCPserver on stdio. You rarely run it by hand — your MCP client launches it for you (seebelow). To try it directly, the zero-install option is uv:

uvx airflow-dev-mcp --check      # fetch + run a one-shot connectivity check

Or install it as a persistent tool:

uv tool install airflow-dev-mcp
# or
pipx install airflow-dev-mcp

Configure your MCP client

Claude Code

Add the server to ~/.claude.json (applies everywhere) or a project's.claude/settings.json (just that project):

{
  "mcpServers": {
    "airflow-dev": {
      "command": "uvx",
      "args": ["airflow-dev-mcp"],
      "env": {
        "AIRFLOW_URL": "http://localhost:8081",
        "AIRFLOW_USERNAME": "admin",
        "AIRFLOW_PASSWORD": "admin"
      }
    }
  }
}

Using uvx means you don't have to manage a virtualenv — it fetches and caches thepackage on first launch. If you'd rather pin an installed copy, replace the command with"command": "airflow-dev-mcp", "args": [] after uv tool install.

Restart Claude Code. The tools show up namespaced as mcp__airflow-dev__trigger_dag,and so on.

Other MCP clients

Any client that launches stdio MCP servers works the same way: run the commandairflow-dev-mcp (or uvx airflow-dev-mcp) with the environment variables below.

Configuration

All configuration is via environment variables:

Variable Default Description
AIRFLOW_URL http://localhost:8080 Base URL of the cluster, no path.
AIRFLOW_API_PREFIX /api/v2 API path prefix. Use /api/v1 for Airflow 2.x.
AIRFLOW_USERNAME Username. Used together with AIRFLOW_PASSWORD.
AIRFLOW_PASSWORD Password.
AIRFLOW_TOKEN Explicit bearer token; skips username/password entirely.
AIRFLOW_AUTH_MODE auto auto, jwt, or basic (see below).
AIRFLOW_TOKEN_ENDPOINT /auth/token Path used to exchange credentials for a JWT.
AIRFLOW_TIMEOUT 30 HTTP timeout, in seconds.
AIRFLOW_VERIFY_SSL true Set false to skip TLS verification (self-signed dev certs).

Authentication

  • Airflow 3.x (the default local/MWAA-style image): leave AIRFLOW_AUTH_MODE=auto.The server posts your username/password to /auth/token, caches the returned JWT, andsends it as a bearer token on every request.
  • Airflow 2.x: set AIRFLOW_API_PREFIX=/api/v1 and AIRFLOW_AUTH_MODE=basic (2.xuses HTTP basic auth against the REST API).
  • Pre-issued token: set AIRFLOW_TOKEN and omit the username/password.

Tools

Tool What it does
trigger_dag Start a manual DAG run, optionally with a conf payload. Returns the dag_run_id.
get_run_status State of a run plus per-task states (task, state, try number, operator, timing).
get_task_logs Logs for one task attempt, tailed to the last N lines by default.
list_dag_runs Recent runs of a DAG — find a run when you don't already have its id.
clear_task_instances Clear tasks so they re-run. Defaults to a dry-run preview.
list_dags Registered DAGs with their paused / import-error / active flags.
get_import_errors Parse failures with filename and traceback — why a new DAG isn't showing up.
set_dag_paused Pause or unpause a DAG (new local DAGs start paused).
list_variables Read Airflow Variables (read-only).
list_connections Read Airflow Connections, minus passwords (read-only).

The four list_* tools, get_run_status, get_task_logs, and get_import_errors arestrictly read-only. trigger_dag, set_dag_paused, and clear_task_instances changecluster state. There are deliberately no tools that create or modify Variables orConnections — that's cluster administration, out of scope for a DAG-development helper.

A typical loop

  1. Write or edit a DAG file; Airflow re-parses it.
  2. list_dags to confirm it registered — or get_import_errors if it didn't.
  3. set_dag_paused(dag_id, paused=false) to enable it (new DAGs start paused).
  4. trigger_dag(dag_id, conf={...}), note the returned dag_run_id.
  5. get_run_status(dag_id, run_id) until it finishes.
  6. On failure, get_task_logs(...); fix the code, then clear_task_instances(dag_id, dag_run_id, dry_run=false) to re-run just the affected tasks.

Approving tools once (Claude Code)

Because each capability is its own MCP tool, Claude Code can remember your approvalper tool — unlike shell curl calls, which re-prompt whenever the command stringchanges. When a tool first runs, choosing "don't ask again" persists an allow rule.You can also pre-approve tools in settings so they never prompt.

A reasonable split is to allow the read-only tools and let the state-changing ones prompt.In .claude/settings.json (project) or ~/.claude/settings.json (global):

{
  "permissions": {
    "allow": [
      "mcp__airflow-dev__list_dags",
      "mcp__airflow-dev__get_run_status",
      "mcp__airflow-dev__get_task_logs",
      "mcp__airflow-dev__get_import_errors",
      "mcp__airflow-dev__list_dag_runs",
      "mcp__airflow-dev__list_variables",
      "mcp__airflow-dev__list_connections"
    ]
  }
}

Leaving trigger_dag, set_dag_paused, and clear_task_instances off the list meansthey still ask before acting.

Verifying your setup

Before wiring it into an editor, confirm the URL and credentials work end-to-end:

AIRFLOW_URL=http://localhost:8081 \
AIRFLOW_USERNAME=admin AIRFLOW_PASSWORD=admin \
  uvx airflow-dev-mcp --check

It prints OK — … with the DAG count on success, or FAIL — … with the reason(wrong URL, auth failure, or an /api/v1 vs /api/v2 mismatch).

Releasing (maintainers)

Releases publish to PyPI automatically via Trusted Publishing (OIDC) — no APItoken is stored in the repo or in GitHub secrets. The.github/workflows/publish.yml workflow builds anduploads whenever a GitHub Release is published.

One-time setup on PyPI (before the first release):

  1. Go to https://pypi.org/manage/account/publishing/ and add a pending publisher(works even though the project doesn't exist on PyPI yet):
    • PyPI Project Name: airflow-dev-mcp
    • Owner: BrianLondon  ·  Repository: airflow-dev-mcp
    • Workflow name: publish.yml
    • Environment name: pypi
  2. In the GitHub repo, create an Environment named pypi(Settings → Environments). Optionally add required reviewers there to gateuploads behind a manual approval.

To cut a release:

  1. Bump __version__ in src/airflow_dev_mcp/__init__.py and commit.
  2. Tag and push: git tag v0.2.0 && git push origin main --tags.
  3. Create a GitHub Release for that tag. The workflow builds, runs twine check,and publishes to PyPI.

License

MIT — see LICENSE.

MCP Server · Populars

MCP Server · New

    semihbugrasezer

    seerxo

    AI-powered Etsy product listing generator for Claude Desktop Generate perfect SEO titles, descriptions, and tags in seconds

    Community semihbugrasezer
    ohad6k

    Ditto

    Mine your Claude Code and Codex logs into a local you.md agent profile.

    Community ohad6k
    aidatacooper

    cwtwb

    A Python-based engine that enables Text-to-Tableau twb dashboards generation.

    Community aidatacooper
    aeonfun

    OPENDIA

    Connect your browser to AI models. Just use Dia on Chrome, Arc or Firefox.

    Community aeonfun
    modelscope

    funasr

    Industrial-grade speech recognition toolkit: 170x realtime, 50+ languages, speaker diarization, emotion detection, streaming, and OpenAI-compatible API.

    Community modelscope