fix(mcp): truncate query-tool responses instead of hard-failing#42244
Conversation
execute_sql, query_dataset, and get_chart_data raised a hard "Response too large" error whenever their result set exceeded the MCP response token limit, even though the majority of oversized responses are just a few rows too many. Extend ResponseSizeGuardMiddleware to truncate these three tools the same way info tools are already truncated: - Binary-search the largest row-count prefix that keeps the serialized response under the token limit, and return that instead of erroring. - Also handle CSV chart-data exports, where the payload lives in the scalar csv_data field (data=[]) rather than a row list. excel_data is base64-encoded binary and is left untouched, since truncating it would produce a corrupt file. - Re-check the truncated response's size before returning it (mirroring the existing info-tool path), so a single row/CSV blob that alone exceeds the limit falls back to the informative size-limit error instead of silently shipping an over-budget response. The bisection now reserves headroom for the truncation-note metadata up front so this fallback only triggers when truncation genuinely can't fit. - Tailor the truncation-note wording per tool (limit/row_limit parameter vs. SQL LIMIT clause) instead of always suggesting SQL.
✅ Deploy Preview for superset-docs-preview ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #42244 +/- ##
==========================================
- Coverage 65.27% 65.20% -0.08%
==========================================
Files 2769 2768 -1
Lines 156343 156431 +88
Branches 35788 35801 +13
==========================================
- Hits 102054 101994 -60
- Misses 52322 52469 +147
- Partials 1967 1968 +1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
The flagged issue is correct. In To resolve this, you should re-estimate the tokens on the final object after rewrapping, or account for the wrapper overhead during the check. Here is the corrected logic for the re-check: # ... (after truncation)
if not was_truncated:
return None
# Re-wrap to check total size including wrapper overhead
final_result = self._rewrap_as_tool_result(truncated, response) if extracted is not None and isinstance(truncated, dict) else truncated
truncated_tokens = estimate_response_tokens(final_result)
if truncated_tokens > self.token_limit:
return None
# ... (proceed with logging and return final_result)Would you like me to check the other comments on this PR and implement fixes for them as well? superset/mcp_service/middleware.py |
There was a problem hiding this comment.
Code Review Agent Run #f8f8ed
Actionable Suggestions - 1
-
superset/mcp_service/middleware.py - 1
- CWE-252: Missing truncation metadata · Line 1398-1401
Review Details
-
Files reviewed - 4 · Commit Range:
9d4e317..2d6ea36- superset/mcp_service/middleware.py
- superset/mcp_service/utils/token_utils.py
- tests/unit_tests/mcp_service/test_middleware.py
- tests/unit_tests/mcp_service/utils/test_token_utils.py
-
Files skipped - 0
-
Tools
- MyPy (Static Code Analysis) - ✔︎ Successful
- Astral Ruff (Static Code Analysis) - ✔︎ Successful
- Whispers (Secret Scanner) - ✔︎ Successful
- Detect-secrets (Secret Scanner) - ✔︎ Successful
Bito Usage Guide
Commands
Type the following command in the pull request comment and save the comment.
-
/review- Manually triggers a full AI review. -
/pause- Pauses automatic reviews on this pull request. -
/resume- Resumes automatic reviews. -
/resolve- Marks all Bito-posted review comments as resolved. -
/abort- Cancels all in-progress reviews.
Refer to the documentation for additional commands.
Configuration
This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.
Documentation & Help
|
Request changes: sound approach and the size-guard/fail-safe design is solid, but for the single-SELECT 🔴 High — 🟡 Medium — 🟡 Medium — Test gaps around the partial-data signal and the excel/fallback safety nets 🟢 Low — CSV truncation cuts mid-row 🟢 Low — Broad Cleared (checked, no issue): binary searches converge correctly with no off-by-one/infinite-loop; the fail-open path is closed (post-truncation re-check falls back to hard error); placeholder-headroom reservation is sound (real note ≤ placeholder); The High item is the one to resolve before merge — without it, the PR's core promise doesn't hold for the most common 🤖 Team review via Claude Code |
|
Thanks for the thorough review — went through each point: 🔴 High — What was real: 🟡 Medium — missing truncation markers on the 🟡 Medium — test gaps. Added:
🟢 Low — CSV truncation cuts mid-row. Checked this one and don't think it's live: the function actually responsible for 🟢 Low — broad Rebased onto master (no conflicts) and pushed. Full commit list: |
rebenitez1802
left a comment
There was a problem hiding this comment.
Looks like this just need a rebase, LGTM
* refactor(mcp): dedupe list-tool schemas and delete dead middleware (apache#41923) * fix(ag-grid-table): respect row limit with server pagination (apache#41346) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * feat(table/pivot-table): correct non-additive totals/subtotals via DB rollup [SIP-216] (apache#41184) Co-authored-by: Superset Dev <dev@superset.apache.org> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Amin Ghadersohi <amin.ghadersohi@gmail.com> * feat(datasets): add RLS filter indicator badge to dataset list and explore view (apache#38807) Co-authored-by: Evan <evan@preset.io> * fix(chart): updates counties of kenya map (apache#38019) Co-authored-by: Zack Adams <zack@Zacks-Laptop.local> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Evan <evan@preset.io> Co-authored-by: Evan Rusackas <evan@rusackas.com> * chore(deps): bump actions/setup-go from 6.5.0 to 7.0.0 (apache#42303) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump nanoid from 5.0.9 to 6.0.0 in /superset-frontend (apache#42230) Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: hainenber <dotronghai96@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: hainenber <dotronghai96@gmail.com> Co-authored-by: Joe Li <joe@preset.io> Co-authored-by: Evan <evan@preset.io> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> * test(dashboard): migrate dashboard load smoke test to Playwright (apache#41432) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(superset_app_root): when used with oauth (apache#38033) Signed-off-by: Grégoire Bellon-Gervais <gregoire.bellon-gervais@docaposte.fr> Co-authored-by: Evan Rusackas <evan@preset.io> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * refactor: engine enforce SQLAlchemy 2.0 (apache#42277) * fix(ag-grid-table): avoid ambiguous build query import (apache#42313) * fix: Revert "chore(deps): bump echarts from 5.6.0 to 6.1.0 in /superset-frontend" (apache#42314) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * adding circleci config * fix(plugin-chart-echarts): import the -obj locale build so time axes render (apache#42317) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(pandas_postprocessing): avoid FutureWarning for max/min in boxplot MINMAX (apache#42272) * fix(heatmap): correct tooltip axis value lookup and percentage calculations and add tests (apache#41864) Signed-off-by: yousoph <sophieyou12@gmail.com> Co-authored-by: Kamil Gabryjelski <kamil.gabryjelski@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix(forecast): resolve time grain robustly for Prophet forecasting (apache#42145) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix: Added PostgreSQL 17.X to the supported database versions table in (apache#42280) * fix(helm): add MCP HTTPRoute configuration (apache#42219) * fix(dashboard): offer Exit edit mode when there is nothing to discard (apache#42208) Co-authored-by: Claude Code <noreply@anthropic.com> * chore(deps): bump actions/labeler from 6.2.0 to 7.0.0 (apache#42332) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump github/codeql-action/analyze from 4.37.0 to 4.37.1 (apache#42331) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump github/codeql-action/init from 4.37.0 to 4.37.1 (apache#42334) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump @formatjs/intl-durationformat from 0.10.17 to 0.10.18 in /superset-frontend (apache#42337) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump caniuse-lite from 1.0.30001805 to 1.0.30001806 in /docs (apache#42333) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump echarts to 6.1.0 with locale and containLabel guards (apache#42315) (apache#42321) Co-authored-by: Claude Code <noreply@anthropic.com> Co-authored-by: Amin Ghadersohi <amin.ghadersohi@gmail.com> * docs: add pattern to the list of organisations using superset (apache#42341) * chore(deps): bump ag-grid from 36.0.0 to 36.0.1 in /superset-frontend (apache#42338) Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: hainenber <dotronghai96@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: hainenber <dotronghai96@gmail.com> * fix(mcp): trust dataset is_dttm flag when applying time_grain to VARCHAR temporal columns (apache#42288) * chore(deps-dev): update taos-ws-py requirement from >=0.6.9 to >=0.7.0 (apache#42344) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump the storybook group in /superset-frontend with 5 updates (apache#42355) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix(native-filters): keep filter value input caret at inline start (apache#42323) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(mcp): truncate query-tool responses instead of hard-failing (apache#42244) * chore(deps): bump nh3 from 0.3.5 to 0.3.6 (apache#42349) Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Joe Li <joe@preset.io> * chore(deps): bump pydantic from 2.11.7 to 2.13.4 (apache#42350) Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Joe Li <joe@preset.io> * chore(deps): bump sqlalchemy-continuum from 1.6.0 to 1.7.0 (apache#42351) Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Joe Li <joe@preset.io> * fix(embedded): stop rejecting guest chart data built from control-specific params keys (apache#42295) Co-authored-by: Claude Code <noreply@anthropic.com> * fix(explore): show the beginning date on time-series x-axis line charts (apache#42046) * fix(api): add example to get_export_ids_schema so Swagger "Try it out" pre-fills a valid array (apache#42265) * chore: SQLAlchemy User cascade backref warnings are irrelevant (apache#42360) * fix(charts): handle async (202) chart-data responses in StatefulChart (apache#42157) Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> Co-authored-by: Evan Rusackas <evan@preset.io> * feat(KustoKQL): Add support for NULL / IS NOT NULL operator (apache#37890) Co-authored-by: ag-ramachandran <ramacg@microsoft.com> Co-authored-by: Joe Li <joe@preset.io> * chore(deps): bump pillow from 12.2.0 to 12.3.0 (apache#42348) Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Joe Li <joe@preset.io> * chore(deps): bump flask-compress from 1.17 to 1.24 (apache#42346) Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Joe Li <joe@preset.io> * chore(deps-dev): bump databricks-sql-connector from 4.2.6 to 4.3.0 (apache#42347) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Joe Li <joe@preset.io> Co-authored-by: Evan Rusackas <evan@preset.io> * fix(native-filters): use FILTER_STATE_CACHE_CONFIG timeout for dynamic filter option queries (apache#38910) * fix(explore): render Jinja before validating legacy chart filters (apache#41996) * fix(dataset): disable duplicate button when name is empty (apache#42217) Co-authored-by: AS-MAC-1123 <as-mac-1123@AS-MAC-1123.local> Co-authored-by: Evan Rusackas <evan@rusackas.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * docs(gunicorn): correct dead links in values.yaml (apache#42385) * chore(deps): bump @deck.gl/mapbox from 9.3.6 to 9.3.7 in /superset-frontend in the deckgl group (apache#42377) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump actions/checkout from 7.0.0 to 7.0.1 (apache#42376) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump immer from 11.1.11 to 11.1.15 in /superset-frontend (apache#42378) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump body-parser from 1.20.5 to 1.20.6 in /docs (apache#42370) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump brace-expansion from 1.1.15 to 1.1.16 in /superset-embedded-sdk (apache#42369) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix(security): bump pyasn1 from 0.6.3 to 0.6.4 (apache#42363) * fix(security): bump pillow from 12.2.0 to 12.3.0 (apache#42362) * docs(map-tiles): add Yandex Maps Tiles API configuration (apache#42375) * ci: improve conditional checks for lillio tests and build --------- Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: hainenber <dotronghai96@gmail.com> Signed-off-by: Grégoire Bellon-Gervais <gregoire.bellon-gervais@docaposte.fr> Signed-off-by: yousoph <sophieyou12@gmail.com> Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Amin Ghadersohi <amin.ghadersohi@gmail.com> Co-authored-by: Evan Rusackas <evan@preset.io> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Superset Dev <dev@superset.apache.org> Co-authored-by: SkinnyPigeon <e.blackledge@stuart.com> Co-authored-by: Zack <adams.z.d@gmail.com> Co-authored-by: Zack Adams <zack@Zacks-Laptop.local> Co-authored-by: Evan Rusackas <evan@rusackas.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: hainenber <dotronghai96@gmail.com> Co-authored-by: Joe Li <joe@preset.io> Co-authored-by: Grégoire <greggbg@gmail.com> Co-authored-by: Hans Yu <hans.yu@outlook.de> Co-authored-by: Elizabeth Thompson <eschutho@gmail.com> Co-authored-by: yousoph <sophieyou12@gmail.com> Co-authored-by: Kamil Gabryjelski <kamil.gabryjelski@gmail.com> Co-authored-by: Amitesh Gupta <143833521+singlaamitesh@users.noreply.github.com> Co-authored-by: David <39565245+dmunozv04@users.noreply.github.com> Co-authored-by: Yash Shrivastava <119301033+alephys26@users.noreply.github.com> Co-authored-by: JUST.in DO IT <justin.park@airbnb.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: jesperct <jmilecelento@gmail.com> Co-authored-by: Abdul Rehman <76230556+Abdulrehman-PIAIC80387@users.noreply.github.com> Co-authored-by: jenwitteng <jenwit.amonpongitsara@agoda.com> Co-authored-by: Ramachandran A G <106139410+ag-ramachandran@users.noreply.github.com> Co-authored-by: ag-ramachandran <ramacg@microsoft.com> Co-authored-by: Ujjwal Jain <jainujjwal1609@gmail.com> Co-authored-by: Jean Massucatto <massucattoj@gmail.com> Co-authored-by: suvankardas216 <rohanrohan510@gmail.com> Co-authored-by: AS-MAC-1123 <as-mac-1123@AS-MAC-1123.local> Co-authored-by: Alejandro Solares <219859296+ASolarers-Rodriguez@users.noreply.github.com> Co-authored-by: ViktorGo86 <114023094+ViktorGo86@users.noreply.github.com>
SUMMARY
execute_sql,query_dataset, andget_chart_dataraised a hard "Response too large" error whenever their result exceeded the MCP response token limit, even when the response was only a few rows over. This extendsResponseSizeGuardMiddlewareto truncate these three tools the same way info tools (get_chart_info,get_dataset_info, etc.) are already truncated, instead of hard-failing:csv_datafield (data=[]) rather than a row list, by truncating that field directly.excel_datais base64-encoded binary and is left untouched, since truncating it would produce a corrupt file.limit/row_limitparameter vs. SQLLIMITclause) instead of always suggesting a SQLLIMIT.BEFORE/AFTER
Before:
execute_sql/query_dataset/get_chart_dataresponses that exceeded the token limit always raisedToolError: Response too large, even if truncating a handful of rows would have brought them under the limit.After: these tools truncate the row set (or CSV content) and return a partial result with
_response_truncated/_truncation_notesset, falling back to the hard error only when truncation genuinely cannot bring the response under the limit.TESTING INSTRUCTIONS
pytest tests/unit_tests/mcp_service/(3086 passed)ruff check/ruff format --diff/mypyon the changed filesADDITIONAL INFORMATION
docs/updates