Skip to content

fix(mcp)!: decouple external access, fix read-only mode, add X-MCP-Allow-Destructive-Tools, generic unsupported-input guard - #1360

Merged
Aaron ("AJ") Steers (aaronsteers) merged 13 commits into
release-candidate/v1from
devin/1791835169-mcp-external-access-orthogonal
Oct 12, 2026
Merged

Aaron ("AJ") Steers (aaronsteers) merged 13 commits into
release-candidate/v1from
devin/1791835169-mcp-external-access-orthogonal

Conversation

@aaronsteers

@aaronsteers Aaron ("AJ") Steers (aaronsteers) commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

Overview

👉 TL;DR: Cloud MCP tool policies now match the hosted docs:

  1. Pipeline changes and external access are independent. Turning off pipeline changes no longer hides SQL/API passthrough tools.
  2. AIRBYTE_CLOUD_MCP_READONLY_MODE=1 now hides and blocks every tool that isn't read-only, including run_cloud_sync and cancel_cloud_sync.
  3. New X-MCP-Allow-Destructive-Tools: 0 / AIRBYTE_CLOUD_MCP_ALLOW_DESTRUCTIVE_TOOLS=0 policy that hides and blocks destructive tools.
  4. Removed env vars and headers now go through one generic, map-driven guard instead of safe-mode-specific code.

Pairs with:

Changes

  • external_access_allowed() drops the fallback to pipeline_changes_allowed(), and the AirbyteExternalAccessDisabledError guidance drops the coupling sentence.
  • Read-only mode: new airbyte_readonly_mode_enabled(). airbyte_readonly_mode_filter hides tools that lack readOnlyHint, and PolicyGuardMiddleware raises the new AirbyteReadOnlyModeError for them. Pipeline-change denial still leaves run/cancel sync available.
  • Destructive tools: new ALLOW_DESTRUCTIVE_TOOLS_CONFIG_ARG, destructive_tools_allowed() (same _resolve_policy env/header precedence) and airbyte_destructive_tools_filter. The middleware blocks with the new AirbyteDestructiveToolsDisabledError.
  • Unsupported inputs: new UNSUPPORTED_ENV_VARS / UNSUPPORTED_MCP_HEADERS maps (removed name → guidance) replace check_if_demo_mode_guards() / check_legacy_safe_mode_header(). UNSUPPORTED_ENV_VARS / check_unsupported_env_vars() live in airbyte/_util/unsupported_inputs.py and run before every pyab CLI command (declaratively, via cli = App(..., config=[_check_unsupported_env_vars_hook]); [project.scripts] still points at airbyte.cli.pyab:cli) and at startup of both MCP servers, and check_unsupported_mcp_headers() runs on tools/list and tools/call. The only entries so far are AIRBYTE_CLOUD_MCP_SAFE_MODE and X-MCP-Safe-Mode, and their guidance now points to AIRBYTE_CLOUD_MCP_ALLOW_DESTRUCTIVE_TOOLS=0 / X-MCP-Allow-Destructive-Tools: 0.
  • docs/CONTRIBUTING.md: new ## Removing Environment Variables and MCP Headers section.
  • Pipeline-change, read-only and destructive policies now apply only to Cloud tools (modules cloud and interactive, via _is_cloud_tool), which matches the documented "local operations are not affected" contract. Local tools such as destination_smoke_test stay available.
  • airbyte/mcp/__init__.py docs cover all three settings, plus the read-only vs. pipeline-change behavior for sync run/cancel.
  • Tests in test_mcp_policy_middleware.py and test_mcp_tool_filters.py cover each policy through both filters and middleware.

Review Spotlight

Reviewers with limited time, please review first:

  • airbyte/mcp/_policy_middleware.py on_call_tool: read-only, pipeline, external-access and destructive checks, in that order
  • airbyte/mcp/_tool_utils.py airbyte_readonly_mode_filter and airbyte_destructive_tools_filter
  • airbyte/_util/unsupported_inputs.py and airbyte/mcp/_tool_utils.py UNSUPPORTED_MCP_HEADERS
  • airbyte/mcp/_tool_utils.py _is_cloud_tool / _CLOUD_MCP_MODULES

Risks

  • Deployments that set only AIRBYTE_CLOUD_MCP_ALLOW_PIPELINE_CHANGES=0 or AIRBYTE_CLOUD_MCP_READONLY_MODE=1, or clients that send only X-MCP-Allow-Pipeline-Changes: 0, now expose SQL/API passthrough tools. Set X-MCP-Allow-External-Access: 0 explicitly to keep blocking them.
  • Deployments with AIRBYTE_CLOUD_MCP_READONLY_MODE=1 lose run_cloud_sync / cancel_cloud_sync.
  • AIRBYTE_CLOUD_MCP_ALLOW_PIPELINE_CHANGES=0 and AIRBYTE_CLOUD_MCP_READONLY_MODE=1 used to also hide non-read-only local tools. They no longer do.
  • The safe-mode env guidance used to differ by mode. Now one static string lists demo mode as "local mode only", and hosted shows it too.
  • The upstream fastmcp-extensions X-MCP-No-Destructive-Tools / MCP_NO_DESTRUCTIVE_TOOLS filter still works but isn't documented anymore.

Test plan

  • uv run ruff check ., uv run ruff format --check ., uv run pyrefly check airbyte/mcp airbyte/exceptions.py airbyte/constants.py
  • uv run pytest tests/unit_tests/test_mcp_tool_utils.py tests/unit_tests/test_mcp_policy_middleware.py tests/unit_tests/test_mcp_tool_filters.py tests/unit_tests/test_mcp_http_main.py -q plus tests/unit_tests/test_unsupported_inputs.py (106 passed at d84f042)
  • uv run pytest tests/unit_tests/test_unsupported_inputs.py tests/unit_tests/test_cli.py -q (17 passed at 8758a36); AIRBYTE_CLOUD_MCP_SAFE_MODE=1 pyab benchmark fails with the guidance, pyab --help still works

Link to Devin session: https://app.devin.ai/sessions/5dd86f59bf0e4c0ea97d21c1111a8f8c
Open in Devin Desktop: https://app.devin.ai/desktop/session/5dd86f59bf0e4c0ea97d21c1111a8f8c?variant=devin
Requested by: Aaron ("AJ") Steers (@aaronsteers)

Important

Auto-merge enabled.

This PR is set to merge automatically when all requirements are met.

devin-ai-integration Bot and others added 2 commits October 12, 2026 20:00
…policy

Co-Authored-By: AJ Steers <aj@airbyte.io>
Co-Authored-By: AJ Steers <aj@airbyte.io>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@github-actions

Copy link
Copy Markdown

👋 Greetings, Airbyte Team Member!

Here are some helpful tips and reminders for your convenience.

💡 Show Tips and Tricks

Testing This PyAirbyte Version

You can test this version of PyAirbyte using the following:

# Run PyAirbyte CLI from this branch:
uvx --from 'git+https://github.com/airbytehq/PyAirbyte.git@devin/1791835169-mcp-external-access-orthogonal' pyairbyte --help

# Install PyAirbyte from this branch for development:
pip install 'git+https://github.com/airbytehq/PyAirbyte.git@devin/1791835169-mcp-external-access-orthogonal'

PR Slash Commands

Airbyte Maintainers can execute the following slash commands on your PR:

  • /fix-pr - Fixes most formatting and linting issues
  • /uv-lock - Updates uv.lock file
  • /test-pr - Runs tests with the updated PyAirbyte
  • /prerelease - Builds and publishes a prerelease version to PyPI
📚 Show Repo Guidance

Helpful Resources

Community Support

Questions? Join the #pyairbyte channel in our Slack workspace.

📝 Edit this welcome message.

Copilot AI 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.

🟢 Approval recommended

The focused implementation, documentation, and tests consistently enforce the intended policy independence.

0 open findings

What changed in this PR

Decouples external-data access controls from pipeline-change and read-only policies.

Changes:

  • Resolves external-access permission independently.
  • Updates guidance and documentation.
  • Expands policy/filter tests for independent behavior.
File Description
airbyte/​mcp/​_tool_utils.py Removes pipeline-policy fallback.
airbyte/​mcp/​__init__.py Documents independent controls.
airbyte/​exceptions.py Updates remediation guidance.
tests/​unit_tests/​test_mcp_policy_middleware.py Tests runtime enforcement.
tests/​unit_tests/​test_mcp_tool_filters.py Tests tool visibility.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-code-quality

github-code-quality Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: Python

Python / code-coverage/pytest-no-creds

The overall line coverage in commit 8758a36 in the devin/1791835169-mcp... branch is 79%. The line coverage in commit d9f652f in the release-candidate/v1 branch is 65%.

Show a line coverage summary of the most impacted files.
File release-candidate/v1 d9f652f devin/1791835169-mcp... 8758a36 +/-
airbyte/mcp/cloud.py 52% 83% +31%
airbyte/_util/api_util.py 36% 68% +32%
airbyte/cloud/connectors.py 34% 75% +41%
airbyte/mcp/_datadog.py 0% 50% +50%
airbyte/mcp/_error_handling.py 0% 89% +89%
airbyte/_direct...ctors/models.py 0% 94% +94%
airbyte/mcp/_telemetry.py 0% 94% +94%
airbyte/mcp/_sso_auth.py 0% 96% +96%
airbyte/cloud/models.py 0% 97% +97%
airbyte/mcp/int...nc_status_ui.py 0% 97% +97%

Python / code-coverage/pytest-unit

The overall line coverage in commit 8758a36 in the devin/1791835169-mcp... branch is 76%. Line coverage data for the release-candidate/v1 branch is not yet available.

Show a line coverage summary of the most covered files.
File release-candidate/v1 devin/1791835169-mcp... 8758a36 +/-
airbyte/cloud/models.py — 97% —
airbyte/mcp/_sso_auth.py — 96% —
airbyte/_direct...ctors/models.py — 94% —
airbyte/cloud/client.py — 90% —
airbyte/exceptions.py — 89% —
airbyte/mcp/cloud.py — 83% —
airbyte/progress.py — 80% —
airbyte/cloud/connectors.py — 75% —
airbyte/_util/api_util.py — 68% —
airbyte/shared/...ql_processor.py — 68% —

Updated October 12, 2026 23:52 UTC

Comment thread airbyte/mcp/_tool_utils.py Outdated
Co-Authored-By: AJ Steers <aj@airbyte.io>
Comment thread airbyte/mcp/__init__.py Outdated
devin-ai-integration Bot and others added 2 commits October 12, 2026 20:52
…ly policies

Co-Authored-By: AJ Steers <aj@airbyte.io>
Comment thread airbyte/mcp/__init__.py Outdated
Co-Authored-By: AJ Steers <aj@airbyte.io>
@aaronsteers
Aaron ("AJ") Steers (aaronsteers) marked this pull request as ready for review October 12, 2026 20:54

@devin-ai-integration devin-ai-integration Bot 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.

🔍 Devin Review: 1 flag

Not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

devin-ai-integration Bot and others added 2 commits October 12, 2026 20:59
Co-Authored-By: AJ Steers <aj@airbyte.io>
@devin-ai-integration devin-ai-integration Bot changed the title fix(mcp)!: make external-access policy independent of pipeline-change policy fix(mcp)!: decouple external access, fix read-only mode, add X-MCP-Allow-Destructive-Tools Oct 12, 2026
…headers

Co-Authored-By: AJ Steers <aj@airbyte.io>
@devin-ai-integration devin-ai-integration Bot changed the title fix(mcp)!: decouple external access, fix read-only mode, add X-MCP-Allow-Destructive-Tools fix(mcp)!: decouple external access, fix read-only mode, add X-MCP-Allow-Destructive-Tools, generic unsupported-input guard Oct 12, 2026

Copilot AI 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.

🟡 Changes recommended

The destructive policy’s scope conflicts with the documented local-tool contract, and read-only documentation remains contradictory.

2 open findings

🧠 Review effort: Balanced

Comment thread airbyte/mcp/_tool_utils.py
Comment thread airbyte/mcp/__init__.py
devin-ai-integration Bot and others added 3 commits October 12, 2026 21:27
…e pyab CLI

Co-Authored-By: AJ Steers <aj@airbyte.io>
…x read-only sync docs

Co-Authored-By: AJ Steers <aj@airbyte.io>
Co-Authored-By: AJ Steers <aj@airbyte.io>
Comment thread pyproject.toml Outdated
@aaronsteers
Aaron ("AJ") Steers (aaronsteers) merged commit 8ebbf9e into release-candidate/v1 Oct 12, 2026
28 checks passed
@aaronsteers
Aaron ("AJ") Steers (aaronsteers) deleted the devin/1791835169-mcp-external-access-orthogonal branch October 12, 2026 23:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants