Skip to content

fix(mcp): resolve get_connector_info spec from registry instead of installing#1077

Merged
Aaron ("AJ") Steers (aaronsteers) merged 4 commits into
mainfrom
devin/1784058706-gate-connector-info-install
Jul 14, 2026
Merged

fix(mcp): resolve get_connector_info spec from registry instead of installing#1077
Aaron ("AJ") Steers (aaronsteers) merged 4 commits into
mainfrom
devin/1784058706-gate-connector-info-install

Conversation

@aaronsteers

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

Copy link
Copy Markdown
Member

Summary

get_connector_info could hang for minutes on the hosted Cloud MCP server. On a
hosted, no-Docker runtime, populating config_spec_jsonschema fell through to a
fresh pip/venv install of the connector on every call — an unbounded operation
that has stalled requests for over four minutes.

PyAirbyte #1052 gated the local.py filesystem/config tools with
requires_client_filesystem, but get_connector_info in registry.py was never
gated, so it stayed exposed on hosted Cloud MCP and kept running the install path.

This gates only the expensive step on Docker availability, so the tool still returns
the fast registry metadata (docs URL, manifest URL, connector metadata) everywhere,
and simply omits config_spec_jsonschema when it can't be resolved cheaply:

config_spec_jsonschema = None
if is_docker_installed():
    # Docker => fast image pull. No Docker (hosted) => unbounded pip/venv install.
    with contextlib.suppress(Exception):
        connector.install()
        config_spec_jsonschema = connector.config_spec

Behavior after the fix:

  • Local with Docker: unchanged — installs (fast image pull) and returns config_spec_jsonschema.
  • Hosted / no Docker: skips the install, returns config_spec_jsonschema=None, no hang.

config_spec_jsonschema is already Optional, so returning None is within the
existing contract. is_docker_installed() is already imported and used two lines
above to choose docker_image=.

Added a parametrized regression test asserting connector.install() is called only
when Docker is available and config_spec_jsonschema is None otherwise.

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

Summary by CodeRabbit

  • Bug Fixes
    • Improved connector information retrieval by resolving configuration schemas from the public connector registry (preferring the cloud spec, falling back to OSS).
    • When no schema is available, config_spec_jsonschema is now returned as None rather than relying on Docker-based execution.
    • Prevents unnecessary connector setup steps in Docker-restricted environments while keeping metadata such as the manifest URL available.
  • Tests
    • Added/updated unit tests to ensure schema resolution is driven by registry lookups (cloud → OSS → none) and that connector installation is not invoked.

Important

Auto-merge enabled.

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

…out Docker

Co-Authored-By: AJ Steers <aj@airbyte.io>
@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/1784058706-gate-connector-info-install' pyairbyte --help

# Install PyAirbyte from this branch for development:
pip install 'git+https://github.com/airbytehq/PyAirbyte.git@devin/1784058706-gate-connector-info-install'

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.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@devin-ai-integration[bot], you've reached your PR review limit, so we couldn't start this review.

Next review available in: 7 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a6d3e62a-2ca9-4973-8e68-edcb35f742fa

📥 Commits

Reviewing files that changed from the base of the PR and between a016541 and 0126a40.

📒 Files selected for processing (2)
  • airbyte/mcp/registry.py
  • tests/unit_tests/test_mcp_connector_registry.py
📝 Walkthrough

Walkthrough

get_connector_info now resolves config_spec_jsonschema from the public connector registry, preferring the cloud spec and falling back to OSS. Connector installation is no longer required, and tests cover available, fallback, and missing-spec cases.

Changes

Connector info resolution

Layer / File(s) Summary
Registry schema resolution
airbyte/mcp/registry.py, tests/unit_tests/test_mcp_connector_registry.py
get_connector_info performs cloud-first registry lookup with OSS fallback and avoids connector installation; tests verify returned metadata, lookup order, and None when no spec exists.

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

Sequence Diagram(s)

sequenceDiagram
  participant get_connector_info
  participant get_connector_spec_from_registry
  participant PublicConnectorRegistry
  get_connector_info->>get_connector_spec_from_registry: Request cloud spec
  get_connector_spec_from_registry->>PublicConnectorRegistry: Fetch connector spec
  PublicConnectorRegistry-->>get_connector_spec_from_registry: Cloud spec or None
  get_connector_info->>get_connector_spec_from_registry: Request OSS spec when cloud is unavailable
  get_connector_spec_from_registry->>PublicConnectorRegistry: Fetch OSS connector spec
  PublicConnectorRegistry-->>get_connector_info: Selected spec or None
Loading
🚥 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 clearly matches the main change: get_connector_info now resolves the config spec from the registry instead of installing connectors.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch devin/1784058706-gate-connector-info-install

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.

🧹 Nitpick comments (1)
airbyte/mcp/registry.py (1)

171-178: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Consider evaluating is_docker_installed() once.

is_docker_installed() relies on a filesystem lookup (which("docker")), and we are currently evaluating it twice in this function (here and previously in the get_source call). Could we assign the result to a local variable to avoid redundant checks and clean up the redundant or False from the get_source call, wdyt?

♻️ Proposed refactor

Apply the following changes outside the current line range, right before the get_source call:

    if connector_name not in get_available_connectors():
        return "Connector not found."

    docker_available = is_docker_installed()

    connector = get_source(
        connector_name,
        docker_image=docker_available,
        install_if_missing=False,  # Defer to avoid failing entirely if it can't be installed.
    )

Then, update this conditional check:

-    if is_docker_installed():
+    if docker_available:
         # Populating `config_spec` requires installing and running the connector.
         # Only attempt it when Docker is available (a fast image pull). In a hosted,
🤖 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/registry.py` around lines 171 - 178, Evaluate
is_docker_installed() once before the get_source call and store the result in a
local docker_available variable. Pass that variable directly as docker_image
without the redundant “or False”, and reuse docker_available for the later
conditional guarding connector installation.
🤖 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.

Nitpick comments:
In `@airbyte/mcp/registry.py`:
- Around line 171-178: Evaluate is_docker_installed() once before the get_source
call and store the result in a local docker_available variable. Pass that
variable directly as docker_image without the redundant “or False”, and reuse
docker_available for the later conditional guarding connector installation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d8c5dfa5-e4dc-4864-b703-7ede96b763d8

📥 Commits

Reviewing files that changed from the base of the PR and between 6a1ce75 and 5b1ce01.

📒 Files selected for processing (2)
  • airbyte/mcp/registry.py
  • tests/unit_tests/test_mcp_connector_registry.py

@github-code-quality

github-code-quality Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: Python

Python / code-coverage/pytest-fast

The overall coverage in the branch is 67%. The coverage in the branch is 65%.

Show a code coverage summary of the most impacted files.
File d9f652f 0126a40 +/-
airbyte/_util/api_util.py 36% 37% +1%
airbyte/registry.py 70% 72% +2%
airbyte/mcp/registry.py 53% 70% +17%
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/int...ive/__init__.py 0% 100% +100%
airbyte/mcp/int...tive/_prefab.py 0% 100% +100%

Python / code-coverage/pytest-no-creds

The overall coverage in the branch is 67%. The coverage in the branch is 65%.

Show a code coverage summary of the most impacted files.
File d9f652f 0126a40 +/-
airbyte/_util/api_util.py 36% 37% +1%
airbyte/registry.py 70% 72% +2%
airbyte/mcp/registry.py 53% 70% +17%
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/int...ive/__init__.py 0% 100% +100%
airbyte/mcp/int...tive/_prefab.py 0% 100% +100%

Python / code-coverage/pytest

The overall coverage in the branch is 72%. The coverage in the branch is 71%.

Show a code coverage summary of the most impacted files.
File d9f652f 0126a40 +/-
airbyte/registry.py 70% 72% +2%
airbyte/mcp/server.py 69% 78% +9%
airbyte/mcp/registry.py 53% 70% +17%
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/int...ive/__init__.py 0% 100% +100%
airbyte/mcp/int...tive/_prefab.py 0% 100% +100%

Updated July 14, 2026 21:18 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@aaronsteers Aaron ("AJ") Steers (aaronsteers) marked this pull request as ready for review July 14, 2026 20:37
@devin-ai-integration devin-ai-integration Bot marked this pull request as ready for review July 14, 2026 20:37
Copilot AI review requested due to automatic review settings July 14, 2026 20:37
@aaronsteers

Copy link
Copy Markdown
Member Author

Is there a different approach we can take? Now that we have, I think, other code in production that is able to get config information from GCS-hosted public HTTP endpoints, only needing to have the version string to calculate the spec based on a stored OSS and cloud spec file hosted in GCP and available via public endpoint.

You can check this repo, and you can check the ops repo for the working pattern, but I think we can just always avoid calling docker here if all we need docker for is to get the spec.json

@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

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

Fixes a performance/hanging issue in the MCP connector registry tool by preventing get_connector_info from triggering an unbounded connector install path in no-Docker (hosted) environments, while still returning fast registry metadata.

Changes:

  • Gate connector.install() / config_spec_jsonschema population behind is_docker_installed() to avoid slow pip/venv installs on hosted runtimes.
  • Reuse a single docker_available check for both get_source(..., docker_image=...) and the config-spec resolution path.
  • Add a parametrized unit regression test ensuring install is attempted only when Docker is available.

Reviewed changes

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

File Description
airbyte/mcp/registry.py Skips config-spec installation step when Docker isn’t available to prevent long hangs in hosted MCP.
tests/unit_tests/test_mcp_connector_registry.py Adds regression coverage for Docker-vs-no-Docker behavior of get_connector_info.

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

Comment thread airbyte/mcp/registry.py Outdated
…point

Fetch the config spec from the public connector registry (cloud then oss
fallback) keyed by version instead of installing/running the connector.
Works in any runtime without Docker, so the spec is populated in hosted
no-Docker mode too, eliminating the unbounded install path entirely.

Co-Authored-By: AJ Steers <aj@airbyte.io>
@devin-ai-integration devin-ai-integration Bot changed the title fix(mcp): skip unbounded connector install in get_connector_info without Docker fix(mcp): resolve get_connector_info spec from registry instead of installing Jul 14, 2026
@devin-ai-integration

Copy link
Copy Markdown
Contributor

☑️ Done — switched to the registry HTTP approach in a016541.

You're right, and this is cleaner than the Docker gate. Instead of installing/running the connector to compute the spec, get_connector_info now fetches it from the public connector registry endpoint keyed by version, using the existing get_connector_spec_from_registry helper in airbyte/_util/registry_spec.py (https://connectors.airbyte.com/files/metadata/airbyte/{connector}/{version}/{platform}.json) — the same helper NoOpExecutor already uses for no-install spec validation.

config_spec_jsonschema = get_connector_spec_from_registry(
    connector_name, platform="cloud"
) or get_connector_spec_from_registry(connector_name, platform="oss")

Net effect vs. the earlier commit: no Docker anywhere in this path, and the spec is now populated in all runtimes (hosted included), not just where Docker exists — it's only None when the registry has no spec for the connector. Prefers cloud, falls back to oss, mirroring NoOpExecutor. Dropped the is_docker_installed gating and replaced the Docker-gating test with three focused tests (cloud used / oss fallback / both-absent→None), each asserting connector.install() is never called. PR title + description updated to match.


Devin session

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

🧹 Nitpick comments (1)
airbyte/mcp/registry.py (1)

173-179: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider passing the version and avoiding or for dict fallbacks.

Since we already fetch connector_metadata above, we could pass the explicit version to get_connector_spec_from_registry here to avoid redundantly looking up the metadata inside that helper.

Additionally, while Airbyte config specs are never empty dictionaries in practice, an empty dictionary evaluates to False in Python. Using or would cause an unintended fallback to the OSS spec if the cloud spec was ever technically valid but empty {}. Using an explicit is None check is a bit safer.

Would you be open to a small refactor like this? wdyt?

💡 Proposed refactor
-    config_spec_jsonschema: dict[str, Any] | None = get_connector_spec_from_registry(
-        connector_name,
-        platform="cloud",
-    ) or get_connector_spec_from_registry(
-        connector_name,
-        platform="oss",
-    )
+    version = connector_metadata.latest_available_version if connector_metadata else None
+    config_spec_jsonschema: dict[str, Any] | None = get_connector_spec_from_registry(
+        connector_name,
+        version=version,
+        platform="cloud",
+    )
+    if config_spec_jsonschema is None:
+        config_spec_jsonschema = get_connector_spec_from_registry(
+            connector_name,
+            version=version,
+            platform="oss",
+        )
🤖 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/registry.py` around lines 173 - 179, Update the config spec
lookup in the surrounding registry flow to pass the already-fetched
connector_metadata version to each get_connector_spec_from_registry call,
avoiding redundant metadata lookup. Replace the truthiness-based cloud/OSS
fallback with an explicit None check so a valid empty cloud dictionary is
retained.
🤖 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.

Nitpick comments:
In `@airbyte/mcp/registry.py`:
- Around line 173-179: Update the config spec lookup in the surrounding registry
flow to pass the already-fetched connector_metadata version to each
get_connector_spec_from_registry call, avoiding redundant metadata lookup.
Replace the truthiness-based cloud/OSS fallback with an explicit None check so a
valid empty cloud dictionary is retained.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e8dd1947-c4c1-459d-a677-37bf04046070

📥 Commits

Reviewing files that changed from the base of the PR and between f28774b and a016541.

📒 Files selected for processing (2)
  • airbyte/mcp/registry.py
  • tests/unit_tests/test_mcp_connector_registry.py

Pass the already-fetched metadata version to get_connector_spec_from_registry
to avoid a redundant lookup and version drift between the cloud/oss calls, and
use an explicit is-None check so a valid empty cloud spec is not skipped.

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

Copy link
Copy Markdown
Contributor

☑️ Addressed CodeRabbit's nitpick on airbyte/mcp/registry.py (config spec lookup) in 0126a40. Both points were valid and functional, so I applied the refactor:

  • Now passes the already-fetched connector_metadata.latest_available_version to both get_connector_spec_from_registry calls, avoiding the redundant metadata lookup inside the helper and eliminating any version drift between the cloud and oss attempts.
  • Switched the fallback from or to an explicit if config_spec_jsonschema is None: so a valid-but-empty {} cloud spec is retained rather than silently falling through to oss.

Tests updated to assert the version= kwarg is threaded through both calls. 29 passing locally.


Devin session

@aaronsteers Aaron ("AJ") Steers (aaronsteers) merged commit 8a6160f into main Jul 14, 2026
21 checks passed
@aaronsteers Aaron ("AJ") Steers (aaronsteers) deleted the devin/1784058706-gate-connector-info-install branch July 14, 2026 21:18
@aaronsteers Aaron ("AJ") Steers (aaronsteers) changed the title fix(mcp): resolve get_connector_info spec from registry instead of installing fix(mcp): resolve get_connector_info spec from registry instead of installing Jul 14, 2026
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