Skip to content

Add env_provider and Extra.env support to MCP stdio transport - #69225

Merged
kaxil merged 2 commits into
apache:mainfrom
astronomer:mcp-stdio-env
Jul 2, 2026
Merged

Add env_provider and Extra.env support to MCP stdio transport#69225
kaxil merged 2 commits into
apache:mainfrom
astronomer:mcp-stdio-env

Conversation

@kaxil

@kaxil kaxil commented Jul 1, 2026

Copy link
Copy Markdown
Member

MCPHook's stdio transport built StdioTransport without ever passing an env argument, so a local MCP server subprocess had no way to receive configuration or credentials except by inheriting the worker's ambient environment. This adds:

  • Extra.env — a static dict[str, str] in the connection's extra, now passed through to the subprocess.
  • env_provider — a zero-argument callable returning dict[str, str], mirroring the existing token_provider for HTTP/SSE. Its return value is merged over Extra.env (env_provider wins on key conflicts), and every value it returns is registered with secret masking regardless of key name.

Why env_provider, not just Extra.env?

Extra.env is fine for a value that genuinely belongs to this connection. env_provider exists for the same reason token_provider does on HTTP/SSE: the credential has no stable static form to store here at all — either because it lives in a different Airflow connection (avoiding two places to rotate the same secret), or because it's minted fresh per call (an OAuth token, a Vault lease) with nothing fixed to store anywhere.

Usage

from airflow.providers.common.ai.toolsets.mcp import MCPToolset


def mint_env() -> dict[str, str]:
    from airflow.providers.common.compat.sdk import BaseHook

    return {"API_KEY": BaseHook.get_connection("my_other_conn").password}


toolset = MCPToolset(mcp_conn_id="my_stdio_mcp", env_provider=mint_env)

Gotchas

  • Extra.env is Fernet-encrypted at rest like the rest of the connection's extra, but it's only masked in the Connections UI/API and task logs if a key's name happens to match a fixed set of sensitive-looking names (api_key, token, secret, password, etc.). env_provider values are always masked regardless of key name.
  • Both token_provider and env_provider are invoked once, the first time a given hook/toolset instance establishes a connection — not on every reconnect of that same instance.
  • Passing env=None (no static Extra.env and no env_provider) does not inherit the full parent process environment; the MCP stdio client falls back to a small allowlist of variables (see the mcp package's get_default_environment()).
  • Both the static Extra.env values and env_provider's return value are validated (non-empty string keys/values) at connection-build time, so a misconfigured connection fails with a clear, attributed error instead of a bare TypeError deep inside subprocess.Popen.

MCPHook's stdio branch built StdioTransport without ever passing an env
argument, so subprocess-based MCP servers had no way to receive credentials
except by inheriting the worker's ambient environment. Extra.env now reaches
the subprocess, and env_provider (mirroring the existing token_provider for
HTTP/SSE) lets a credential that lives in a different connection, or one
minted fresh per call, be resolved lazily at connection-establish time
instead of being duplicated into this connection's static config.
@vikramkoka

Copy link
Copy Markdown
Contributor

Oh, very interesting change. Didn't expect this, but this seems very logical to add

@vikramkoka vikramkoka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, makes sense to me.
Also, is nice and localized.

sphinx-spelling tokenizes hyphenated compounds as a single word, so the
unquoted "MCP-server" didn't match the wordlist entry for "MCP" even though
standalone MCP is already allowlisted.
@kaxil
kaxil merged commit e29d36f into apache:main Jul 2, 2026
77 checks passed
@kaxil
kaxil deleted the mcp-stdio-env branch July 2, 2026 00:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants