Skip to content

feat(mcp): Add HTTP header bearer token authentication support#914

Closed
devin-ai-integration[bot] wants to merge 16 commits into
devin/1763010134-bearer-token-authfrom
devin/1765845063-http-header-bearer-token
Closed

feat(mcp): Add HTTP header bearer token authentication support#914
devin-ai-integration[bot] wants to merge 16 commits into
devin/1763010134-bearer-token-authfrom
devin/1765845063-http-header-bearer-token

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Dec 16, 2025

Copy link
Copy Markdown
Contributor

This PR targets the following PR:


Summary

Enable PyAirbyte MCP tools to authenticate via Authorization header when running over HTTP transport. This allows a single shared MCP server to handle requests from multiple users with different bearer tokens, rather than requiring a subprocess per request.

Changes:

  • Add get_bearer_token_from_headers() utility in airbyte/mcp/_util.py that extracts bearer tokens from HTTP Authorization headers using fastmcp's get_http_headers()
  • Update resolve_cloud_bearer_token() in airbyte/cloud/auth.py to check HTTP headers first before falling back to environment variables
  • Add noqa: SLF001 comments in airbyte/cloud/connectors.py for private member access (lint fixes)
  • Add noqa: PLR0904 comment on CloudWorkspace class (lint fix for too many public methods)

Token resolution order:

  1. Explicit input_value parameter
  2. HTTP Authorization: Bearer <token> header (when running as MCP HTTP server)
  3. AIRBYTE_CLOUD_BEARER_TOKEN environment variable

Review & Testing Checklist for Human

  • Verify import side effects are acceptable: airbyte.cloud.auth now imports from airbyte.mcp._util at module load time, which triggers fastmcp imports. Verify this doesn't break code that imports auth.py but doesn't use MCP.
  • Review resolution order change: The original resolve_cloud_bearer_token() passed input_value as default to try_get_secret(). Now it checks input_value first explicitly and passes default=None to the env var fallback - verify this doesn't break existing callers.
  • Verify HTTP transport works: Start MCP HTTP server, send request with Authorization: Bearer <token> header, verify API calls use that token
  • Verify stdio transport still works: Confirm env var fallback works when not running over HTTP

Recommended test plan:

# Start MCP HTTP server
poetry run poe mcp-serve-http

# Test with bearer token header (in another terminal)
curl -X POST http://127.0.0.1:8000/... \
  -H "Authorization: Bearer <your-token>" \
  -H "Content-Type: application/json" \
  -d '{"tool": "list_workspaces", "args": {}}'

Notes

Updates since last revision

  • Removed unrelated CI type fixes per user request (changes to api_util.py, cloud_ops.py, and .github/ workflow files)
  • PR now contains only spec-related changes and lint fixes (noqa comments)
  • Base PR feat: Add bearer token authentication support #866 is expected to handle any remaining CI type issues

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ility (#912)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Enable PyAirbyte MCP tools to authenticate via Authorization header when
running over HTTP transport. This allows a single shared MCP server to
handle requests from multiple users with different bearer tokens.

Changes:
- Add get_bearer_token_from_headers() utility in airbyte/mcp/_util.py
- Update resolve_cloud_bearer_token() to check HTTP headers first

Resolution order for bearer token:
1. Explicit input_value parameter
2. HTTP Authorization header (when running as MCP HTTP server)
3. AIRBYTE_CLOUD_BEARER_TOKEN environment variable

Co-Authored-By: aldo.gonzalez@airbyte.io <aldo.gonzalez@airbyte.io>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author
Original prompt from aldo.gonzalez@airbyte.io
Received message in Slack channel #ask-devin-ai:

@Devin can you stack an PR on the top of <https://github.com/airbytehq/PyAirbyte/pull/866> for the below spec?
```## PyAirbyte MCP: HTTP Header Bearer Token Authentication Spec

### Overview

Enable PyAirbyte MCP tools to authenticate via `Authorization` header when running over HTTP transport, allowing a single shared MCP server to handle requests from multiple users with different bearer tokens.

### Current Behavior

Tools read bearer token from environment variable only:

```python
# airbyte/cloud/auth.py
def resolve_cloud_bearer_token(...) -&gt; SecretString | None:
    return try_get_secret(constants.CLOUD_BEARER_TOKEN_ENV_VAR, default=input_value)

Required Changes

1. Add HTTP header extraction utility

File: airbyte/mcp/_util.py (or new file)

from fastmcp.server.dependencies import get_http_headers

def get_bearer_token_from_headers() -&gt; str | None:
    """Extract bearer token from HTTP Authorization header.
    
    Returns None if not running over HTTP transport or no header present.
    """
    try:
        headers = get_http_headers()
        auth_header = headers.get("authorization", "")
        if auth_header.startswith("Bearer "):
            return auth_header[7:]  # Strip "Bearer " prefix
        return None
    except Exception:
        # Not running over HTTP transport
        return None

2. Update resolve_cloud_bearer_token to check headers first

File: airbyte/cloud/auth.py

def resolve_cloud_bearer_token(
    input_value: str | SecretString | None = None,
    /,
) -&gt; SecretString | None:
    """Get the Airbyte Cloud bearer token.
    
    Resolution order:
    1. Explicit input_value parameter
    2. HTTP Authorization header (when running as MCP HTTP server)
    3. AIRBYTE_CLOUD_BEARER_TOKEN environment variable
    """
    if input_value:
        return SecretString(input_value)
    
    # Try HTTP header first (for MCP HTTP tran... (1427 chars truncated...)

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 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 and CI monitoring

@github-actions

Copy link
Copy Markdown

👋 Greetings, Airbyte Team Member!

Here are some helpful tips and reminders for your convenience.

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/1765845063-http-header-bearer-token' pyairbyte --help

# Install PyAirbyte from this branch for development:
pip install 'git+https://github.com/airbytehq/PyAirbyte.git@devin/1765845063-http-header-bearer-token'

Helpful Resources

PR Slash Commands

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

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

Community Support

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

📝 Edit this welcome message.

Co-Authored-By: aldo.gonzalez@airbyte.io <aldo.gonzalez@airbyte.io>
@github-actions

github-actions Bot commented Dec 16, 2025

Copy link
Copy Markdown

PyTest Results (Fast Tests Only, No Creds)

348 tests  ±0   348 ✅ ±0   5m 48s ⏱️ +10s
  1 suites ±0     0 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 98d6d26. ± Comparison against base commit 4f05142.

♻️ This comment has been updated with latest results.

- Move fastmcp.server.dependencies.get_http_headers import to top-level in _util.py
- Move airbyte.mcp._util.get_bearer_token_from_headers import to top-level in auth.py
- Remove noqa: PLC0415 comments as inline imports are no longer used

Co-Authored-By: aldo.gonzalez@airbyte.io <aldo.gonzalez@airbyte.io>
Comment thread airbyte/mcp/_util.py
…th' into devin/1765845063-http-header-bearer-token
@aldogonzalez8

Copy link
Copy Markdown
Contributor

Devin CI is failing

devin-ai-integration Bot and others added 2 commits December 16, 2025 00:57
… all API call sites

Co-Authored-By: aldo.gonzalez@airbyte.io <aldo.gonzalez@airbyte.io>

- name: Compute prerelease version
id: version
run: |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 [actionlint] reported by reviewdog 🐶
shellcheck reported issue in this script: SC2086:info:7:39: Double quote to prevent globbing and word splitting [shellcheck]

Comment thread .github/workflows/pypi_publish.yml Outdated
- uses: hynek/build-and-inspect-python-package@efb823f52190ad02594531168b7a2d5790e66516 # v2.14.0
- name: Prepare version override
id: version
run: |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 [actionlint] reported by reviewdog 🐶
shellcheck reported issue in this script: SC2086:info:1:51: Double quote to prevent globbing and word splitting [shellcheck]

Comment thread .github/workflows/pypi_publish.yml Outdated
- uses: hynek/build-and-inspect-python-package@efb823f52190ad02594531168b7a2d5790e66516 # v2.14.0
- name: Prepare version override
id: version
run: |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 [actionlint] reported by reviewdog 🐶
shellcheck reported issue in this script: SC2086:info:2:61: Double quote to prevent globbing and word splitting [shellcheck]

devin-ai-integration Bot and others added 3 commits December 16, 2025 01:07
Co-Authored-By: aldo.gonzalez@airbyte.io <aldo.gonzalez@airbyte.io>
… favor of PR branch

Co-Authored-By: aldo.gonzalez@airbyte.io <aldo.gonzalez@airbyte.io>
Co-Authored-By: aldo.gonzalez@airbyte.io <aldo.gonzalez@airbyte.io>
@aldogonzalez8 Aldo Gonzalez (aldogonzalez8) changed the title feat(mcp): Add HTTP header bearer token authentication support (do not merge) feat(mcp): Add HTTP header bearer token authentication support Dec 16, 2025
devin-ai-integration Bot and others added 2 commits December 16, 2025 01:38
…lint fixes

Co-Authored-By: aldo.gonzalez@airbyte.io <aldo.gonzalez@airbyte.io>
Co-Authored-By: aldo.gonzalez@airbyte.io <aldo.gonzalez@airbyte.io>
@github-actions

Copy link
Copy Markdown

PyTest Results (Full)

416 tests  ±0   391 ✅ ±0   23m 23s ⏱️ + 1m 39s
  1 suites ±0    17 💤 ±0 
  1 files   ±0     8 ❌ ±0 

For more details on these failures, see this check.

Results for commit 98d6d26. ± Comparison against base commit 4f05142.

Comment thread airbyte/cloud/auth.py
"""Authentication-related constants and utilities for the Airbyte Cloud."""

from airbyte import constants
from airbyte.mcp._util import get_bearer_token_from_headers

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Devin, Can you create a follow-on issue to refactor slightly...

Ideally nothing outside the MCP module would import from the MCP module. That said, this is expedient and doesn't seem to create circular dependencies or side effects (that I can see). So I'm inclined to merge and create follow-on issue for refactoring.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Created follow-on issue: #915

The issue proposes moving get_bearer_token_from_headers() to a shared utility location (like airbyte/_util/http_auth.py) so the MCP module can import from it rather than the other way around.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approving with one post-merge update requested: https://github.com/airbytehq/PyAirbyte/pull/914/changes#r2625121278

devin-ai-integration Bot added a commit that referenced this pull request Dec 17, 2025
…on support

This commit consolidates authentication handling for Airbyte Cloud API:

- Add CloudCredentials dataclass in airbyte/cloud/credentials.py that
  encapsulates auth configuration (client_id/secret or bearer_token)
- Add bearer token authentication support to api_util functions
- Add resolve_cloud_credentials() in MCP _util.py for multi-source
  credential resolution (explicit params -> HTTP headers -> env vars)
- Add HTTP header extraction helpers for MCP HTTP/SSE transport
- Update CloudWorkspace to support bearer token authentication
- Export CloudCredentials from airbyte.cloud module

This replaces PRs #866, #867, and #914 with a unified implementation.

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

Copy link
Copy Markdown
Member

Replaced by #916

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