Skip to content

feat(mcp): map branded AIRBYTE_MCP_* env into typed build_mcp_auth - #1085

Merged
Aaron ("AJ") Steers (aaronsteers) merged 8 commits into
mainfrom
devin/1784854608-mcp-branded-typed-auth
Jul 24, 2026
Merged

feat(mcp): map branded AIRBYTE_MCP_* env into typed build_mcp_auth#1085
Aaron ("AJ") Steers (aaronsteers) merged 8 commits into
mainfrom
devin/1784854608-mcp-branded-typed-auth

Conversation

@aaronsteers

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

Copy link
Copy Markdown
Member

Summary

fastmcp-extensions 0.14.0 removed the library's env-var mapping (resolve_mcp_auth), so each MCP server now owns its own env names and hands the library typed config objects. This migrates PyAirbyte's HTTP-transport auth (airbyte/mcp/server.py) to the typed build_mcp_auth API and rebrands its auth env vars into the AIRBYTE_MCP_* namespace (AJ: "read branded env var names — unique domain of env vars is added security layer").

Names here, values in the deployment. PyAirbyte declares only the env var names and maps their values into typed configs. It embeds no provider-specific configuration values — no cloud.airbyte.com realm URLs, issuer, JWKS URI, audience, or algorithm. Those concrete values are supplied at deploy time by the deployment's own repo (the hosted Cloud MCP image in airbyte-ops-mcp), keeping infra config out of this generic library.

Behavior:

  • Auth activates from env, per path. The headless JWTVerifier activates once a signing-key source (AIRBYTE_MCP_AUTH_JWKS_URI or AIRBYTE_MCP_AUTH_JWT_PUBLIC_KEY) is set; the interactive OIDCProxy activates once AIRBYTE_MCP_OIDC_CLIENT_ID + AIRBYTE_MCP_OIDC_CLIENT_SECRET are set. With no auth env, _create_auth() returns None (unauthenticated local behavior).
  • OIDC discovery URL is required, not defaulted. When the OIDC credentials are set but AIRBYTE_MCP_OIDC_CONFIG_URL is not, _create_auth() raises a clear ValueError naming the missing var rather than falling back to a baked-in realm.
  • Env vars are rebranded (generic → AIRBYTE_MCP_*), and the MCP_AUTH_AIRBYTE_CLOUD opt-in toggle is removed. MCP_SERVER_URL stays unbranded (it's a deployment URL, not an auth var).

New _create_auth() shape:

base_url = _env_or_default(MCP_SERVER_URL_ENV, DEFAULT_MCP_SERVER_URL)

jwt = None
jwks_uri = env(JWKS_URI_ENV); public_key = env(JWT_PUBLIC_KEY_ENV)
if jwks_uri or public_key:                       # verifier activates only when configured
    jwt = JWTAuthConfig(jwks_uri=..., public_key=..., issuer=env(...), audience=env(...), algorithm=env(...), base_url=...)

oidc = None
if oidc_client_id and oidc_client_secret:
    config_url = env(OIDC_CONFIG_URL_ENV)
    if not config_url:
        raise ValueError(f"{OIDC_CLIENT_ID_ENV} and {OIDC_CLIENT_SECRET_ENV} are set but {OIDC_CONFIG_URL_ENV} is not; ...")
    oidc = OIDCAuthConfig(config_url=config_url, ..., client_storage=_resolve_client_storage(...))

return build_mcp_auth(oidc=oidc, jwt=jwt, base_url=base_url)   # -> None when both are None

PyAirbyte stays backend-agnostic. Durable OAuth-state storage for the interactive OIDCProxy is injected via a PyAirbyte-owned factory hook rather than any concrete store:

# AIRBYTE_MCP_OIDC_CLIENT_STORAGE_FACTORY="package.module:callable"
factory = pkgutil.resolve_name(spec)                              # imported only if the var is set
store = factory(encryption_source_material=oidc_client_secret)    # -> AsyncKeyValue | None
OIDCAuthConfig(..., client_storage=store)

The concrete Firestore/Fernet factory (and its infra config) ships in the deployment's own package — the hosted Cloud MCP image in airbyte-ops-mcp — keeping PyAirbyte free of infra-specific params.

Docs in airbyte/mcp/__init__.py and airbyte/mcp/http_main.py updated to the branded names and the "names here, values at deploy time" model. Bumps fastmcp-extensions to >=0.14.0. Adds tests/unit_tests/test_mcp_auth.py covering the branded names, blank-as-unset handling, per-path activation, JWT/OIDC env mapping, the missing-discovery-URL error, and storage-factory resolution/injection.

Requested by AJ Steers.

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

Summary by CodeRabbit

  • New Features

    • Added branded AIRBYTE_MCP_* settings for interactive OIDC and headless bearer-token (JWT) verification, including optional durable OIDC client-state storage.
    • Enabled HTTP transport authentication based on configured AIRBYTE_MCP_* values, while stdio remains unauthenticated.
  • Documentation

    • Updated MCP auth documentation to use the new AIRBYTE_MCP_* namespace and clarified blank-as-unset fallback to unauthenticated local behavior when unset.
    • Clarified HTTP server URL and auth redirect behavior consistency.
  • Tests

    • Added/updated unit tests for env-var handling, JWT/OIDC activation rules, and durable storage resolution/error cases.
  • Chores

    • Updated the fastmcp-extensions dependency constraint.

Migrate airbyte/mcp/server.py off the retired fastmcp_extensions.resolve_mcp_auth env mapping onto the typed build_mcp_auth API. This server now owns its branded AIRBYTE_MCP_* env names and maps them into JWTAuthConfig/OIDCAuthConfig, with a PyAirbyte-owned storage-factory hook (AIRBYTE_MCP_OIDC_CLIENT_STORAGE_FACTORY) feeding OIDCAuthConfig.client_storage. HTTP transport is now always authenticated, defaulting to the Airbyte Cloud realm. Bumps fastmcp-extensions to >=0.14.0.

Co-Authored-By: AJ Steers <aj@airbyte.io>
Copilot AI review requested due to automatic review settings July 24, 2026 01:03
@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/1784854608-mcp-branded-typed-auth' pyairbyte --help

# Install PyAirbyte from this branch for development:
pip install 'git+https://github.com/airbytehq/PyAirbyte.git@devin/1784854608-mcp-branded-typed-auth'

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.

Comment thread airbyte/mcp/server.py Dismissed
Comment thread airbyte/mcp/server.py Dismissed

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

This PR updates PyAirbyte’s MCP HTTP transport authentication to align with fastmcp-extensions>=0.14.0 by moving env-var parsing into airbyte.mcp.server and passing typed auth config objects into build_mcp_auth. It also rebrands auth-related environment variables into the AIRBYTE_MCP_* namespace and makes HTTP transport authentication default-on (Cloud realm defaults).

Changes:

  • Bump fastmcp-extensions to >=0.14.0,<1.0.0 and migrate from resolve_mcp_auth to build_mcp_auth with typed JWTAuthConfig/OIDCAuthConfig.
  • Introduce branded AIRBYTE_MCP_* env-var mapping (including blank-as-unset behavior) and optional OIDC client storage factory injection.
  • Add unit tests covering the new env mapping and auth assembly defaults/precedence.

Reviewed changes

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

Show a summary per file
File Description
uv.lock Updates locked dependency version for fastmcp-extensions and its transitive deps.
pyproject.toml Bumps fastmcp-extensions constraint and documents the migration rationale.
airbyte/mcp/server.py Implements branded env-var parsing and builds typed auth configs for build_mcp_auth.
airbyte/mcp/http_main.py Updates HTTP entrypoint documentation to match the new auth behavior and env vars.
airbyte/mcp/__init__.py Updates user-facing docs for always-on HTTP auth and rebranded env vars.
tests/unit_tests/test_mcp_auth.py Adds coverage for env mapping, defaults, signing-key precedence, OIDC activation, and storage factory injection.

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

Comment thread airbyte/mcp/__init__.py Outdated
Comment thread airbyte/mcp/server.py Outdated
Copilot AI review requested due to automatic review settings July 24, 2026 01:07
@devin-ai-integration
devin-ai-integration Bot marked this pull request as ready for review July 24, 2026 01:08
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

HTTP MCP authentication is now configured through server-owned AIRBYTE_MCP_* variables. The server directly builds JWT and optional OIDC authentication, handles blank environment values consistently, updates HTTP transport documentation, raises the fastmcp-extensions requirement, and adds comprehensive unit coverage.

Changes

MCP authentication configuration

Layer / File(s) Summary
Authentication contracts and dependency wiring
airbyte/mcp/server.py, pyproject.toml
Defines branded authentication variables and typed configuration inputs, adds the shared default server URL, and requires fastmcp-extensions 0.14 or newer.
Authentication assembly and validation
airbyte/mcp/server.py, tests/unit_tests/test_mcp_auth.py
Normalizes environment values, constructs JWT/OIDC authentication, resolves optional durable OIDC storage, validates configuration, and tests the supported authentication paths.
HTTP transport contract
airbyte/mcp/__init__.py, airbyte/mcp/http_main.py, airbyte/mcp/server.py
Documents configured bearer-token and OIDC authentication, aligns blank server URL handling with authentication setup, describes unauthenticated local fallback, and updates the no-auth startup warning.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Environment
  participant server._create_auth
  participant build_mcp_auth
  participant JWTVerifier
  participant OIDCProxy
  Environment->>server._create_auth: AIRBYTE_MCP_* values
  server._create_auth->>build_mcp_auth: JWTAuthConfig and OIDCAuthConfig
  build_mcp_auth->>JWTVerifier: Verify bearer tokens
  build_mcp_auth->>OIDCProxy: Configure interactive OIDC
Loading

Possibly related PRs

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: branded MCP env vars mapped into the typed build_mcp_auth flow.
Docstring Coverage ✅ Passed Docstring coverage is 88.00% which is sufficient. The required threshold is 80.00%.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch devin/1784854608-mcp-branded-typed-auth

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 coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@airbyte/mcp/__init__.py`:
- Around line 204-205: Update the defaults description near the Airbyte Cloud
realm note to state that the verifier defaults to Cloud’s JWKS, issuer,
audience, and algorithm, while AIRBYTE_MCP_AUTH_JWT_PUBLIC_KEY has no Cloud
default. Clarify that the Cloud JWKS fallback is used only when neither
key-source override is configured, without implying all headless variables are
populated.
- Line 203: Clarify the HTTP guide namespace wording in airbyte/mcp/__init__.py
at lines 203-203 by limiting the AIRBYTE_MCP_* statement to transport-auth names
or explicitly identifying MCP_SERVER_URL as the exception. In
airbyte/mcp/http_main.py at lines 12-16, retain MCP_SERVER_URL as the base-URL
variable and align the surrounding wording with that exception.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f4379817-9114-43f5-8c61-281ca1c76d7c

📥 Commits

Reviewing files that changed from the base of the PR and between dbe4d48 and 57e52a1.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • airbyte/mcp/__init__.py
  • airbyte/mcp/http_main.py
  • airbyte/mcp/server.py
  • pyproject.toml
  • tests/unit_tests/test_mcp_auth.py

Comment thread airbyte/mcp/__init__.py Outdated
Comment thread airbyte/mcp/__init__.py Outdated
@devin-ai-integration devin-ai-integration Bot changed the title refactor(mcp): map branded AIRBYTE_MCP_* env into typed build_mcp_auth feat(mcp): map branded AIRBYTE_MCP_* env into typed build_mcp_auth Jul 24, 2026

@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 2 additional findings.

Open in Devin Review

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

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 5 out of 6 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (2)

airbyte/mcp/server.py:229

  • pkgutil.resolve_name() will raise (e.g., ImportError, AttributeError, ValueError) if AIRBYTE_MCP_OIDC_CLIENT_STORAGE_FACTORY is malformed or points at a missing symbol, which will currently crash module import / server startup with a low-context traceback. Consider catching exceptions here and raising a clearer error mentioning the env var name and expected format.
    factory_spec = os.getenv(OIDC_CLIENT_STORAGE_FACTORY_ENV, "").strip()
    if not factory_spec:
        return None
    factory: _ClientStorageFactory = pkgutil.resolve_name(factory_spec)
    return factory(encryption_source_material=encryption_source_material)

airbyte/mcp/server.py:232

  • _create_auth() now always builds a JWTAuthConfig (with Cloud defaults) and therefore should always return an AuthProvider. Keeping | None in the return type is misleading for callers and for static typing (and contradicts the docstring/tests that assert a verifier is returned by default).
def _create_auth() -> AuthProvider | None:

Comment thread airbyte/mcp/server.py
Copilot AI review requested due to automatic review settings July 24, 2026 01:10
@devin-ai-integration

Copy link
Copy Markdown
Contributor

Thanks @copilot. Addressing the two low-confidence findings from the overview:

☑️ pkgutil.resolve_name crash on a bad factory spec — fixed in 37b1424. Good call. _resolve_client_storage now wraps the resolve in a targeted except (ImportError, AttributeError, ValueError) and re-raises a ValueError that names AIRBYTE_MCP_OIDC_CLIENT_STORAGE_FACTORY and the expected package.module:callable format (via raise ... from), so a misconfigured deployment fails with a clear message instead of a bare traceback. Added parametrized tests for both the malformed-reference and missing-symbol cases.

🚫 _create_auth() -> AuthProvider | None — leaving as-is. The | None isn't dead: it mirrors fastmcp_extensions.build_mcp_auth, which is itself typed -> AuthProvider | None, and _create_auth returns that value directly. While the current env-mapping always yields a JWT config (so at runtime a provider is produced today), narrowing the annotation would require an unsupported assertion and would couple this signature to an internal invariant of the library rather than its declared contract. Keeping it aligned with build_mcp_auth is the more robust typing.


Devin session

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 5 out of 6 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

airbyte/mcp/server.py:180

  • The storage-factory hook is described as optional/nullable (and _resolve_client_storage() returns AsyncKeyValue | None), but _ClientStorageFactory.__call__ is typed as always returning AsyncKeyValue. This makes the typing contract inconsistent and prevents factories from intentionally returning None to keep the in-memory default.
class _ClientStorageFactory(Protocol):
    """Callable that builds a durable `OIDCProxy` OAuth-state backend.

    A deployment names its factory via
    `AIRBYTE_MCP_OIDC_CLIENT_STORAGE_FACTORY` (`"package.module:callable"`). The
    callable receives the OIDC client secret as `encryption_source_material` so
    it can derive an at-rest encryption key, and returns an `AsyncKeyValue`
    store. Keeping the concrete backend (Firestore, Redis, ...) behind this hook
    lets PyAirbyte stay generic — the infrastructure-specific factory ships in

Comment thread airbyte/mcp/server.py
Copilot AI review requested due to automatic review settings July 24, 2026 01:14

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 5 out of 6 changed files in this pull request and generated 1 comment.

Comment thread airbyte/mcp/server.py
Co-Authored-By: AJ Steers <aj@airbyte.io>
Copilot AI review requested due to automatic review settings July 24, 2026 01:18

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 5 out of 6 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

airbyte/mcp/server.py:242

  • _resolve_client_storage() wraps failures from pkgutil.resolve_name(), but if the resolved object is not callable or doesn't accept the required encryption_source_material=... kwarg, the TypeError from factory(...) will bubble up without naming the env var or expected callable signature. Since this is operator-facing configuration, it’s better to re-raise a clear ValueError in that case as well.
    return factory(encryption_source_material=encryption_source_material)

@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 eacae28 in the devin/1784854608-mcp... 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/1784854608-mcp... eacae28 +/-
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 eacae28 in the devin/1784854608-mcp... 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/1784854608-mcp... eacae28 +/-
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 eacae28 in the devin/1784854608-mcp... 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/1784854608-mcp... eacae28 +/-
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 05:36 UTC

Comment thread airbyte/mcp/server.py Outdated
Copilot AI review requested due to automatic review settings July 24, 2026 05:02

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 5 out of 6 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

airbyte/mcp/server.py:214

  • _resolve_client_storage() wraps errors from pkgutil.resolve_name, but if the resolved object is not callable or has an incompatible signature, calling it will raise TypeError with a less actionable traceback. Since this is an operator-facing env var, consider catching TypeError and re-raising a ValueError that names the env var and expected callable signature.
    return factory(encryption_source_material=encryption_source_material)

Comment thread airbyte/mcp/server.py Outdated
Comment thread airbyte/mcp/http_main.py
…h warning

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

@coderabbitai coderabbitai 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
airbyte/mcp/server.py (1)

251-271: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Fail closed on partial OIDC env configuration?

_create_auth() rejects missing AIRBYTE_MCP_OIDC_CONFIG_URL, but if only AIRBYTE_MCP_OIDC_CLIENT_ID or AIRBYTE_MCP_OIDC_CLIENT_SECRET is set, OIDC stays unset and HTTP can still start unauthenticated. Since docs say both OIDC values are required, wdyt about raising a ValueError for that partial-credential case so a typo/rotator leak is not silently ignored?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@airbyte/mcp/server.py` around lines 251 - 271, Update _create_auth so it
raises ValueError when exactly one of OIDC_CLIENT_ID_ENV or
OIDC_CLIENT_SECRET_ENV is configured, rather than leaving oidc unset and
starting unauthenticated. Preserve the existing configuration-URL validation and
OIDCAuthConfig construction when both credentials are present.
🧹 Nitpick comments (1)
airbyte/mcp/http_main.py (1)

104-105: 🩺 Stability & Availability | 🔵 Trivial

Startup warning for unauthenticated HTTP removed — worth an info log instead?

Unauthenticated-by-default is now an intentional fallback, so a warning no longer fits — but dropping all visibility means an operator has no easy way to confirm from logs whether a deployment is actually running with auth configured. wdyt about keeping a single logger.info line stating whether auth is enabled (and which mode), so this is still discoverable without digging through env vars?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@airbyte/mcp/http_main.py` around lines 104 - 105, Update the HTTP startup
logging around logger.info to retain one informational message describing
whether authentication is enabled and, when enabled, which authentication mode
is configured; preserve the intentional unauthenticated fallback without
emitting a warning.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@airbyte/mcp/server.py`:
- Around line 251-271: Update _create_auth so it raises ValueError when exactly
one of OIDC_CLIENT_ID_ENV or OIDC_CLIENT_SECRET_ENV is configured, rather than
leaving oidc unset and starting unauthenticated. Preserve the existing
configuration-URL validation and OIDCAuthConfig construction when both
credentials are present.

---

Nitpick comments:
In `@airbyte/mcp/http_main.py`:
- Around line 104-105: Update the HTTP startup logging around logger.info to
retain one informational message describing whether authentication is enabled
and, when enabled, which authentication mode is configured; preserve the
intentional unauthenticated fallback without emitting a warning.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 17be8360-c2f5-4c2a-960c-78c5ffab593c

📥 Commits

Reviewing files that changed from the base of the PR and between 8228d92 and fe6a962.

📒 Files selected for processing (4)
  • airbyte/mcp/__init__.py
  • airbyte/mcp/http_main.py
  • airbyte/mcp/server.py
  • tests/unit_tests/test_mcp_auth.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • airbyte/mcp/init.py

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 5 out of 6 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

airbyte/mcp/server.py:216

  • _resolve_client_storage() wraps resolve/import failures into a clear ValueError, but the actual factory invocation can still raise a raw TypeError (e.g. resolved symbol is not callable, or doesn’t accept the encryption_source_material kwarg). Since this is an operator-facing env var, it’s better to re-raise a ValueError naming AIRBYTE_MCP_OIDC_CLIENT_STORAGE_FACTORY and the expected callable signature to avoid an opaque startup traceback.
    return factory(encryption_source_material=encryption_source_material)

Copilot AI review requested due to automatic review settings July 24, 2026 05:12
@devin-ai-integration

Copy link
Copy Markdown
Contributor

Addressing CodeRabbit's two out-of-diff findings (they couldn't post inline) — both fixed in eacae28:

  1. Fail closed on partial OIDC config (server.py, Major). A lone AIRBYTE_MCP_OIDC_CLIENT_ID or AIRBYTE_MCP_OIDC_CLIENT_SECRET now raises a ValueError naming the missing var, instead of silently leaving OIDC unset and starting unauthenticated. This matches the documented "both required" contract and surfaces a typo/rotator leak loudly. Added test_create_auth_partial_oidc_id_only_raises / ..._secret_only_raises and replaced the old permissive test.

  2. Auth-mode log visibility (http_main.py, nitpick). Kept the unauthenticated warning (Copilot separately flagged that silently starting unauthenticated is easy to do by accident — a warning is more visible than info for that risky case) and added an else branch logging a single logger.info with the active auth provider type when auth is enabled, so an operator can confirm from logs either way.

Ruff + pyrefly clean; 21 unit tests pass.


Devin session

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 5 out of 6 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

airbyte/mcp/server.py:216

  • _resolve_client_storage() wraps errors from pkgutil.resolve_name(), but if the resolved symbol is not callable or has an incompatible signature, the subsequent factory(...) call will raise a raw TypeError (operator-facing traceback) rather than a clear ValueError naming the env var and required parameter. Since this is configured via an env var, it’s worth wrapping call-time TypeError as well.
        )
        raise ValueError(msg) from exc
    return factory(encryption_source_material=encryption_source_material)

@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown

Prerelease Build Started

Building and publishing prerelease package from this PR...
Check job output.
Prerelease Build/Publish Failed

The prerelease encountered an error.
Check publish workflow output for details.

You can still install directly from this PR branch:

pip install 'git+https://github.com/airbytehq/PyAirbyte.git@devin/1784854608-mcp-branded-typed-auth'

@aaronsteers
Aaron ("AJ") Steers (aaronsteers) merged commit 41a04e2 into main Jul 24, 2026
22 checks passed
@aaronsteers
Aaron ("AJ") Steers (aaronsteers) deleted the devin/1784854608-mcp-branded-typed-auth branch July 24, 2026 06:04
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.

3 participants