Skip to content

feat(mcp): add manage_native_filters tool#40960

Open
aminghadersohi wants to merge 1 commit into
apache:masterfrom
aminghadersohi:mcp-manage-native-filters
Open

feat(mcp): add manage_native_filters tool#40960
aminghadersohi wants to merge 1 commit into
apache:masterfrom
aminghadersohi:mcp-manage-native-filters

Conversation

@aminghadersohi

Copy link
Copy Markdown
Contributor

SUMMARY

Adds a new MCP tool, manage_native_filters, to the Superset MCP service. Native filters are what make dashboards interactive; the MCP server could previously read them (via get_dashboard_info) but not write them.

The tool exposes four operations on a dashboard's native filters, translated into the deleted / modified / reordered payload consumed by the existing UpdateDashboardNativeFiltersCommand (the same command behind the PUT /api/v1/dashboard/{pk}/filters endpoint):

  • add — create new filters from strict Pydantic specs (no raw JSON configs). v1 supports filter_select (dropdown: dataset + column target, multiSelect, defaultToFirstItem, enableEmptyFilter, sortAscending, searchAllOptions) and filter_time (time range with optional default). Other filter types (numerical range, time column, time grain) are documented as not yet supported.
  • update — partial updates addressed by filter ID. Because the backend command substitutes whole config entries (it does not merge deltas), the tool reads the dashboard's current native_filter_configuration and merges changes into FULL filter configs. Type-incompatible fields (e.g. default_time_range on a filter_select) are rejected.
  • remove — delete filters by ID (unknown IDs produce a descriptive error listing valid IDs).
  • reorder — complete ordered ID list. The DAO silently drops any surviving filter missing from the reordered list, so the tool validates the list covers every remaining filter; newly added filters are appended automatically.

Design notes:

  • Filter IDs are server-generated as NATIVE_FILTER-<random>, matching the frontend's generateFilterId convention, and returned in the response (added_filter_ids).
  • New filter configs follow the frontend Filter type shape: {id, type: "NATIVE_FILTER", filterType, name, description, scope, targets, controlValues, defaultDataMask, cascadeParentIds}.
  • Optional scope_chart_ids per filter is translated into the frontend's exclusion-list scope ({rootPath: ["ROOT_ID"], excluded: [...]}); IDs not on the dashboard are rejected. When omitted, the filter applies to all charts.
  • Dataset and column targets are validated via DatasetDAO with an error that lists available columns so LLM callers can self-correct.
  • Decorated with tags=["mutate"], class_permission_name="Dashboard", method_permission_name="write", and ToolAnnotations(readOnlyHint=False, destructiveHint=True) since remove deletes filters. DashboardForbiddenError / TagForbiddenError surface as structured permission_denied responses.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

N/A — MCP service only, no UI changes.

TESTING INSTRUCTIONS

  1. pytest tests/unit_tests/mcp_service/dashboard/tool/test_manage_native_filters.py
  2. Or manually: start the MCP service, then call manage_native_filters with e.g. {"dashboard_id": 1, "add": [{"filter_type": "filter_select", "name": "Region", "dataset_id": 5, "column": "region"}]} and verify the filter appears on the dashboard's filter bar; exercise update, remove, and reorder similarly.

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • 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

@codecov

codecov Bot commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 35.02304% with 141 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.33%. Comparing base (f79a88c) to head (5bd5c9a).
⚠️ Report is 19 commits behind head on master.

Files with missing lines Patch % Lines
...cp_service/dashboard/tool/manage_native_filters.py 15.62% 135 Missing ⚠️
superset/mcp_service/dashboard/schemas.py 89.28% 6 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #40960      +/-   ##
==========================================
+ Coverage   64.19%   64.33%   +0.14%     
==========================================
  Files        2655     2658       +3     
  Lines      143925   145679    +1754     
  Branches    33181    33504     +323     
==========================================
+ Hits        92386    93719    +1333     
- Misses      49919    50283     +364     
- Partials     1620     1677      +57     
Flag Coverage Δ
hive 39.75% <35.02%> (+0.29%) ⬆️
mysql 58.64% <35.02%> (+0.45%) ⬆️
postgres 58.71% <35.02%> (+0.45%) ⬆️
presto 41.37% <35.02%> (+0.33%) ⬆️
python 60.14% <35.02%> (+0.41%) ⬆️
sqlite 58.34% <35.02%> (+0.46%) ⬆️
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.

@aminghadersohi aminghadersohi marked this pull request as ready for review June 12, 2026 21:22
@aminghadersohi aminghadersohi requested a review from eschutho June 12, 2026 21:24
@bito-code-review

bito-code-review Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #13a2f1

Actionable Suggestions - 0
Additional Suggestions - 2
  • superset/mcp_service/dashboard/tool/manage_native_filters.py - 1
    • Dead exception handler · Line 411-417
      The `except DashboardNotFoundError:` handler at line 411 is unreachable. `DashboardDAO.find_by_id` (line 361) delegates to `_find_by_column` in `superset/daos/base.py:313`, which calls `query.filter(...).one_or_none()` and returns `None` — it never raises `DashboardNotFoundError`. The only DAO method that raises this exception is `get_by_id_or_slug` (used elsewhere), not `find_by_id`. The not-found case is already handled by the `if not dashboard:` guard at line 362.
      Code suggestion
      --- a/superset/mcp_service/dashboard/tool/manage_native_filters.py
      +++ b/superset/mcp_service/dashboard/tool/manage_native_filters.py
       @@ -347,7 +347,6 @@ def manage_native_filters(
            from superset.commands.dashboard.exceptions import (
                DashboardForbiddenError,
                DashboardInvalidError,
      -        DashboardNativeFiltersUpdateFailedError,
      -        DashboardNotFoundError,
      +        DashboardNativeFiltersUpdateFailedError,
            )
            from superset.commands.dashboard.update import (
                UpdateDashboardNativeFiltersCommand,
       @@ -408,13 +407,6 @@ def manage_native_filters(
                    removed_filter_ids=list(request.remove),
                    filters=[_filter_summary(conf) for conf in configuration],
                )
      -
      -    except DashboardNotFoundError:
      -        return ManageNativeFiltersResponse(
      -            error=(
      -                f"Dashboard with ID {request.dashboard_id} not found."
      -                " Use list_dashboards to get valid dashboard IDs."
      -            ),
      -        )
            except DashboardForbiddenError:
  • tests/unit_tests/mcp_service/dashboard/tool/test_manage_native_filters.py - 1
    • Unused import · Line 44-44
      This import is unused — all error-case tests inject exceptions directly via `patch(COMMAND_PATH, side_effect=)` rather than catching the exception class. Remove it to eliminate dead code and avoid misleading readers.
      Code suggestion
      --- a/tests/unit_tests/mcp_service/dashboard/tool/test_manage_native_filters.py
      +++ b/tests/unit_tests/mcp_service/dashboard/tool/test_manage_native_filters.py
       @@ -41,7 +41,6 @@ import pytest
        from fastmcp import Client
       
      -from superset.commands.dashboard.exceptions import DashboardForbiddenError
        from superset.mcp_service.app import mcp
        from superset.utils import json
Review Details
  • Files reviewed - 5 · Commit Range: 5bd5c9a..5bd5c9a
    • superset/mcp_service/app.py
    • superset/mcp_service/dashboard/schemas.py
    • superset/mcp_service/dashboard/tool/__init__.py
    • superset/mcp_service/dashboard/tool/manage_native_filters.py
    • tests/unit_tests/mcp_service/dashboard/tool/test_manage_native_filters.py
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ 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

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant