Add internal development MCP server for Airflow API as part of Breeze#69381
Add internal development MCP server for Airflow API as part of Breeze#69381shahar1 wants to merge 3 commits into
Conversation
There was a problem hiding this comment.
I didn't review the whole implementation and the functionality yet, but based on the title and PR description I would like to cc @RoyLee1224 (our GSoC intern working on Agent Eval / Breeze Agent Skills recently!) here.
We had considered MCP for breeze before as well (I need to recall the context and dig into what we had discussed why not MCP but Agent Skills) or perhaps the purpose of the MCP this PR would like to introduce is different from what we want to achieve in Airflow GSoC Breeze Agent Skills -- #62500.
I will take a thorough review soon, and see what is the better next step for both directions.
Thanks! What was the intended scope of the solution you and Roy worked on? |
I would echo what @jason810496 wrote. I think MCP server is only really useful where you want to have some real "server side" content that you want to keep behind the server. Breeze does not really have any "data" behind to expose via MCP only "actions" and I would say SKILLs are much, much better (and cheaper) way of accessing breeze functionality - if we think CLI is not enough. |
I feel that there's a misunderstanding here (and I renamed the title, as previous one might have been misleading) - Edit: also clarified in the docs + ADR, it's indeed quite important to clarify the scope. |
0c39510 to
b2e6208
Compare
Ah... Never judge the book by the cover? :) |
|
I've read in the description that "breeze command line is unreliable so this is to replace it" - and yes - I have not read the PR, just jumped to the conclusion it's for the "breeze CLI" :) |
|
@abhishekbhakat you worked on a related project - any feedback you can share to improve this feature will be most welcome! |
|
I think the eval harness in #69308 could turn this n=2 A/B into a proper with/without comparison — happy to explore as a follow-up. |
| confirmation. Deliberately, there is **no dedicated `delete_*` tool**: deletion is reachable | ||
| only through the generic `airflow_api_call` escape hatch, so an agent must construct the method | ||
| and path explicitly rather than invoke a one-purpose delete tool — keeping deletion a conscious, | ||
| visible action and avoiding a standing, easily-triggered destructive verb in the tool list. |
There was a problem hiding this comment.
I have some reservations about this approach:
- Either allow deletion normally, or forbid it completely. At the moment it is "hidden" behind an extra tool use, so the only real effect is making it harder (i.e. require more steps), but not impossible, for an agent to run a risky action. What you'll get is agents that are worse at tool calling will be unable to run it, and agents that are good at it won't care.
- When an MCP available action is "risky", the right place to flag it is in the SKILL accompanying the MCP - it should use wording like "requires explicit user consent before calling" etc. In the absence of such instructions, there's little stopping the agent from sidestepping the MCP and calling the API directly
Additionally:
- I don't understand why have a "semi Code Mode" implementation - the split seems arbitrary, and a main benefit of the code mode transform (having an unlimited number of mcp endpoints w/o confusing agents) gets diluted.
How about having two flavors of the MCP, one with destructive actions enabled and one without?Edit: I noticed that this is what you already did with the env vars later.
There was a problem hiding this comment.
- It's not an extra tool use - it's a hard rejection at the request layer, enforced as a barrier on every call to the Airflow REST API.
- I agree that bypassing the MCP is possible by design, and there's nothing to do about it except for scoping the credentials via RBAC - which is out of scope for this PR. However, we should eventually implement the defense mechanism in two layers:
a. Skill level - prevents bypass attempts via explicit-consent wording in the SKILL (I'd prefer to leave that implementation to a follow-up PR, since this one is already large).
b. MCP level - prevents accidents from agents that already got past the skill-level guard. - During development of the MCP, I tried to aim towards the most common tools in use for internal development of Airflow (@jason810496 - airflowctl currently does not support some useful features such as task instances). I think that the current list is good enough to start with, we could always change it later as part of the evaluation or on the go. If and when we reach the scale that justifies usage of CodeMode - we could consider using it as well (considering it will also become stable at that time).
There was a problem hiding this comment.
It's not an extra tool use - it's a hard rejection at the request layer, enforced as a barrier on every call to the Airflow REST API.
By "extra tool use" I was referring to the below (emphasis mine):
plus two escape hatches (
airflow_api_get/airflow_api_call) so no endpoint is out of reach
Perhaps I misunderstood what "no endpoint out of reach" means (might be worth rewording?). If the endpoint is discoverable via one of the MCP methods, it practically begs the AI to sidestep the MCP - I can already imagine the following interaction: "hmm apparently there's a DELETE method in the API, let me try to call it" -> "seems like the MCP doesn't allow calling the method, perhaps it's a bug? <looking for workarounds...>" -> "oh, looks like this .env file has the necessary credentials to access the DB" -> "great, now can I start over with a fresh DB"
we should eventually implement the defense mechanism in two layers: a. Skill level ...
I think the Skill layer is an easy win. I urge you to consider making it now.
There was a problem hiding this comment.
Thanks Shahar for brining this up!
I confirmed that the purpose of MCP server for Airflow API and the Airflow GSoC Breeze Agent Skills #62500, the Breeze Agent Skills only focus on overall developer journey and ensure our developer-facing skills, Agents.md won't drift and will be able to verify the setup -> by eval).
the MCP is for Airflow REST API which is deployed as part of breeze, not for breeze commands.
I'll be happy if you could read through the use cases in the PR's description, as well as the ADR.
IIUC, we could achieve the same purpose and functionally by adding a new "rule" on AGENTS.md to route the query with Airflow CTL by breeze exec ... airflowctl or (even just naive docker exec ... airflowctl ...).
MCP for Airflow API server in Breeze is definitely another direction to achieve it but might introduce more maintenance effort.
I think the eval harness in #69308 could turn this n=2 A/B into a proper with/without comparison — happy to explore as a follow-up.
IMHO. How about waiting for the eval framework that @RoyLee1224 working in #69308 to settle down first before directly introducing MCP for Breeze. WDYT?
Additionally, @shahar1 would you mind to provide more context or even concrete setup for I've empirically tested the resolving 2*** GitHub issues by subagents, where each issue is resolved independently by 2 subagents with the same model (A/B testing): this part you mentioned when you have a moment? Thanks.
Then we're able to eval for both directions (without, MCP approach, AGENTS.md + defer to airflowctl approach)
The usage eval framework will be like the following as #69308 (comment) pointed out.
EVAL_REPEAT=3 prek run run-skill-eval --hook-stage manual --all-files
EVAL_FULL=1 prek run run-skill-eval --hook-stage manual --all-files
MODEL=claude-haiku-4-5-20251001 prek run run-skill-eval --hook-stage manual --all-files
From my perspective, If we miss context of some the server-side runtime, we should improve the coverage of Airflow CTL, leverage the existing feature at much as possible instead of introducing new deps in the first place. (IMO, CTL should be able to represent the all the Core API context)
Give MCP-capable coding agents a safe, vendor-neutral way to inspect and debug the Airflow instance running in Breeze - list Dags, runs and task instances, fetch tailed logs with tracebacks, surface import errors, and (opt-in) trigger or clear runs - without direct metastore access and without any airflow-core changes. This is the "internal Breeze tool" step of AIP-91: a standalone dev-only project (dev/mcp_server) proxying the public REST API, so later AIP-91/AIP-101 phases can grow out of it while production concerns stay out of scope. Deployed as the mcp_server component via "breeze start-airflow --mcp-server" (host port 28081) or run over stdio directly by any MCP client. Co-authored-by: Aritra Basu <24430013+aritra24@users.noreply.github.com> Generated-by: Claude Code (Opus 4.8)
RFC 10008 defines QUERY as a safe, idempotent method like GET, so the method safety gate should let it through without requiring the write gate. Floor fastmcp at 3.4 since that's the version actually resolved and tested, rather than claiming compatibility back to 3.0.
I don't think it's too much maintenance in practice:
I wouldn't like to gate on that, if it's ok - this is an opt-in feature that doesn't touch any other code areas, so I think we can run independently and evaluate/adjust along the way rather than block on it. I still see agentic skills and MCP as complementary here. In fact, we'll even need a dedicated skill for using the MCP, covering the consent/risk wording around write/delete operations discussed with @Dev-iL (separate from the other breeze-related skills you're developing as part of your current efforts). I'd be happy if Roy wants to contribute this part, once the eval framework settles.
For each issue I ran two headless agents (claude -p), same model (Sonnet), each in its own git worktree off the same main commit, unaware of each other, given the identical task prompt (reproduce, root-cause, fix, and add a regression test). The only difference was MCP access - one arm had the proposed MCP, the other was hard-denied it. I checked ground truth myself: each arm's regression test passes with its fix and fails without it. I evaluted some metrics from a JSON output (wall-clock, turns, tokens, cost) and parsed each transcript (pytest runs, live API/MCP calls). I used this method on two issues:
Agreed on the direction, but:
|
b2e6208 to
d50467e
Compare
There was a problem hiding this comment.
Interesting choice to using MCP Server for Breeze, and I'd like to understand the rationale a bit more. Like @potiuk mentioned, Server side/Remote MCP is where I see tremendous value of an MCP Server. In fact, I wrote https://kaxil.substack.com/p/mcp-vs-cli-vs-rest when people were calling MCP dead.
I don't see agentic skills and MCP as contradictory, but complementary: agentic skills for Breeze help build the contribution workflow correctly, while the MCP operates at runtime inspecting the live instance.
Skills that use CLIs can inspect live and are categorically better for such things for the reason mentioned in the blog post, specifically piping and chaining the output of various commands -- that makes output token efficient, which is why the suggestion of airflowctl makes complete sense to me.
IMO, we should first invest on ensuring our CLI tools are agent friendly before we go deeper on this route. Specifically asking as this started with Breeze.
airflowctl is still missing some commands we rely on (TIs, logs). Worth noting logs aren't in the legacy airflow CLI either - there's no airflow tasks logs command; fetching task logs has only ever been possible through the REST API (or the web UI), which is exactly what this MCP wraps.
I think then we should help get airflowctl over the line since that is what we are saying is going to be the recommending Prod way to reach to Airflow Prod deployment. That's one thing to consciously decide from maintenance & focus perspective with Helm Chart, airflowctl, API clients, etc
Adding a "Request changes", just to avoid accidental merges and have discussion. I might have a few weeks where I don't have access to laptop and as such if I don't respond, feel free to "dismiss" the request changes if it has been discussed and other committers are aligned.
Human Summary
To prepare the ground for production-scale user-facing MCP server for Airflow REST API, as proposed by AIP-91 (still in draft), I came to the conclusion that it might be better to start in lower scope with an MCP server for internal development purposes of the open-source (specifically the API parts), bundled with
breezeas an opt-in feature.There's a breeze ADR included as part of this PR (ADR-0018), I'll give tha main parts here:
Why?
It is intended mostly for using AI agents to tackle issues whose resolution requires multiple API calls
Without MCP, you have to rely on API calls using the CLI (hoping that the agent doesn't make typos), and there's some authentication friction (generating JWT tokens). With MCP - the server is deployed as part of breeze and takes care of the authentication parts, and the methods are exposed to the client.
The bigger payoff, though, is that exposing the API as typed, ready-to-call methods lets the agent cheaply inspect the live state of a running Airflow - so on issues that hinge on what's actually happening at runtime, it converges on a fix with far less trial-and-error instead of guessing.
How do you know that it (may) work?
I've empirically tested the resolving 2*** GitHub issues by subagents, where each issue is resolved independently by 2 subagents with the same model (A/B testing):
Both agents resolved the tested issues successfully, generating equivalent solutions.
In the issue with less requirement for multiple API calls - the MCP arm was no faster (slightly slower, in fact) and consumed more tokens.
However, in the other issue where there were multiple API calls - the MCP subagent took less than 50% of the running time and reached the fix with far fewer iterations (about half the turns and a third of the test runs).
*** Disclaimer: I'm aware that the sample space of 2 issues doesn't say much about statistical significance, but I'll be happy to reevaluate it when it's in used by others! (I'll also try it out on additional issues as long as the PR is in review)
How do we use it?
Deploying it as part of the breeze deployment is as easy as:
breeze start-airflow --mcp-serverto activate itImportant things
I'd like to thank @aritra24 for the brainstorming, discussion, and implementing a prototype.
AI Summary
Click here
Adds an **internal, development-only** [MCP](https://modelcontextprotocol.io/) server (`dev/mcp_server`) that lets any MCP-capable coding agent inspect and debug the Airflow instance running in Breeze through the public REST API — list Dags/runs/task instances, fetch tailed logs with tracebacks, surface import errors, diagnose a failed run in one call, and (opt-in) trigger/clear runs. It is **not** shipped to users and makes **no** airflow-core changes.This is the "internal Breeze tool" step of AIP-91: a stateless REST proxy (no direct metastore access, read-only by default) so later AIP-91/AIP-101 phases can grow out of it. Full rationale, alternatives, and the pros/cons are captured in a new ADR:
dev/breeze/doc/adr/0018-internal-mcp-server-for-breeze-development.md.Highlights
breeze start-airflow --mcp-server(host port 28081), run from mounted sources viauvx; also runnable over stdio by any MCP client. Gone when Breeze is off.AIRFLOW_MCP_ALLOW_WRITES;DELETEbehind a separate, stricterAIRFLOW_MCP_ALLOW_DELETES(off even when writes are on) and reachable only via the generic escape hatch — no dedicated delete tool. Secrets stripped from list responses.Dev MCP server testsjob; a contract test asserts every endpoint the server calls exists (with its method) in Airflow's committed OpenAPI spec, with a second test guarding that endpoint list against drift; the live-Breeze and real-LLM-client integration tests are opt-in/manual for now.Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (Opus 4.8) following the guidelines