Fix Airflow MCP plugin mode for remote deployments#183
Merged
kaxil merged 1 commit intomainastronomer/agents:mainfrom Apr 14, 2026
fix/airflow-mcp-plugin-modeastronomer/agents:fix/airflow-mcp-plugin-modeCopy head branch name to clipboard
Merged
Fix Airflow MCP plugin mode for remote deployments#183kaxil merged 1 commit intomainastronomer/agents:mainfrom fix/airflow-mcp-plugin-modeastronomer/agents:fix/airflow-mcp-plugin-modeCopy head branch name to clipboard
kaxil merged 1 commit intomainastronomer/agents:mainfrom
fix/airflow-mcp-plugin-modeastronomer/agents:fix/airflow-mcp-plugin-modeCopy head branch name to clipboard
Conversation
Plugin mode had three issues preventing it from working on Astro deployments: 1. FastMCP's streamable HTTP transport stored sessions in-memory, so requests load-balanced across multiple API server replicas got "Session not found" errors. Fixed by enabling stateless_http=True. 2. The plugin never called configure(), so the adapter defaulted to http://localhost:8080 which uses the wrong port on Astro (9091) and attempted credential-less token fetches that fail on non-local setups. Fixed by auto-detecting the port from Airflow's [api] config. 3. Internal Airflow API calls had no auth token. Fixed by adding ASGI middleware that extracts the Authorization header from incoming MCP requests and forwards it to internal API calls via a per-request ContextVar (thread-safe for concurrent async requests). Also adds plugin mode documentation with MCP client config examples for Cursor/VS Code connecting to Astro deployments. Closes AI-190
schnie
approved these changes
Apr 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Plugin mode had three issues preventing it from working on Astro deployments:
stateless_http=True.configure(), so the adapter defaulted tolocalhost:8080. On Astro the API server runs on port 9091. Fixed by reading[api] portfrom Airflow config.Authorizationheader from incoming MCP requests and forwards it to internal API calls via a per-requestContextVar(safe for concurrent async requests).Design rationale
Why
stateless_http=True? The MCP spec (2025-03-26) says sessions are optional ("a server MAY assign a session ID"). Stateless mode means every POST is independent — no in-memory session store, works with any number of replicas without session affinity.Why forward the client's token instead of generating one internally? The MCP client already authenticates with a valid Airflow/Astro token. Forwarding it to localhost API calls is equivalent to the user making those calls directly — no privilege escalation, no credential management, no
/auth/tokenround-trips.Why
ContextVarinstead of setting_manager._auth_tokendirectly? With concurrent async requests, a shared attribute would race — Alice's token could be overwritten by Bob's before Alice's tool call reads it.ContextVaris scoped per-async-task (per-request in ASGI).Why pure ASGI middleware instead of
BaseHTTPMiddleware?BaseHTTPMiddlewarerunscall_nextin a separate task, which breaksContextVarpropagation. A pure ASGI middleware class runs in the same task as the downstream handler.Tested on
url-based config