feat(mcp): accept separate Client-Id/Client-Secret credential headers - #1086
Conversation
…p-extensions 0.15.0 Co-Authored-By: AJ Steers <aj@airbyte.io>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
👋 Greetings, Airbyte Team Member!Here are some helpful tips and reminders for your convenience. 💡 Show Tips and TricksTesting This PyAirbyte VersionYou 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/1784872732-pyairbyte-fastmcp-ext-0.15' pyairbyte --help
# Install PyAirbyte from this branch for development:
pip install 'git+https://github.com/airbytehq/PyAirbyte.git@devin/1784872732-pyairbyte-fastmcp-ext-0.15'PR Slash CommandsAirbyte Maintainers can execute the following slash commands on your PR:
📚 Show Repo GuidanceHelpful ResourcesCommunity SupportQuestions? Join the #pyairbyte channel in our Slack workspace. |
There was a problem hiding this comment.
Pull request overview
Updates the MCP server’s optional client-credentials transport auth by bumping fastmcp-extensions to a version that accepts client_id/client_secret via either HTTP Basic or separate Client-Id / Client-Secret headers, and aligns local documentation accordingly.
Changes:
- Bump
fastmcp-extensionsdependency floor to>=0.15.0,<1.0.0and refresh the lockfile. - Update MCP module docs/docstrings to document the new
Client-Id/Client-Secretheader form alongside HTTP Basic.
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| uv.lock | Locks fastmcp-extensions to 0.15.0 and updates artifact metadata. |
| pyproject.toml | Raises the minimum supported fastmcp-extensions version and documents the new header-based credential option. |
| airbyte/mcp/_client_credentials.py | Updates module and function docstrings to reflect that credentials can be provided via Basic or separate headers. |
| airbyte/mcp/init.py | Expands public documentation to include the Client-Id / Client-Secret header option for opt-in static client credentials. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ### Opt-in: static client credentials | ||
|
|
||
| The headless bearer path assumes the client can re-mint a token every ~15 min. | ||
| An agent that can only set a **static** `Authorization` value (no refresh hook) | ||
| can't do that. For this case the server can optionally accept the long-lived | ||
| `client_id` / `client_secret` directly on the inbound request, via standard HTTP | ||
| Basic (the same credential encoding OAuth's `client_secret_basic` uses): | ||
| `client_id` / `client_secret` directly on the inbound request, in either form — | ||
| standard HTTP Basic (the same credential encoding OAuth's `client_secret_basic` | ||
| uses), or separate flat headers for clients that can't Base64-encode the pair: |
There was a problem hiding this comment.
☑️ Resolved in e91e7d9. Updated the AIRBYTE_MCP_AUTH_ALLOW_CLIENT_CREDENTIALS bullet to say it "enables the inbound static client-credentials path described above (Basic or the Client-Id/Client-Secret headers)" so it matches the expanded behavior.
Co-Authored-By: AJ Steers <aj@airbyte.io>
Code Coverage OverviewLanguages: Python Python / code-coverage/pytest-fastThe overall coverage in commit e91e7d9 in the Show a code coverage summary of the most impacted files.
Python / code-coverage/pytest-no-credsThe overall coverage in commit e91e7d9 in the Show a code coverage summary of the most impacted files.
Python / code-coverage/pytestThe overall coverage in commit e91e7d9 in the Show a code coverage summary of the most impacted files.
Updated |
This PR targets the following PR:
Summary
Bumps
fastmcp-extensions0.14.0 -> 0.15.0so the opt-in client-credentials transport auth accepts a second credential form. Previously a headless agent could only present staticclient_id/client_secretas HTTP Basic (Authorization: Basic base64(id:secret)); 0.15.0'swrap_client_credentialsmiddleware now also accepts them as two flat headers, for clients that can't Base64-encode the pair:The exchange (post to the Airbyte token endpoint -> short-lived Bearer -> verify via existing
JWTVerifier) is unchanged, and the new headers are redacted from logs + stripped before forwarding downstream — all inside the library. This consumer inherits the behavior purely by the version bump;airbyte/mcp/_client_credentials.pystill owns only the Airbyte-specific policy (opt-inAIRBYTE_MCP_AUTH_ALLOW_CLIENT_CREDENTIALSflag + token endpoint) and passes plain values towrap_client_credentials.No behavior change when
AIRBYTE_MCP_AUTH_ALLOW_CLIENT_CREDENTIALSis unset (the default): the wrapper returns the app unchanged.Changes
pyproject.toml/uv.lock: floorfastmcp-extensions>=0.15.0,<1.0.0, relock (0.14.0 -> 0.15.0).airbyte/mcp/__init__.py,airbyte/mcp/_client_credentials.py): document theClient-Id/Client-Secretheader form alongside Basic; drop "HTTP Basic"-only phrasing.Test
uv run pytest tests/unit_tests/test_mcp_client_credentials.py tests/unit_tests/test_mcp_server_auth.py -q— 31 passed.uv run ruff check airbyte/mcp/+ruff format --check— clean.Link to Devin session: https://app.devin.ai/sessions/0b0d7690d5354d5c95e12ccf1b2e620e
Requested by: Aaron ("AJ") Steers (@aaronsteers)