Skip to content

fix(mcp): request openid scope on interactive OIDC so downstream APIs accept the token - #1091

Merged
Aaron ("AJ") Steers (aaronsteers) merged 4 commits into
mainfrom
devin/1784931658-cloud-mcp-oidc-openid-scope
Jul 24, 2026
Merged

fix(mcp): request openid scope on interactive OIDC so downstream APIs accept the token#1091
Aaron ("AJ") Steers (aaronsteers) merged 4 commits into
mainfrom
devin/1784931658-cloud-mcp-oidc-openid-scope

Conversation

@aaronsteers

@aaronsteers Aaron ("AJ") Steers (aaronsteers) commented Jul 24, 2026

Copy link
Copy Markdown
Member

Summary

AJ asked for this fix (the cloud-mcp half; the ops-mcp half is airbytehq/airbyte-ops-mcp#1170). The interactive OIDC MCP server (airbyte airbyte-mcp-http, deployed as cloud-mcp) authenticated the transport but every downstream Airbyte Cloud API call returned 401. Root cause: the upstream token minted for interactive clients carried scope=email profile — an identity-only token with no openid — which Airbyte Cloud rejects. The MCP flow dropped openid because _create_auth() left OIDCAuthConfig.required_scopes unset, so OIDCProxy advertised no valid scopes and clients could not request openid (DCR rejected it). The fix is server-side.

  OIDC_SCOPES_ENV = "AIRBYTE_MCP_OIDC_SCOPES"     # override for non-standard realms
  DEFAULT_OIDC_SCOPES = "openid email profile"

  OIDCAuthConfig(
      ...,
+     required_scopes=_env_or_default(OIDC_SCOPES_ENV, DEFAULT_OIDC_SCOPES).split(),
  )

The proxy now (1) advertises openid email profile via DCR/.well-known, (2) requests them on the upstream /authorize, and (3) enforces them on the verified token. The default is the provider-neutral standard OIDC set (this is the generic library); a deployment can override via AIRBYTE_MCP_OIDC_SCOPES. Headless bearer/JWT behavior is untouched.

Testing

The equivalent change was proven end-to-end locally on the sibling ops-mcp server (same FastMCP OIDCProxy wiring): the full MCP client → proxy → Keycloak → callback → token-swap flow yielded a forwarded token with scope=openid email profile and read-only Cloud tools returning 200 (was 401). Controlled webapp-token comparison isolated openid as the single decisive variable (openid present → 200, absent → 401, with aud=account unchanged in both).

Unit tests added in tests/unit_tests/test_mcp_auth.py assert the default required_scopes == ["openid","email","profile"] and the env override. ruff check, ruff format --check, pyrefly check, and pytest tests/unit_tests/test_mcp_auth.py (22 passed) all pass locally.

Link to Devin session: https://app.devin.ai/sessions/a5b9501ef92c412aad0408b7c74ef9c8
Requested by: Aaron ("AJ") Steers (@aaronsteers)

Summary by CodeRabbit

  • New Features
    • Added configurable interactive OIDC authorization scopes via the AIRBYTE_MCP_OIDC_SCOPES environment variable.
    • Defaults to openid, email, and profile.
    • Custom scope settings are enforced for interactive OIDC authorization, with openid always guaranteed (even if omitted in the override).
  • Tests
    • Extended unit tests to cover default required scopes, environment override behavior, and ensuring openid is always included.
    • Improved test environment isolation so scope overrides don’t leak between tests.

Important

Auto-merge enabled.

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

… accept the token

Co-Authored-By: AJ Steers <aj@airbyte.io>
Copilot AI review requested due to automatic review settings July 24, 2026 22:31
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • 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/1784931658-cloud-mcp-oidc-openid-scope' pyairbyte --help

# Install PyAirbyte from this branch for development:
pip install 'git+https://github.com/airbytehq/PyAirbyte.git@devin/1784931658-cloud-mcp-oidc-openid-scope'

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.

Pull request overview

Updates the interactive OIDC transport-auth configuration for the airbyte-mcp-http server so that it requests and enforces standard OIDC scopes (including openid), ensuring downstream Airbyte Cloud API calls accept the minted token.

Changes:

  • Add configurable required_scopes for interactive OIDC via AIRBYTE_MCP_OIDC_SCOPES, defaulting to openid email profile.
  • Wire the new scopes into the OIDCAuthConfig created by _create_auth().
  • Add unit tests covering the default scopes and the env-var override behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
airbyte/mcp/server.py Introduces OIDC_SCOPES_ENV/DEFAULT_OIDC_SCOPES and passes required_scopes into OIDCAuthConfig during auth provider construction.
tests/unit_tests/test_mcp_auth.py Adds assertions that default OIDC scopes include openid, and verifies AIRBYTE_MCP_OIDC_SCOPES overrides are honored.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The MCP server adds environment-driven OIDC scopes, defaults to openid email profile, preserves order while removing duplicates, and always places openid first. Unit tests cover defaults, overrides, cleanup, and forced inclusion.

Changes

OIDC scope configuration

Layer / File(s) Summary
OIDC scope configuration and auth assembly
airbyte/mcp/server.py
Adds AIRBYTE_MCP_OIDC_SCOPES, resolves unique ordered scopes with openid first, and assigns them to OIDCAuthConfig.required_scopes.
OIDC scope test coverage
tests/unit_tests/test_mcp_auth.py
Clears scope overrides between tests and verifies default, customized, and openid-enforced scope behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Environment
  participant _resolve_oidc_scopes
  participant _create_auth
  participant OIDCAuthConfig
  Environment->>_resolve_oidc_scopes: provide AIRBYTE_MCP_OIDC_SCOPES
  _resolve_oidc_scopes->>_create_auth: return ordered required scopes
  _create_auth->>OIDCAuthConfig: set required_scopes
Loading

Possibly related PRs

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding openid to interactive OIDC scope requests so downstream APIs accept the token.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch devin/1784931658-cloud-mcp-oidc-openid-scope

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

coderabbitai[bot]

This comment was marked as resolved.

Copilot AI review requested due to automatic review settings July 24, 2026 22:35

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@github-code-quality

github-code-quality Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: Python

Python / code-coverage/pytest-fast

The overall coverage in commit 4ca28e5 in the devin/1784931658-clo... branch is 68%. The coverage in commit d9f652f in the main branch is 65%.

Show a code coverage summary of the most impacted files.
File main d9f652f devin/1784931658-clo... 4ca28e5 +/-
airbyte/mcp/_tool_utils.py 72% 84% +12%
airbyte/mcp/registry.py 53% 70% +17%
airbyte/mcp/server.py 69% 88% +19%
airbyte/mcp/_arg_resolvers.py 13% 44% +31%
airbyte/mcp/int...c_history_ui.py 0% 36% +36%
airbyte/mcp/int...hared_models.py 0% 81% +81%
airbyte/cloud/models.py 0% 91% +91%
airbyte/mcp/int..._registry_ui.py 0% 92% +92%
airbyte/mcp/int...nc_status_ui.py 0% 97% +97%
airbyte/mcp/_guards.py 0% 100% +100%

Python / code-coverage/pytest-no-creds

The overall coverage in commit 4ca28e5 in the devin/1784931658-clo... branch is 68%. The coverage in commit d9f652f in the main branch is 65%.

Show a code coverage summary of the most impacted files.
File main d9f652f devin/1784931658-clo... 4ca28e5 +/-
airbyte/mcp/_tool_utils.py 72% 84% +12%
airbyte/mcp/registry.py 53% 70% +17%
airbyte/mcp/server.py 69% 88% +19%
airbyte/mcp/_arg_resolvers.py 13% 44% +31%
airbyte/mcp/int...c_history_ui.py 0% 36% +36%
airbyte/mcp/int...hared_models.py 0% 81% +81%
airbyte/cloud/models.py 0% 91% +91%
airbyte/mcp/int..._registry_ui.py 0% 92% +92%
airbyte/mcp/int...nc_status_ui.py 0% 97% +97%
airbyte/mcp/_guards.py 0% 100% +100%

Python / code-coverage/pytest

The overall coverage in commit 4ca28e5 in the devin/1784931658-clo... branch is 73%. The coverage in commit d9f652f in the main branch is 71%.

Show a code coverage summary of the most impacted files.
File main d9f652f devin/1784931658-clo... 4ca28e5 +/-
airbyte/mcp/_tool_utils.py 72% 84% +12%
airbyte/mcp/registry.py 53% 70% +17%
airbyte/mcp/server.py 69% 88% +19%
airbyte/mcp/_arg_resolvers.py 13% 44% +31%
airbyte/mcp/int...c_history_ui.py 0% 36% +36%
airbyte/mcp/int...hared_models.py 0% 81% +81%
airbyte/mcp/int..._registry_ui.py 0% 92% +92%
airbyte/cloud/models.py 0% 93% +93%
airbyte/mcp/int...nc_status_ui.py 0% 97% +97%
airbyte/mcp/_guards.py 0% 100% +100%

Updated July 24, 2026 23:12 UTC

@aaronsteers
Aaron ("AJ") Steers (aaronsteers) marked this pull request as ready for review July 24, 2026 22:42
Comment thread airbyte/mcp/server.py Outdated

@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: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

…IDC_SCOPES

Co-Authored-By: AJ Steers <aj@airbyte.io>
Copilot AI review requested due to automatic review settings July 24, 2026 22:44

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

airbyte/mcp/server.py:205

  • This docstring and the default resolution still reference AIRBYTE_CLOUD_REQUIRED_OIDC_SCOPES; if the constant is renamed to DEFAULT_OIDC_SCOPES, update the reference here as well so the docs match the behavior.
    configured = _env_or_default(OIDC_SCOPES_ENV, AIRBYTE_CLOUD_REQUIRED_OIDC_SCOPES).split()

Comment thread airbyte/mcp/server.py Outdated
… email profile

Co-Authored-By: AJ Steers <aj@airbyte.io>
Copilot AI review requested due to automatic review settings July 24, 2026 22:49

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (2)

airbyte/mcp/server.py:149

  • The PR description says interactive OIDC scopes are configurable via an AIRBYTE_MCP_OIDC_SCOPES env var, but the code currently hard-codes AIRBYTE_CLOUD_REQUIRED_OIDC_SCOPES and does not expose an override. Also, the constant name reads Cloud-specific even though this module describes itself as a generic library mapping env vars into auth config.
# Upstream authorize scopes requested for the interactive OIDC flow, also
# advertised to clients via DCR/`.well-known` and enforced on the verified
# upstream token. `openid` is required for OIDC: without it the IdP may issue an
# identity-only token that downstream APIs reject.
AIRBYTE_CLOUD_REQUIRED_OIDC_SCOPES: str = "openid email profile"

airbyte/mcp/server.py:287

  • required_scopes is currently derived from a hard-coded string. If scopes are intended to be configurable (per PR description), read them from AIRBYTE_MCP_OIDC_SCOPES with a default, and enforce inclusion of openid so a misconfigured override can't silently produce identity-only tokens again.
            base_url=base_url,
            required_scopes=AIRBYTE_CLOUD_REQUIRED_OIDC_SCOPES.split(),

Comment thread tests/unit_tests/test_mcp_auth.py
@aaronsteers
Aaron ("AJ") Steers (aaronsteers) merged commit 6f539a8 into main Jul 24, 2026
23 checks passed
@aaronsteers
Aaron ("AJ") Steers (aaronsteers) deleted the devin/1784931658-cloud-mcp-oidc-openid-scope branch July 24, 2026 23:13
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