Skip to content

Conversation

@villebro
Copy link
Member

@villebro villebro commented Nov 18, 2025

SUMMARY

This moves the @mcp.tool, @mcp.prompt and @mcp_auth_hook decorators into superset-core, and replaces them with unified @tool and @prompt decorators that can be used for both authed and un-authed tools/prompts. We roll out the new decorators on all current implementations, and make it possible to add new tools/prompts in extensions (these get discovered during startup by the MCP Server). We also add a new section for MCP tools in the Developer Portal and test the example locally to make sure it works (see screenshot).

Some key changes:

  • Merged @mcp.tool and @mcp_auth_hook into a new @tool decorator with an optional protect: bool parameter to align with the @protect decorator used for REST API endpoints. This can be used both within the host application and extensions.
  • Merged @mcp.prompt and @mcp_auth_hook into a new @prompt with a similar signature as @tool.
  • Replaced all instances of @mcp.tool and @mcp_auth_hook with the new @tool from superset-core
  • Replaced all instances of @mcp.prompt and @mcp_auth_hook with the new @prompt from superset-core
  • Updated initialization logic to always perform superset_core.api dependency injection, irrespective of ENABLE_EXTENSIONS feature flag, as the public API is now being used in the host codebase.
  • Added docs on the new MCP functionality to developer portal.
  • Added pydantic as a dependency to superset-core to explicitly support MCP tool schema validation. Rebuilt the requirements/*.txt files as per the new superset-core dependencies.
  • Changed mode on run_proxy.sh from -rw-r--r-- to -rwxr-xr-x to make it executable

SCREENSHOTS

Here's a screenshot of one of the example tools from the docs in action. You can see the extension code (left) and using Roo Code to call the Superset MCP (right):
image

Here's the startup logs for the MCP Server (notice how it's registering the example_extension.random_number tool towards the end, and how it's showint that they are protected and not public):

$ superset mcp run --port 5008 --debug
Loaded your LOCAL configuration at [/Users/ville/pythonpath/superset_config.py]
2025-11-19 11:45:50,966:DEBUG:superset.utils.logging_configurator:logging was configured successfully
2025-11-19 11:45:50,970:DEBUG:root:Configured event logger of type <class 'superset.utils.log.DBEventLogger'>
2025-11-19 11:45:51,167:INFO:alembic.runtime.migration:Context impl SQLiteImpl.
2025-11-19 11:45:51,167:INFO:alembic.runtime.migration:Will assume non-transactional DDL.
2025-11-19 11:45:51,294:DEBUG:superset.app:Pending migrations. Current: c233f5365c9e, Head: x2s8ocx6rto6
2025-11-19 11:45:51,294:INFO:superset.app:Pending database migrations: run 'superset db upgrade'
2025-11-19 11:45:51,529:INFO:superset.core.mcp.core_mcp_injection:MCP dependency injection initialized successfully
2025-11-19 11:45:51,529:INFO:superset.extensions.utils:Loading extension Hello World (ID: helloworld) from local filesystem
2025-11-19 11:45:51,656:DEBUG:mcp.server.lowlevel.server:Initializing server 'Superset MCP Server'
2025-11-19 11:45:51,656:DEBUG:mcp.server.lowlevel.server:Registering handler for ListToolsRequest
2025-11-19 11:45:51,656:DEBUG:mcp.server.lowlevel.server:Registering handler for ListResourcesRequest
2025-11-19 11:45:51,656:DEBUG:mcp.server.lowlevel.server:Registering handler for ListResourceTemplatesRequest
2025-11-19 11:45:51,656:DEBUG:mcp.server.lowlevel.server:Registering handler for PromptListRequest
2025-11-19 11:45:51,656:DEBUG:mcp.server.lowlevel.server:Registering handler for CallToolRequest
2025-11-19 11:45:51,656:DEBUG:mcp.server.lowlevel.server:Registering handler for ReadResourceRequest
2025-11-19 11:45:51,656:DEBUG:mcp.server.lowlevel.server:Registering handler for GetPromptRequest
/Users/ville/projects/superset/venv/lib/python3.10/site-packages/fastmcp/server/server.py:213: DeprecationWarning: Providing `stateless_http` when creating a server is deprecated. Provide it when calling `run` or as a global setting instead.
  self._handle_deprecated_settings(
2025-11-19 11:45:51,657:INFO:superset.mcp_service.app:Created FastMCP instance: Superset MCP Server
2025-11-19 11:45:51,657:INFO:superset.core.mcp.core_mcp_injection:Registered MCP prompt: create_chart_guided (protected)
2025-11-19 11:45:51,693:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: generate_chart (protected)
2025-11-19 11:45:51,694:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: get_chart_available_filters (protected)
2025-11-19 11:45:51,699:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: get_chart_data (protected)
2025-11-19 11:45:51,705:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: get_chart_info (protected)
2025-11-19 11:45:51,713:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: get_chart_preview (protected)
2025-11-19 11:45:51,718:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: list_charts (protected)
2025-11-19 11:45:51,728:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: update_chart (protected)
2025-11-19 11:45:51,731:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: update_chart_preview (protected)
2025-11-19 11:45:51,743:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: add_chart_to_existing_dashboard (protected)
2025-11-19 11:45:51,749:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: generate_dashboard (protected)
2025-11-19 11:45:51,749:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: get_dashboard_available_filters (protected)
2025-11-19 11:45:51,760:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: get_dashboard_info (protected)
2025-11-19 11:45:51,767:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: list_dashboards (protected)
2025-11-19 11:45:51,774:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: get_dataset_available_filters (protected)
2025-11-19 11:45:51,783:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: get_dataset_info (protected)
2025-11-19 11:45:51,790:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: list_datasets (protected)
2025-11-19 11:45:51,793:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: generate_explore_link (protected)
2025-11-19 11:45:51,797:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: execute_sql (protected)
2025-11-19 11:45:51,798:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: open_sql_lab_with_context (protected)
2025-11-19 11:45:51,798:INFO:superset.core.mcp.core_mcp_injection:Registered MCP prompt: superset_quickstart (protected)
2025-11-19 11:45:51,801:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: get_instance_info (protected)
2025-11-19 11:45:51,802:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: health_check (protected)
2025-11-19 11:45:51,802:INFO:superset.core.mcp.core_mcp_injection:Registered MCP tool: example_extension.random_number (protected)
Hello World extension registered
2025-11-19 11:45:51,803:INFO:root:🔍 SQL Debug logging enabled
2025-11-19 11:45:51,803:INFO:root:Creating MCP app with default configuration...
2025-11-19 11:45:51,804:INFO:superset.mcp_service.flask_singleton:Creating Flask app instance for MCP service
2025-11-19 11:45:51,804:INFO:superset.core.mcp.core_mcp_injection:MCP dependency injection initialized successfully
2025-11-19 11:45:51,804:INFO:superset.mcp_service.flask_singleton:Core dependencies and extensions initialized for MCP service
2025-11-19 11:45:51,804:INFO:superset.mcp_service.flask_singleton:Minimal Flask app instance created successfully for MCP service
2025-11-19 11:45:51,804:INFO:superset.mcp_service.app:Using default FastMCP instance - scaffold version without auth
2025-11-19 11:45:51,804:INFO:root:Starting FastMCP on 127.0.0.1:5008
2025-11-19 11:45:51,805:INFO:superset.extensions.local_extensions_watcher:Watching LOCAL_EXTENSIONS dist directory: /Users/ville/projects/superset-extensions/helloworld/dist
2025-11-19 11:45:51,806:DEBUG:asyncio:Using selector: KqueueSelector

TESTING INSTRUCTIONS

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

@bito-code-review
Copy link
Contributor

bito-code-review bot commented Nov 18, 2025

Code Review Agent Run #7c88d9

Actionable Suggestions - 0
Additional Suggestions - 14
  • superset/core/mcp/core_mcp_injection.py - 5
    • Use logging.exception instead of error · Line 71-71
      Use `logging.exception` instead of `logging.error` to automatically include exception traceback information.
      Code suggestion
       @@ -70,2 +70,2 @@
      -        except Exception as e:
      -            logger.error("Failed to register MCP tool %s: %s", name, e)
      +        except Exception as e:
      +            logger.exception("Failed to register MCP tool %s: %s", name, e)
    • Multi-line docstring summary formatting issue · Line 18-18
      Multi-line docstring summary should start at the first line. There are 3 similar docstring formatting issues in this file (lines 18, 34, 46).
      Code suggestion
       @@ -17,6 +17,5 @@
      -
      -"""
      -MCP core dependency injection for direct import patterns.
      -
      -This module provides the concrete implementation of MCP tool registration
      -that replaces the abstract functions in superset-core during initialization.
      -"""
      +
      +"""MCP core dependency injection for direct import patterns.
      +
      +This module provides the concrete implementation of MCP tool registration
      +that replaces the abstract functions in superset-core during initialization.
      +"""
    • Import Callable from collections.abc instead · Line 28-28
      Import `Callable` from `collections.abc` instead of `typing` for Python 3.9+ compatibility.
      Code suggestion
       @@ -27,2 +27,2 @@
      -import logging
      -from typing import Any, Callable
      +import logging
      +from collections.abc import Callable
      +from typing import Any
    • Unused function argument tags parameter · Line 44-44
      Unused function argument `tags`. Consider removing it or prefixing with underscore if required by interface. Also missing trailing comma on this line.
      Code suggestion
       @@ -43,2 +43,2 @@
      -    def concrete_mcp_tool(
      -        name: str, func: Callable[..., Any], description: str, tags: list[str]
      +    def concrete_mcp_tool(
      +        name: str, func: Callable[..., Any], description: str, _tags: list[str],
    • Missing blank line after docstring section · Line 49-49
      Missing blank line after last docstring section ("Args"). Add a blank line before the closing quotes.
      Code suggestion
       @@ -52,2 +52,3 @@
      -            description: Human-readable description of the tool's purpose
      -            tags: List of tags for categorizing the tool
      +            description: Human-readable description of the tool's purpose
      +            tags: List of tags for categorizing the tool
      +
  • superset-core/src/superset_core/mcp/__init__.py - 5
    • Deprecated import from typing module · Line 36-36
      Import `Callable` from `collections.abc` instead of `typing` for better compatibility with Python 3.9+.
      Code suggestion
       @@ -36,1 +36,1 @@
      -from typing import Any, Callable
      +from collections.abc import Callable
      +from typing import Any
    • Multi-line docstring summary formatting issue · Line 18-18
      Multi-line docstring summary should start at the first line. Move the opening summary text to the same line as the triple quotes. This issue also occurs at line 45.
      Code suggestion
       @@ -18,3 +18,2 @@
      -"""
      -MCP (Model Context Protocol) tool registration for Superset extensions.
      -
      +"""MCP (Model Context Protocol) tool registration for Superset extensions.
      +
    • Function docstring summary formatting issue · Line 45-45
      Multi-line docstring summary should start at the first line. Move the opening summary text to the same line as the triple quotes.
      Code suggestion
       @@ -45,3 +45,2 @@
      -    """
      -    Register an MCP tool with the host application.
      -
      +    """Register an MCP tool with the host application.
      +
    • Missing blank line after docstring section · Line 60-60
      Missing blank line after the last docstring section ("Example"). Add a blank line before the closing triple quotes.
      Code suggestion
       @@ -67,2 +67,3 @@
      -            return {"result": "success"}
      -    """
      +            return {"result": "success"}
      +
      +    """
    • Exception string literal should be variable · Line 69-69
      Exception should not use a string literal directly. Assign the message to a variable first for better maintainability.
      Code suggestion
       @@ -69,1 +69,2 @@
      -    raise NotImplementedError("Function will be replaced during initialization")
      +    msg = "Function will be replaced during initialization"
      +    raise NotImplementedError(msg)
  • tests/unit_tests/mcp_service/test_mcp_tool_registration.py - 4
    • Missing return type annotation for function · Line 25-25
      Function `test_initialize_mcp_dependencies_replaces_abstract_function` is missing return type annotation. Add `-> None` to the function signature. Similar issue exists on line 40.
      Code suggestion
       @@ -25,1 +25,1 @@
      -def test_initialize_mcp_dependencies_replaces_abstract_function():
      +def test_initialize_mcp_dependencies_replaces_abstract_function() -> None:
    • Missing trailing comma in function call · Line 31-31
      Missing trailing comma after `mock_mcp_module` parameter. Add trailing comma for consistency. Similar issue exists on line 49 and 71.
      Code suggestion
       @@ -31,1 +31,1 @@
      -        "superset.core.mcp.core_mcp_injection.superset_core.mcp", mock_mcp_module
      +        "superset.core.mcp.core_mcp_injection.superset_core.mcp", mock_mcp_module,
    • Nested with statements should be combined · Line 48-48
      Use a single `with` statement with multiple contexts instead of nested `with` statements for better readability.
      Code suggestion
       @@ -48,4 +48,2 @@
      -    with patch(
      -        "superset.core.mcp.core_mcp_injection.superset_core.mcp", mock_mcp_module,
      -    ):
      -        with patch("superset.mcp_service.app.mcp", mock_fastmcp):
      +    with patch(
      +        "superset.core.mcp.core_mcp_injection.superset_core.mcp", mock_mcp_module,
      +    ), patch("superset.mcp_service.app.mcp", mock_fastmcp):
    • Missing return type annotation for function · Line 59-59
      Inner function `test_tool` is missing return type annotation. Add `-> dict[str, str]` to the function signature.
      Code suggestion
       @@ -59,1 +59,1 @@
      -            def test_tool():
      +            def test_tool() -> dict[str, str]:
Review Details
  • Files reviewed - 5 · Commit Range: 1e63247..62a7fc5
    • superset-core/pyproject.toml
    • superset-core/src/superset_core/mcp/__init__.py
    • superset/core/mcp/core_mcp_injection.py
    • superset/initialization/__init__.py
    • tests/unit_tests/mcp_service/test_mcp_tool_registration.py
  • Files skipped - 1
    • docs/developer_portal/extensions/mcp-tools.md - Reason: Filter setting
  • 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 Default Agent You can customize the agent settings here or contact your Bito workspace admin at [email protected].

Documentation & Help

AI Code Review powered by Bito Logo

@github-actions github-actions bot added the doc Namespace | Anything related to documentation label Nov 18, 2025
Copy link

@korbit-ai korbit-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've completed my review and didn't find any issues.

Files scanned
File Path Reviewed
superset-core/src/superset_core/mcp/init.py
superset/core/mcp/core_mcp_injection.py
superset/initialization/init.py

Explore our documentation to understand the languages and file types we support and the files we ignore.

Check out our docs on how you can make Korbit work best for you and your team.

Loving Korbit!? Share us on LinkedIn Reddit and X

@codecov
Copy link

codecov bot commented Nov 18, 2025

Codecov Report

❌ Patch coverage is 18.36735% with 80 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.25%. Comparing base (76d897e) to head (229bd5f).
⚠️ Report is 2962 commits behind head on master.

Files with missing lines Patch % Lines
superset/core/mcp/core_mcp_injection.py 17.14% 58 Missing ⚠️
superset/mcp_service/flask_singleton.py 0.00% 8 Missing ⚠️
superset/initialization/__init__.py 75.00% 1 Missing and 1 partial ⚠️
.../mcp_service/explore/tool/generate_explore_link.py 0.00% 2 Missing ⚠️
superset/mcp_service/sql_lab/tool/execute_sql.py 0.00% 2 Missing ⚠️
..._service/sql_lab/tool/open_sql_lab_with_context.py 0.00% 2 Missing ⚠️
superset/mcp_service/system/prompts/quickstart.py 0.00% 2 Missing ⚠️
...erset/mcp_service/system/tool/get_instance_info.py 0.00% 2 Missing ⚠️
superset/mcp_service/system/tool/health_check.py 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #36151      +/-   ##
==========================================
+ Coverage   60.48%   68.25%   +7.76%     
==========================================
  Files        1931      638    -1293     
  Lines       76236    47005   -29231     
  Branches     8568     5060    -3508     
==========================================
- Hits        46114    32081   -14033     
+ Misses      28017    13655   -14362     
+ Partials     2105     1269     -836     
Flag Coverage Δ
hive 43.80% <18.36%> (-5.35%) ⬇️
javascript ?
mysql 67.17% <18.36%> (?)
postgres 67.22% <18.36%> (?)
presto 47.40% <18.36%> (-6.41%) ⬇️
python 68.04% <18.36%> (+4.53%) ⬆️
sqlite 66.84% <18.36%> (?)
superset-extensions-cli 94.80% <ø> (?)
unit 100.00% <ø> (+42.36%) ⬆️

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

☔ View full report in Codecov by Sentry.
📢 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.

@sadpandajoe sadpandajoe marked this pull request as draft November 18, 2025 18:22
@villebro villebro marked this pull request as ready for review November 18, 2025 23:41
@dosubot dosubot bot added the change:backend Requires changing the backend label Nov 18, 2025
Comment on lines -292 to +299
- Do NOT import `Optional` from typing
- Still import `List`, `Dict`, `Any`, etc. from typing (for now)
- Do NOT import `Optional`, `List`, `Dict` from typing, prefer `| None`, `list[]` etc
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bycatch, I think we've moved from List[] to list[] some time ago.

@villebro villebro force-pushed the villebro/mcp-extensions branch from e7caafa to 50a2ae8 Compare November 19, 2025 20:05
@villebro villebro changed the title feat: add mcp tool abstractions to core feat: add mcp abstractions to core Nov 19, 2025
@michael-s-molina michael-s-molina moved this from TODO to In progress in Superset Extensions Nov 25, 2025
@michael-s-molina michael-s-molina moved this from In progress to In review in Superset Extensions Nov 25, 2025
Copy link
Member

@michael-s-molina michael-s-molina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work @villebro! I left some non-blocking comments that would be nice to address before merging but overall LGTM.


@mcp.prompt("create_chart_guided")
@mcp_auth_hook
@prompt("create_chart_guided")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# Files still using @mcp.resource + @mcp_auth_hook:
- superset/mcp_service/system/resources/instance_metadata.py:30-31
- superset/mcp_service/chart/resources/chart_configs.py:30-31

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are ok for now, as we don't currently need to expose the MCP resource to extension devs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the idea to always use annotations from the core package independently of extensions?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mcp_auth_hook is integrated into @tool and @prompt, but here it's needed here explicitly, as we haven't abstracted @mcp.resource into core as it's not needed yet. But if we do, then we'll replace these with a new @resource that introduces an optional param protect=True.

Comment on lines +34 to +41
def create_tool_decorator(
func_or_name: str | Callable[..., Any] | None = None,
*,
name: Optional[str] = None,
description: Optional[str] = None,
tags: Optional[list[str]] = None,
protect: bool = True,
) -> Callable[[F], F] | F:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# Current:
def create_tool_decorator(...) -> Callable[[F], F] | F:

# Consider using TypeVar for better type inference:
_F = TypeVar("_F", bound=Callable[..., Any])
def create_tool_decorator(...) -> Callable[[_F], _F] | _F:

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I fully understand this change request. But we can improve this in future iterations as needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using overloads preserves the decorated function's exact type signature (parameters and return type), enabling IDEs to provide accurate autocomplete and type checkers to catch errors like passing wrong argument types or mismatching return types.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's chat about this in the next sync. I can follow up on this when we agree on the exact nature of this change.

@villebro villebro merged commit a486007 into apache:master Nov 25, 2025
77 checks passed
@github-project-automation github-project-automation bot moved this from In review to Done in Superset Extensions Nov 25, 2025
LuisSanchez pushed a commit to LuisSanchez/superset that referenced this pull request Nov 25, 2025
aminghadersohi pushed a commit to aminghadersohi/superset that referenced this pull request Nov 25, 2025
kshi020302 pushed a commit to jl141/superset that referenced this pull request Nov 30, 2025
@villebro villebro deleted the villebro/mcp-extensions branch December 1, 2025 19:23
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

Projects

Development

Successfully merging this pull request may close these issues.

4 participants