Repository navigation
feat(mcp): always return snippets from execute_external_search_query - #1464
Conversation
…uery` Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".
|
👋 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/1794459230-fusion-snippet-search' pyairbyte --help
# Install PyAirbyte from this branch for development:
pip install 'git+https://github.com/airbytehq/PyAirbyte.git@devin/1794459230-fusion-snippet-search'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. |
Code coverage overviewLanguages: Python Python / code-coverage/pytest-no-creds
View coverage of the 10 most impacted files.
Python / code-coverage/pytest
View coverage of the 10 most impacted files.
Python / code-coverage/pytest-unit
Line coverage data for the release-candidate/v1 branch is not yet available. View coverage of the 10 most covered files.
ℹ️ Calculations represent line coverage. Results may change as calculations are updated. Updated |
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>
execute_external_search_queryexecute_external_search_query
|
Cloud MCP eval comparison (run 43159059561, dispatched at 073095f, before
Posted by Devin, on behalf of Caleb Evans (@calebevans-ab). |
|
Devin, is this ready to go? Did you do e2e test? |
|
Aaron ("AJ") Steers (@aaronsteers) this is a bit of a PoC at the moment, sorry meant to mark this as a draft while I work on this. Devin, please mark this as a draft and add DO NOT MERGE to the title while we work on proving if this actually helps or hurts our results. |
There was a problem hiding this comment.
🟡 Changes recommended
An empty streams selection bypasses client-side stripping despite include_entity_data=False, retaining entity_data and undermining response-size reduction; this case needs a fix and test coverage.
1 open issue
What changed in this PR
This PR makes MCP searches use snippet mode to reduce agent response size while preserving full-record behavior for existing SDK callers.
Changes:
- Adds SDK snippet mode with stream field projection, client-side data stripping when streams are omitted, and a default 512-character context limit.
- Adds hit namespaces and warnings for hits omitted due to response-size limits.
- Updates agent guidance and tests for snippet behavior and SDK compatibility.
| File | Description |
|---|---|
| tests/unit_tests/test_mcp_cloud.py | Verifies the MCP tool always requests snippet mode. |
| tests/unit_tests/test_cloud_direct_execute.py | Tests projections, context limits, SDK compatibility, namespaces, and omission warnings. |
| airbyte/mcp/cloud.py | Forces snippet mode and updates agent-facing search guidance. |
| airbyte/cloud/connectors.py | Adds optional snippet-mode behavior while retaining SDK defaults. |
| airbyte/_direct_connectors/models.py | Adds namespace enrichment, omitted-hit warnings, and search-key documentation. |
Review effort: Balanced
|
AJ, not yet. I haven't run an e2e test against a live Fusion index. What has been verified:
Still open before merge:
I can run item 1 next if you want it before merge. Posted by Devin, on behalf of Caleb Evans (@calebevans-ab). |
execute_external_search_queryexecute_external_search_query
|
Done, Caleb: the PR is back to draft and the title now starts with Posted by Devin, on behalf of Caleb Evans (@calebevans-ab). |
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
AJ, the read-only live test passed. I ran
Posted by Devin, on behalf of Caleb Evans (@calebevans-ab). |
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
execute_external_search_queryexecute_external_search_query
|
Devin please run e2e tests on this |
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
On it, Caleb. I'm running a read-only end-to-end test of the full flow from this branch against the Fusion test org: search for snippets, pick hits, then read their full records through Posted by Devin, on behalf of Caleb Evans (@calebevans-ab). |
|
Caleb, the end-to-end flow passed. I ran the MCP tools from this branch locally (head
One gap for agents: a hit doesn't tell them where its full record lives. Here Posted by Devin, on behalf of Caleb Evans (@calebevans-ab). |
7de8652
into
release-candidate/v1

Overview
👉 TL;DR: Agents searching Fusion-indexed data now always get short text snippets and record IDs back, never every matched record in full. That cuts a typical search response from hundreds of thousands of tokens to a few thousand.
Specifically,
execute_external_search_queryalways runs in snippet mode and has no option to return full records.CloudConnector.execute_search_querygainsinclude_entity_data(defaultTrue, so existing SDK callers are unchanged); the MCP tool always passesFalse.Requested by Caleb Evans. This is phase 1. Phase 2 adds a fetch-by-id tool that reads full records for chosen hits; it needs work in Sonar and the Cloud API first and is not in this PR.
Changes
streamsentry with nofieldsis sent withfields: [], so the backend leavesentity_dataoutstreams, the request goes out unchanged (no status lookup) and each hit'sentity_datais set to{}on the clientmax_context_charsdefaults to512when the caller leaves it unset; a value the caller passes is keptinclude_entity_data=Truesends the request unchanged and returns full records, as today.ExternalSearchHit.namespaceis new. It is filled frommetadatawhen only one namespace matches the hit's(source_id, stream_name).ExternalSearchIndexMetadata.hits_omittedis new. A positive total adds a warning to narrowstreamsor lowerlimit.entity_iddocs now say it is a search record key (a JSON array of typed primary key parts, orrow-sha256:<hash>), not a source API ID.execute_external_api_query/execute_external_sql_query, until the phase 2 fetch-by-id tool lands.Review Spotlight
Reviewers with limited time, please review first:
connectors.py#L747-L789: the projection, the 512 default and strippingentity_dataon the clientmodels.py#L414-L441: thehits_omittedwarning and namespace matchingcloud.py#L2301-L2347: the agent-facing description and the forced snippet modeRisks
entity_datafrom a search now get{}unless they listfieldsinstreams; full records must come from the API or SQL tools until phase 2.streams. That search still returns full records over the wire and drops them on the client, so agent tokens go down but response size and latency do not.hits_omitteddepends on the backend. PyAirbyte reads it when the backend sends it; until then it is0and no warning shows.Evals: no Fusion scenario exists yet
cloud-mcp-evalsmain has no scenario that callsexecute_external_search_query, and itsairbyte_cloudtwin has no search endpoint for one to call. Fusion scenarios and the twin are separate work in another session (not yet merged), andfusion_snippet_then_fetchthere expects aninclude_entity_data=truecall, which this PR no longer allows. The changed-tools comparison for this PR therefore cannot measure the snippet change, and its result is reported in a comment below.Test plan
poe check(ruff, pyrefly, test collection, docstring lint): passespoe test-unit-tests: 2486 passed, 1 skipped. The VM'sAIRBYTE_CLIENT_ID/AIRBYTE_CLIENT_SECRETenv vars were unset for the run, because they maketest_agent_request_problem_message_and_guidancefail in this environment regardless of the change.test_cloud_direct_execute.pyandtest_mcp_cloud.pycover:fields: []added tostreamsentries, while callerfieldsare keptstreamsmaking one call and returningentity_data == {}include_entity_data=Trueforwarding the request unchangedsource_idhits_omittedwarninginclude_entity_data=FalseLink to Devin session: https://app.devin.ai/sessions/e0df147ccc894ea78fcbd53adadad8d3