Skip to content

feat(mcp): add feature-gated interactive pivot support - #43480

Open
aminghadersohi wants to merge 7 commits into
apache:masterfrom
aminghadersohi:aminghadersohi/mcp-interactive-pivot
Open

feat(mcp): add feature-gated interactive pivot support#43480
aminghadersohi wants to merge 7 commits into
apache:masterfrom
aminghadersohi:aminghadersohi/mcp-interactive-pivot

Conversation

@aminghadersohi

Copy link
Copy Markdown
Contributor

SUMMARY

Recreates and supersedes closed PR #43268 after its head repository was removed. This PR is explicitly based on apache/superset:master.

Adds a distinct, feature-gated MCP adapter for Preset's ag-grid-pivot-table visualization. This deliberately does not alias Interactive Pivot to the OSS pivot_table_v2 adapter.

The new interactive_pivot schema and plugin cover:

  • AG Grid row groups, pivot columns, metrics, metric aggregation, totals/subtotals, formats, filters, sorting, and cell/series limits
  • persisted pivot_table_state for the Rows, Column Labels, and Values side-panel buckets
  • unsupported time-comparison fields are intentionally omitted until the Preset visualization consumes them, preventing false-success chart generation
  • schema discovery and examples, generated names, capabilities/semantics, and tabular chart-data handling
  • update/preview preservation of UI-managed AG Grid state while replacing declarative grouping and aggregation state
  • fail-closed availability through Preset's AG_GRID_PIVOT_TABLE_ENABLED feature flag plus the existing MCP plugin filter, so OSS-only deployments do not advertise an unavailable visualization

This implements the supported Interactive Pivot portion of SC-113786 and records the true AG Grid pivot as distinct from the OSS Pivot Table V2 delivered under SC-100129. Time comparison remains a visualization-side prerequisite: the Preset plugin does not consume time_compare or comparison_type, so the MCP does not advertise those controls.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Not applicable. This changes MCP schemas and form-data generation; it does not add or modify UI components.

TESTING INSTRUCTIONS

  1. Enable AG_GRID_PIVOT_TABLE_ENABLED on a host that registers Preset's Interactive Pivot plugin.
  2. Call get_chart_type_schema("interactive_pivot") and verify the schema and examples are returned.
  3. Generate an Interactive Pivot with rows, columns, metrics, and totals; verify the Explore URL uses viz_type=ag-grid-pivot-table and its persisted grid state populates the AG Grid side-panel buckets.
  4. Update an existing Interactive Pivot and verify its concrete viz type remains ag-grid-pivot-table and UI-managed grid state such as sizing/filter/sort state is retained.
  5. Disable the feature flag and verify schema discovery and generation return DISABLED_CHART_TYPE rather than offering a broken chart.

Automated validation run:

PYTHONPATH="$PWD/superset-core/src:$PWD" pytest -q tests/unit_tests/mcp_service/chart
# 1307 passed on the original reviewed PR

PYTHONPATH="$PWD/superset-core/src:$PWD" pytest -q \
  tests/unit_tests/mcp_service/chart/test_interactive_pivot_chart.py \
  tests/unit_tests/mcp_service/chart/test_chart_utils.py \
  tests/unit_tests/mcp_service/chart/tool/test_get_chart_type_schema.py \
  tests/unit_tests/mcp_service/chart/tool/test_update_chart_preview.py
# 227 passed after rebasing onto the latest apache/superset master

pre-commit run --from-ref origin/master --to-ref HEAD
# Passed

ADDITIONAL INFORMATION

  • Has associated issue: SC-113786
  • Required feature flags: AG_GRID_PIVOT_TABLE_ENABLED
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

AI behavior / evaluation evidence

This is a deterministic schema, validation, and form-data mapping change. Unit tests cover schema examples, exact native viz resolution, feature-gated availability, validation, omission of unsupported comparison fields, side-panel state, update/preview preservation, capabilities, and generated naming. No model prompt, routing, retrieval, or sampling behavior changes.

Cost and latency

No additional model calls or network requests are introduced. Availability checks are in-process feature-flag lookups; chart mapping remains deterministic and local.

@dosubot dosubot Bot added change:backend Requires changing the backend viz:charts:pivot Related to the Pivot Table charts labels Aug 24, 2026
@bito-code-review

bito-code-review Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #851990

Actionable Suggestions - 0
Additional Suggestions - 4
  • superset/mcp_service/chart/validation/schema_validator.py - 2
    • Missing translation function wrapper · Line 187-187
      Wrap the `message`, `details`, and each suggestion string in this error block with `t()` for i18n support, and add the corresponding `import` for the translation function.
    • Translation consistency for new suggestion · Line 134-135
      The new suggestion line 135 'Use 'interactive_pivot' only when schema discovery exposes it' added to the missing_chart_type error must also be wrapped with translation function per BITO.md rule [6516] to maintain consistency with translation requirements.
  • superset/mcp_service/chart/schemas.py - 1
    • Missing test for normalization mapping · Line 2235-2235
      The `_normalize_chart_request_input` function at line 2240 now handles `ag-grid-pivot-table` normalization, but lacks direct unit test coverage. Add a test case in `test_chart_utils.py` that validates the viz_type-to-chart_type mapping for this entry.
  • tests/unit_tests/mcp_service/chart/test_chart_utils.py - 1
    • Missing asymmetric viz_type test · Line 238-252
      Add test case for asymmetric viz_type mismatch — when existing is NOT ag-grid-pivot-table but updated is — to complete coverage of the guard condition.
Review Details
  • Files reviewed - 20 · Commit Range: 65e31ae..f41ad6d
    • docs/docs/using-superset/using-ai-with-superset.mdx
    • superset/mcp_service/app.py
    • superset/mcp_service/chart/chart_utils.py
    • superset/mcp_service/chart/plugin.py
    • superset/mcp_service/chart/plugins/__init__.py
    • superset/mcp_service/chart/plugins/interactive_pivot.py
    • superset/mcp_service/chart/registry.py
    • superset/mcp_service/chart/resources/chart_configs.py
    • superset/mcp_service/chart/schemas.py
    • superset/mcp_service/chart/tool/generate_chart.py
    • superset/mcp_service/chart/tool/get_chart_data.py
    • superset/mcp_service/chart/tool/get_chart_type_schema.py
    • superset/mcp_service/chart/tool/update_chart.py
    • superset/mcp_service/chart/tool/update_chart_preview.py
    • superset/mcp_service/chart/validation/schema_validator.py
    • tests/unit_tests/mcp_service/chart/test_chart_utils.py
    • tests/unit_tests/mcp_service/chart/test_interactive_pivot_chart.py
    • tests/unit_tests/mcp_service/chart/test_registry_filters.py
    • tests/unit_tests/mcp_service/chart/tool/test_get_chart_type_schema.py
    • tests/unit_tests/mcp_service/chart/tool/test_update_chart_preview.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 an incremental AI Review.

  • /review full - 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

@github-actions github-actions Bot added the doc Namespace | Anything related to documentation label Aug 24, 2026
@aminghadersohi

Copy link
Copy Markdown
Contributor Author

This recreates #43268 after its head repository was removed. The implementation and review fixes are unchanged, with the branch updated onto the latest apache/superset:master. Re-requesting review because GitHub could not reopen the original approved PR.

@netlify

netlify Bot commented Aug 24, 2026

Copy link
Copy Markdown

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit f41ad6d
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6a8c8a2dee0851000939d81b
😎 Deploy Preview https://deploy-preview-43480--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.

Comment on lines +95 to +100
if config.time_grain:
# Preset's hidden temporal_columns_lookup control identifies temporal
# dimensions in groupby, and its buildQuery applies this grain to each
# one. A single granularity_sqla is neither required nor sufficient for
# a pivot that can contain multiple temporal dimensions.
form_data["time_grain_sqla"] = config.time_grain.value

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.

Suggestion: The pivot state never identifies which grouped dimensions are temporal: setting only time_grain_sqla is insufficient because the form data does not include granularity_sqla or temporal_columns_lookup. As a result, time_grain is ignored or cannot be applied to the intended row/column dimensions, so generated pivots with temporal grouping do not honor the requested grain. [logic error]

Severity Level: Major ⚠️
- ⚠️ Interactive Pivot temporal grouping can ignore requested grain.
- ⚠️ Generated pivot rows or columns may use raw timestamps.
- ❌ Time-based pivot analysis can return incorrect aggregation buckets.

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset/mcp_service/chart/plugins/interactive_pivot.py
**Line:** 95:100
**Comment:**
	*Logic Error: The pivot state never identifies which grouped dimensions are temporal: setting only `time_grain_sqla` is insufficient because the form data does not include `granularity_sqla` or `temporal_columns_lookup`. As a result, `time_grain` is ignored or cannot be applied to the intended row/column dimensions, so generated pivots with temporal grouping do not honor the requested grain.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@bito-code-review

Copy link
Copy Markdown
Contributor

The flagged issue is correct. In superset/mcp_service/chart/plugins/interactive_pivot.py, the map_interactive_pivot_config function sets time_grain_sqla but fails to populate the temporal_columns_lookup control, which is required by the pivot table to identify which dimensions in the groupby list are temporal and should have the grain applied.

To resolve this, you should update map_interactive_pivot_config to populate temporal_columns_lookup with the names of the temporal columns present in the rows and columns lists. This ensures the pivot table correctly applies the time_grain_sqla to the intended dimensions.

Would you like me to implement this fix and check the rest of the PR comments for other issues?

superset/mcp_service/chart/plugins/interactive_pivot.py

if config.time_grain:
        form_data["time_grain_sqla"] = config.time_grain.value
        # Identify temporal dimensions for the pivot table
        temporal_cols = [col.name for col in config.rows + config.columns if col.is_temporal]
        form_data["temporal_columns_lookup"] = {col: True for col in temporal_cols}

Comment on lines +1147 to +1150
series_limit_metric: ColumnRef | None = Field(
None,
description="Metric used to rank series when a series/cell limit applies",
)

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.

Suggestion: The series_limit_metric field accepts any ColumnRef, including a plain dimension with no aggregate or saved-metric marker. map_interactive_pivot_config then passes it to create_metric_object, which defaults such a reference to SUM(column). A request such as {"name": "region"} therefore becomes a series-ranking metric of SUM(region), potentially producing an invalid SQL aggregation or ranking by unintended values. Require this reference to represent a metric (an aggregate, saved metric, or SQL expression) before accepting it. [api mismatch]

Severity Level: Major ⚠️
- ❌ Interactive Pivot generation can fail for nonnumeric ranking dimensions.
- ⚠️ Numeric dimensions may rank series by unintended SUM values.
- ⚠️ Series limiting produces incorrect user-visible pivot results.

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset/mcp_service/chart/schemas.py
**Line:** 1147:1150
**Comment:**
	*Api Mismatch: The `series_limit_metric` field accepts any `ColumnRef`, including a plain dimension with no aggregate or saved-metric marker. `map_interactive_pivot_config` then passes it to `create_metric_object`, which defaults such a reference to `SUM(column)`. A request such as `{"name": "region"}` therefore becomes a series-ranking metric of `SUM(region)`, potentially producing an invalid SQL aggregation or ranking by unintended values. Require this reference to represent a metric (an aggregate, saved metric, or SQL expression) before accepting it.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@codecov

codecov Bot commented Aug 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 70.62500% with 47 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.91%. Comparing base (c980b3a) to head (f41ad6d).

Files with missing lines Patch % Lines
...set/mcp_service/chart/plugins/interactive_pivot.py 59.09% 31 Missing and 5 partials ⚠️
superset/mcp_service/chart/registry.py 50.00% 4 Missing and 1 partial ⚠️
...erset/mcp_service/chart/resources/chart_configs.py 0.00% 4 Missing ⚠️
superset/mcp_service/chart/schemas.py 93.93% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #43480      +/-   ##
==========================================
- Coverage   78.92%   78.91%   -0.01%     
==========================================
  Files        2878     2879       +1     
  Lines      165088   165246     +158     
  Branches    38137    38168      +31     
==========================================
+ Hits       130296   130411     +115     
- Misses      32342    32381      +39     
- Partials     2450     2454       +4     
Flag Coverage Δ
hive 38.01% <33.75%> (-0.01%) ⬇️
mysql 57.72% <33.75%> (-0.05%) ⬇️
postgres 57.75% <33.75%> (-0.05%) ⬇️
presto 39.93% <33.75%> (-0.02%) ⬇️
python 83.59% <70.62%> (-0.03%) ⬇️
sqlite 57.44% <33.75%> (-0.05%) ⬇️
unit 73.66% <70.62%> (-0.01%) ⬇️

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.

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

Thanks for recreating this cleanly after the fork mishap, Amin. I verified the recreation rather than assuming it: I diffed all 20 changed files at f41ad6d against the content I approved on #43268 at 895af43, and the PR delta is line for line identical at both bases; the only differences are master drift the merge brought in. The approved history is preserved in the branch, the body carries the corrected time-comparison notes, tests/unit_tests/mcp_service/chart passes locally at this head (1,311 tests), and CI is green. Same content, same verdict. LGTM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:backend Requires changing the backend doc Namespace | Anything related to documentation size/XXL viz:charts:pivot Related to the Pivot Table charts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants