servers / apache-airflow-mcp-server
apache-airflow-mcp-server
communityunknownpythonwrite capablehealthy
Production-grade MCP server for Apache Airflow - Enable AI agents to inspect DAGs, runs, logs, and perform operations
01Tools · 16
How to read this: tool names here are observed from a live tools/list handshake. The Risk label is a heuristic inferred from the tool name (write/destructive verbs), not from executing the tool — a conservative guess, not a verified capability. We never escalate risk from a description. Found one that's wrong? Tell us — we fix on report.
| Tool | Risk | Side effects | Approval |
|---|---|---|---|
| airflow_get_task_instance Return task metadata, config, attempt summary, optional rendered fields, and UI URLs.
Parameters
- instance | ui_url: Target selection (URL precedence)
- dag_id, dag_run_id, task_id: Required identifiers (unless resolved from ui_url)
- include_rendered: When true, include rendered template fields (truncated using max_rendered_bytes)
- max_rendered_bytes: Byte cap for rendered fields payload (default 100KB; accepts int/float/str, coerced to positive int, fractional values truncated)
Returns
- Response dict: { "task_instance": {...}, "task_config": {...}, "attempts": {...}, "ui_url": {...}, "request_id": str, "rendered_fields"?: {...} }
Notes
- `attempts.try_number` is the authoritative input for `airflow_get_task_instance_logs`.
- Rendered fields include `bytes_returned` and `truncated` metadata.
- Sensors increment `try_number` on every reschedule, so treat it as an attempt index; the derived retries counters are heuristic. | read | false | unknown |
| airflow_clear_task_instances Clear task instances for a DAG across one or more runs using Airflow's native filter set (destructive).
Parameters
- instance: Instance key (optional; mutually exclusive with ui_url)
- ui_url: Airflow UI URL to resolve instance (optional; takes precedence)
- dag_id: DAG identifier (required if ui_url not provided)
- task_ids: List of task IDs to clear (optional)
- start_date: ISO8601 start date filter (optional)
- end_date: ISO8601 end date filter (optional)
- include_subdags: Include subDAGs (optional)
- include_parentdag: Include parent DAG (optional)
- include_upstream: Include upstream tasks (optional)
- include_downstream: Include downstream tasks (optional)
- include_future: Include future runs (optional)
- include_past: Include past runs (optional)
- dry_run: Preview without mutating (default true); set false explicitly to clear
- reset_dag_runs: Reset DagRun state (optional)
Returns
- Response dict: { "dag_id": str, "cleared": object, "request_id": str }
- Raises: ToolError with compact JSON payload (`code`, `message`, `request_id`, optional `context`) | read | false | unknown |
| airflow_resolve_url Parse an Airflow UI URL, resolve instance and identifiers.
Parameters
- url: Airflow UI URL (http/https)
Returns
- Response dict: { "instance", "dag_id"?, "dag_run_id"?, "task_id"?, "try_number"?, "route", "request_id" }
- Raises: ToolError with compact JSON payload (`code`, `message`, `request_id`, optional `context`) | read | false | unknown |
| airflow_list_dags List DAGs (pause state + UI link) for the target instance.
Parameters
- instance: Instance key (optional; mutually exclusive with ui_url)
- ui_url: Airflow UI URL to resolve instance (optional; takes precedence - must match a configured host)
- limit: Max results (default 100; accepts int/float/str, coerced to non-negative int, fractional values truncated)
- offset: Offset for pagination (default 0; accepts int/float/str, coerced to non-negative int, fractional values truncated)
Returns
- Response dict: { "dags": [{ "dag_id", "is_paused", "ui_url" }], "count": int, "request_id": str }
- Raises: ToolError with compact JSON payload (`code`, `message`, `request_id`, optional `context`) | read | false | unknown |
| airflow_list_task_instances List task instances within one DAG run, including state and attempt log URLs.
Parameters
- instance: Instance key (optional)
- ui_url: Airflow UI URL to resolve instance/dag/dag_run (optional)
- dag_id: DAG identifier
- dag_run_id: DAG run identifier
- limit: Max results (default 100; accepts int/float/str, coerced to non-negative int, fractional values truncated)
- offset: Offset for pagination (default 0; accepts int/float/str, coerced to non-negative int, fractional values truncated)
- state: Optional list of task states (case-insensitive). When provided, only matching states are returned.
- task_ids: Optional list of task identifiers to include.
Returns
- Response dict: {
"task_instances": [{ "task_id", "state", "try_number", "ui_url" }],
"count": int,
"total_entries"?: int,
"filters"?: { "state": [...], "task_ids": [...] },
"request_id": str
}
- Raises: ToolError with compact JSON payload (`code`, `message`, `request_id`, optional `context`) | read | false | unknown |
| airflow_trigger_dag Trigger a DAG run with optional configuration.
Parameters
- instance: Instance key (optional; mutually exclusive with ui_url)
- ui_url: Airflow UI URL to resolve instance (optional; takes precedence)
- dag_id: DAG identifier (required if ui_url not provided)
- dag_run_id: Custom run id (optional)
- logical_date: Optional ISO8601 logical date/time assigned to the new run
- conf: Configuration object as dict or JSON string (optional)
- note: Run note/comment (optional)
Returns
- Response dict: { "dag_run_id": str, "ui_url": str }
- Raises: ToolError with compact JSON payload (`code`, `message`, `request_id`, optional `context`) | read | false | unknown |
| airflow_list_instances List configured Airflow instance keys.
Returns
- Response dict: { "instances": [str], "default_instance": str | null, "request_id": str }
- Raises: ToolError with compact JSON payload (`code`, `message`, `request_id`, optional `context`) | read | false | unknown |
| airflow_get_task_instance_logs Fetch task instance logs with optional filtering and truncation.
Large log handling: Logs >100MB automatically tail to last 10,000 lines (sets auto_tailed=true).
Host-segmented responses are flattened into a single string using headers of the form `--- [worker] ---`,
ensuring agents can reason about multi-host output.
The tool requires an explicit `try_number`; callers should first retrieve it via `airflow_get_task_instance`.
Filter order of operations:
1. Auto-tail: If log >100MB, take last 10,000 lines
2. tail_lines: Extract last N lines from log
3. filter_level: Find matching lines by level (content filter)
4. context_lines: Add surrounding lines around matches (symmetric: N before + N after)
5. max_bytes: Hard cap on total output (UTF-8 safe truncation)
Parameters
- instance: Instance key (optional, mutually exclusive with ui_url)
- ui_url: Airflow UI URL to resolve identifiers (optional)
- dag_id, dag_run_id, task_id, try_number: Task instance identifiers (required)
- filter_level: "error" | "warning" | "info" (optional) - Show only lines matching level
* "error": ERROR, CRITICAL, FATAL, Exception, Traceback
* "warning": WARN, WARNING + error patterns
* "info": INFO + warning + error patterns
- context_lines: N lines before/after each match (optional, clamped to [0, 1000]; accepts int/float/str, coerced to non-negative int, fractional values truncated)
- tail_lines: Extract last N lines before filtering (optional, clamped to [0, 100000]; accepts int/float/str, coerced to non-negative int, fractional values truncated)
- max_bytes: Maximum response size in bytes (default: 100KB ≈ 25K tokens, clamped to 1MB)
Returns
- Response dict with fields:
* log: Normalized/filtered log text (host headers inserted when needed)
* truncated: true if output exceeded max_bytes
* auto_tailed: true if original log >100MB triggered auto-tail
* bytes_returned: Actual byte size of returned log
* original_lines: Line count before any filtering
* returned_lines: Line count after all filtering/truncation
* match_count: Number of lines matching filter_level (before context expansion)
* meta.try_number: Attempt number for this task instance
* meta.filters: Echo of effective filters applied (shows clamped values)
* ui_url: Direct link to log view in Airflow UI
* request_id: Correlates with server logs
- Raises: ToolError with compact JSON payload (`code`, `message`, `request_id`, optional `context`) | read | false | unknown |
| airflow_clear_dag_run Destructively clear all task instances within one specific DAG run.
Parameters
- instance: Instance key (optional; mutually exclusive with ui_url)
- ui_url: Airflow UI URL to resolve instance (optional; takes precedence)
- dag_id: DAG identifier (required if ui_url not provided)
- dag_run_id: DAG run identifier (required if ui_url not provided)
- include_subdags: Include subDAGs (optional)
- include_parentdag: Include parent DAG (optional)
- include_upstream: Include upstream tasks (optional)
- include_downstream: Include downstream tasks (optional)
- dry_run: Preview without mutating (default true); set false explicitly to clear
- reset_dag_runs: Reset DagRun state (optional)
Returns
- Response dict: { "dag_id": str, "dag_run_id": str, "cleared": object, "request_id": str }
- Raises: ToolError with compact JSON payload (`code`, `message`, `request_id`, optional `context`) | write | true | unknown |
| airflow_dataset_events List dataset events.
Parameters
- instance: Instance key (optional)
- ui_url: Airflow UI URL to resolve instance (optional)
- dataset_uri: Dataset URI (required)
- limit: Max results (default 50; accepts int/float/str, coerced to non-negative int, fractional values truncated)
Returns
- Response dict: { "events": [object], "count": int, "request_id": str } | read | false | unknown |
| airflow_unpause_dag Resume DAG scheduling (sets `is_paused=False` and returns UI link).
Parameters
- instance: Instance key (optional; mutually exclusive with ui_url)
- ui_url: Airflow UI URL to resolve instance (optional; takes precedence)
- dag_id: DAG identifier (required if ui_url not provided)
Returns
- Response dict: { "dag_id": str, "is_paused": false, "ui_url": str, "request_id": str }
- Raises: ToolError with compact JSON payload (`code`, `message`, `request_id`, optional `context`) | read | false | unknown |
| airflow_get_dag Get DAG details and a UI link.
Parameters
- instance | ui_url: Provide one; `ui_url` auto-resolves/validates the host.
- dag_id: Required when only `instance` is supplied.
Returns
- Response dict: { "dag": object, "ui_url": str, "request_id": str }
- Raises: ToolError with compact JSON payload (`code`, `message`, `request_id`, optional `context`) | read | false | unknown |
| airflow_describe_instance Describe a configured Airflow instance (host + metadata, never secrets).
Parameters
- instance: Instance key (e.g., "data-stg")
Returns
- Response dict: { "instance", "host", "api_version", "verify_ssl", "auth_type", "request_id": str }
- Raises: ToolError with compact JSON payload (`code`, `message`, `request_id`, optional `context`) | read | false | unknown |
| airflow_pause_dag Pause DAG scheduling (sets `is_paused=True` and returns UI link).
Parameters
- instance: Instance key (optional; mutually exclusive with ui_url)
- ui_url: Airflow UI URL to resolve instance (optional; takes precedence)
- dag_id: DAG identifier (required if ui_url not provided)
Returns
- Response dict: { "dag_id": str, "is_paused": true, "ui_url": str, "request_id": str }
- Raises: ToolError with compact JSON payload (`code`, `message`, `request_id`, optional `context`) | read | false | unknown |
| airflow_get_dag_run Get a single DAG run and a UI link.
Parameters
- instance: Instance key (optional)
- ui_url: Airflow UI URL to resolve instance/dag/dag_run (optional)
- dag_id: DAG identifier
- dag_run_id: DAG run identifier
Returns
- Response dict: { "dag_run": object, "ui_url": str, "request_id": str } | write | true | unknown |
| airflow_list_dag_runs List DAG runs (defaults to execution_date DESC) with per-run UI URLs.
Parameters
- instance: Instance key (optional)
- ui_url: Airflow UI URL to resolve instance/dag_id (optional)
- dag_id: DAG identifier (required if ui_url not provided)
- limit: Max results (default 100; accepts int/float/str, coerced to non-negative int, fractional values truncated)
- offset: Offset for pagination (default 0; accepts int/float/str, coerced to non-negative int, fractional values truncated)
- state: List of states to filter by (optional)
- order_by: Optional `"start_date"`, `"end_date"`, `"execution_date"`, or `"logical_date"` (omit to use ``execution_date``; execution_date and logical_date are mapped to whichever name the target Airflow version uses)
- descending: Sort direction (default True). Ignored when order_by is omitted; defaults always use execution_date descending
Returns
- Response dict: { "dag_runs": [{ "dag_run_id", "state", "start_date", "end_date", "ui_url" }], "count": int, "request_id": str }
- Raises: ToolError with compact JSON payload (`code`, `message`, `request_id`, optional `context`) | read | false | unknown |
02Install & source
uvx apache-airflow-mcp-server
uvxpip install apache-airflow-mcp-server
pip- repohttps://github.com/madamak/apache-airflow-mcp-server
- packagehttps://pypi.org/project/apache-airflow-mcp-server
- homepagehttps://github.com/madamak/apache-airflow-mcp-server
- licenseApache-2.0
- adoption2 stars · 0 forks
05Provenance & freshness
sourcesPyPI [p4]
last_checked2026-08-16 20:20Z
next_check2026-08-16 23:10Z
cadenceevery 3h
verifiedtools_list:passed handshake:passed metadata:passed tools_list:passed handshake:passed metadata:passed tools_list:passed handshake:passed metadata:passed tools_list:passed
index_statusindex — 8 unique facts >= 5
06Badge
Add the “as seen on MCPExplorer” badge to your README.
[](https://mcpexplorer.com/servers/apache-airflow-mcp-server)
Next step
This is one server. A loadout combines the right servers, governance, and proven plays for a whole job — assembled deliberately, not tool-dumped.
Explore loadouts →