Skip to content

fix(mcp): stop false-flagging successful responses with error_type:null as failures (#42580) - #42736

Merged
rusackas merged 2 commits into
masterfrom
tdd/issue-42580-mcp-false-positive-error-logging
Aug 5, 2026
Merged

fix(mcp): stop false-flagging successful responses with error_type:null as failures (#42580)#42736
rusackas merged 2 commits into
masterfrom
tdd/issue-42580-mcp-false-positive-error-logging

Conversation

@rusackas

@rusackas rusackas commented Aug 3, 2026

Copy link
Copy Markdown
Member

SUMMARY

Fixes #42580: successful execute_sql (and other tool) calls were logged as failures in the MCP audit log.

Root cause. LoggingMiddleware._is_error_response decided success/failure with a raw substring search, '"error_type"' in result.content[0].text. Success response schemas (the ones adjacent to ChartError/DashboardError) declare error_type as an optional field defaulting to null, for a uniform response shape — so every successful call's serialized JSON contains that substring too, and gets logged as success=False.

Fix. Parse the response body as JSON and check whether error_type is actually truthy, not merely present. The real error schemas (e.g. DashboardError) always populate error_type with a concrete type string on failure and never on success, so this is a reliable discriminator where the substring check wasn't.

Also corrected a pre-existing test fixture (test_on_call_tool_does_not_extract_id_on_failed_response) that modeled error_type nested under an "error" object — no schema in the codebase actually produces that shape; error is always a plain message string with error_type as its sibling field, not a container.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

N/A — backend audit-logging fix, no UI change.

TESTING INSTRUCTIONS

.venv/bin/python -m pytest tests/unit_tests/mcp_service/test_middleware_logging.py -q

39 passed. Also ran the full tests/unit_tests/mcp_service/ suite (3134 tests): 1 pre-existing unrelated failure (test_tools_call_health_check_over_real_asgi_transport, a test-isolation FK-constraint/version-field issue, confirmed unrelated by running it in isolation both before and after this change).

ADDITIONAL INFORMATION

…payloads (#42580)

LoggingMiddleware._is_error_response substring-matches for the literal
"error_type" key, but response schemas like ExecuteSqlResponse always
serialize an "error_type" field (null on success), so every successful
execute_sql call is misclassified as a failure and logged with
success=False.
@bito-code-review

bito-code-review Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #bda4ef

Actionable Suggestions - 0
Review Details
  • Files reviewed - 1 · Commit Range: 1cd9754..1cd9754
    • tests/unit_tests/mcp_service/test_middleware_logging.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

AI Code Review powered by Bito Logo

@codecov

codecov Bot commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.59%. Comparing base (25ab961) to head (eaec5e2).
⚠️ Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
superset/mcp_service/middleware.py 0.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #42736      +/-   ##
==========================================
+ Coverage   65.57%   65.59%   +0.01%     
==========================================
  Files        2818     2819       +1     
  Lines      160038   160168     +130     
  Branches    36557    36569      +12     
==========================================
+ Hits       104942   105055     +113     
- Misses      53051    53064      +13     
- Partials     2045     2049       +4     
Flag Coverage Δ
hive 38.09% <0.00%> (+0.01%) ⬆️
mysql 57.92% <0.00%> (+0.05%) ⬆️
postgres 57.96% <0.00%> (+0.04%) ⬆️
presto 40.02% <0.00%> (+0.05%) ⬆️
python 59.34% <0.00%> (+0.04%) ⬆️
sqlite 57.59% <0.00%> (+0.05%) ⬆️
unit 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…ll as failures (#42580)

_is_error_response did a raw substring search for '"error_type"' in the
serialized tool response, but success schemas (ChartError-adjacent
response models) declare error_type as an optional field defaulting to
null, so every successful call's response contains that substring too --
logging it as a failure regardless of outcome.

Parse the response as JSON and check error_type for a truthy value
instead of merely being present, matching how the real error schemas
(DashboardError, etc.) always populate it with a real type string on
failure and never on success.

Also corrects a pre-existing test fixture that modeled error_type nested
under an "error" object -- no schema in the codebase produces that shape;
error is always a plain message string with error_type as its sibling.
@pull-request-size pull-request-size Bot added size/M and removed size/S labels Aug 4, 2026
@rusackas rusackas changed the title test(mcp): pin _is_error_response against error_type:null in success payloads (#42580) fix(mcp): stop false-flagging successful responses with error_type:null as failures (#42580) Aug 4, 2026
@netlify

netlify Bot commented Aug 4, 2026

Copy link
Copy Markdown

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit eaec5e2
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6a7134a30e207a00084170de
😎 Deploy Preview https://deploy-preview-42736--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@bito-code-review

bito-code-review Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #1f34e6

Actionable Suggestions - 0
Filtered by Review Rules

Bito filtered these suggestions based on rules created automatically for your feedback. Manage rules.

  • tests/unit_tests/mcp_service/test_middleware_logging.py - 1
Review Details
  • Files reviewed - 2 · Commit Range: 1cd9754..eaec5e2
    • superset/mcp_service/middleware.py
    • tests/unit_tests/mcp_service/test_middleware_logging.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

AI Code Review powered by Bito Logo

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

Verified the success/failure determination behaves correctly across the null-vs-absent-vs-real distinction.

Predicate — old '"error_type"' in result.content[0].text (substring, shape-blind) → new bool(isinstance(payload, dict) and payload.get("error_type")) over the parsed JSON:

  • error_type absent → .get None → success
  • error_type: null → None → success ✅ (the #42580 bug)
  • error_type: "validation_error" (real value) → truthy → failure

No under-reporting of real failures. All error responses derive from MCPBaseError (common/error_schemas.py), which declares a required, top-level, non-empty error_type: str, so genuine errors still serialize a truthy top-level value and are still flagged. The raised-exception path (error_type = type(exc).__name__, success = False) and the separate isError encoding path in StructuredContentStripperMiddleware are untouched — no collateral damage. Success is derived from this single signal, consistent with the pre-existing design and non-conflicting with the error-path work in #42730.

Edge cases: error_type: "" → treated as success — acceptable, since the schema contract makes an empty discriminator a non-error; 0/False are unreachable given the str | None typing. Only top-level error_type is inspected, which matches the real serialized shape (the old test's nested "error": {"error_type": ...} fixture was an artifact of the substring check, correctly updated here).

Tests cover both directions, non-vacuously. Reverting only the production predicate makes test_success_response_with_null_error_type_not_detected_as_error fail (null→success), while test_on_call_tool_does_not_extract_id_on_failed_response guards real-error→failure against the actually-emitted curated_payload["success"]. Verified locally.

@rusackas
rusackas merged commit 9c97d48 into master Aug 5, 2026
78 checks passed
@rusackas
rusackas deleted the tdd/issue-42580-mcp-false-positive-error-logging branch August 5, 2026 16:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(mcp): successful execute_sql calls logged as success=False — _is_error_response substring-matches "error_type" including when null

3 participants