From 832fee3ff8c084704ac8aacceef31c81d2d17337 Mon Sep 17 00:00:00 2001 From: "Michael S. Molina" <70410625+michael-s-molina@users.noreply.github.com> Date: Wed, 4 Mar 2026 14:38:17 -0300 Subject: [PATCH] refactor(mcp): move superset_core MCP module from mcp to api/mcp (#38394) --- docs/developer_docs/extensions/mcp.md | 6 +++--- .../{mcp/__init__.py => api/mcp.py} | 2 +- superset/core/mcp/core_mcp_injection.py | 8 ++++---- superset/mcp_service/CLAUDE.md | 16 ++++++++-------- superset/mcp_service/app.py | 2 +- .../chart/prompts/create_chart_guided.py | 2 +- .../mcp_service/chart/tool/generate_chart.py | 2 +- .../mcp_service/chart/tool/get_chart_data.py | 2 +- .../mcp_service/chart/tool/get_chart_info.py | 2 +- .../mcp_service/chart/tool/get_chart_preview.py | 2 +- superset/mcp_service/chart/tool/list_charts.py | 2 +- superset/mcp_service/chart/tool/update_chart.py | 2 +- .../chart/tool/update_chart_preview.py | 2 +- .../tool/add_chart_to_existing_dashboard.py | 2 +- .../dashboard/tool/generate_dashboard.py | 2 +- .../dashboard/tool/get_dashboard_info.py | 2 +- .../dashboard/tool/list_dashboards.py | 2 +- .../mcp_service/dataset/tool/get_dataset_info.py | 2 +- .../mcp_service/dataset/tool/list_datasets.py | 2 +- .../explore/tool/generate_explore_link.py | 2 +- superset/mcp_service/sql_lab/tool/execute_sql.py | 2 +- .../sql_lab/tool/open_sql_lab_with_context.py | 2 +- .../mcp_service/system/prompts/quickstart.py | 2 +- .../mcp_service/system/tool/get_instance_info.py | 2 +- superset/mcp_service/system/tool/get_schema.py | 2 +- superset/mcp_service/system/tool/health_check.py | 2 +- 26 files changed, 38 insertions(+), 38 deletions(-) rename superset-core/src/superset_core/{mcp/__init__.py => api/mcp.py} (99%) diff --git a/docs/developer_docs/extensions/mcp.md b/docs/developer_docs/extensions/mcp.md index 5a90dddc9a9..ad9b10e6e85 100644 --- a/docs/developer_docs/extensions/mcp.md +++ b/docs/developer_docs/extensions/mcp.md @@ -61,7 +61,7 @@ Prompts provide interactive guidance and context to AI agents. They help agents The simplest way to create an MCP tool is using the `@tool` decorator: ```python -from superset_core.mcp import tool +from superset_core.api.mcp import tool @tool def hello_world() -> dict: @@ -94,7 +94,7 @@ Here's a more comprehensive example showing best practices: import random from datetime import datetime, timezone from pydantic import BaseModel, Field -from superset_core.mcp import tool +from superset_core.api.mcp import tool class RandomNumberRequest(BaseModel): """Request schema for random number generation.""" @@ -253,7 +253,7 @@ The AI agent sees your tool's: Create interactive prompts using the `@prompt` decorator: ```python -from superset_core.mcp import prompt +from superset_core.api.mcp import prompt from fastmcp import Context @prompt("my_extension.workflow_guide") diff --git a/superset-core/src/superset_core/mcp/__init__.py b/superset-core/src/superset_core/api/mcp.py similarity index 99% rename from superset-core/src/superset_core/mcp/__init__.py rename to superset-core/src/superset_core/api/mcp.py index a5e241eb22a..f413a9ec7e7 100644 --- a/superset-core/src/superset_core/mcp/__init__.py +++ b/superset-core/src/superset_core/api/mcp.py @@ -22,7 +22,7 @@ This module provides a decorator interface to register MCP tools with the host application. Usage: - from superset_core.mcp import tool + from superset_core.api.mcp import tool @tool(name="my_tool", description="Custom business logic", tags=["extension"]) def my_extension_tool(param: str) -> dict: diff --git a/superset/core/mcp/core_mcp_injection.py b/superset/core/mcp/core_mcp_injection.py index 037e9d29e86..0ecde4ff591 100644 --- a/superset/core/mcp/core_mcp_injection.py +++ b/superset/core/mcp/core_mcp_injection.py @@ -207,14 +207,14 @@ def create_prompt_decorator( def initialize_core_mcp_dependencies() -> None: """ Initialize MCP dependency injection by replacing abstract functions - in superset_core.mcp with concrete implementations. + in superset_core.api.mcp with concrete implementations. """ try: - import superset_core.mcp + import superset_core.api.mcp # Replace the abstract decorators with concrete implementations - superset_core.mcp.tool = create_tool_decorator - superset_core.mcp.prompt = create_prompt_decorator + superset_core.api.mcp.tool = create_tool_decorator + superset_core.api.mcp.prompt = create_prompt_decorator logger.info("MCP dependency injection initialized successfully") diff --git a/superset/mcp_service/CLAUDE.md b/superset/mcp_service/CLAUDE.md index f8a3984c6c9..ae905fd35a4 100644 --- a/superset/mcp_service/CLAUDE.md +++ b/superset/mcp_service/CLAUDE.md @@ -80,7 +80,7 @@ superset/mcp_service/ **Example**: ```python # superset/mcp_service/chart/tool/my_new_tool.py -from superset_core.mcp import tool +from superset_core.api.mcp import tool @tool def my_new_tool(param: str) -> dict: @@ -110,7 +110,7 @@ from superset.mcp_service.chart.tool import ( # noqa: F401, E402 **Example**: ```python # superset/mcp_service/chart/prompts/my_new_prompt.py -from superset_core.mcp import prompt +from superset_core.api.mcp import prompt @prompt("my_new_prompt") async def my_new_prompt_handler(ctx: Context) -> str: @@ -180,7 +180,7 @@ The `mcp_core.py` module provides reusable patterns: **Example**: ```python -from superset_core.mcp import tool +from superset_core.api.mcp import tool from superset.mcp_service.mcp_core import ModelListCore from superset.daos.dashboard import DashboardDAO @@ -205,7 +205,7 @@ def list_dashboards(filters: List[DashboardFilter], page: int = 1) -> DashboardL - Audit logging of tool access ```python -from superset_core.mcp import tool +from superset_core.api.mcp import tool @tool # REQUIRED - secure=True by default def my_tool() -> dict: @@ -572,14 +572,14 @@ def my_function(param: Optional[str] = None) -> Optional[int]: **Solution**: Use `@tool` without parentheses unless passing arguments. ```python # GOOD -from superset_core.mcp import tool +from superset_core.api.mcp import tool @tool def my_tool(): pass # BAD -from superset_core.mcp import tool +from superset_core.api.mcp import tool @tool def my_tool(): @@ -588,10 +588,10 @@ def my_tool(): ### 10. ❌ Circular Imports **Problem**: Importing too many things from `app.py` can create circular dependencies. -**Solution**: Use the unified `@tool` decorator from `superset_core.mcp`: +**Solution**: Use the unified `@tool` decorator from `superset_core.api.mcp`: ```python # GOOD - New pattern -from superset_core.mcp import tool +from superset_core.api.mcp import tool @tool def my_tool(): diff --git a/superset/mcp_service/app.py b/superset/mcp_service/app.py index 5db973067e1..1e579a0ee64 100644 --- a/superset/mcp_service/app.py +++ b/superset/mcp_service/app.py @@ -306,7 +306,7 @@ def create_mcp_app( mcp = create_mcp_app() # Initialize MCP dependency injection BEFORE importing tools/prompts -# This replaces the abstract @tool and @prompt decorators in superset_core.mcp +# This replaces the abstract @tool and @prompt decorators in superset_core.api.mcp # with concrete implementations that can register with the mcp instance from superset.core.mcp.core_mcp_injection import ( # noqa: E402 initialize_core_mcp_dependencies, diff --git a/superset/mcp_service/chart/prompts/create_chart_guided.py b/superset/mcp_service/chart/prompts/create_chart_guided.py index 06bca71bbd0..b3fdf2a6f44 100644 --- a/superset/mcp_service/chart/prompts/create_chart_guided.py +++ b/superset/mcp_service/chart/prompts/create_chart_guided.py @@ -19,7 +19,7 @@ Chart prompts for visualization guidance """ -from superset_core.mcp import prompt +from superset_core.api.mcp import prompt @prompt("create_chart_guided") diff --git a/superset/mcp_service/chart/tool/generate_chart.py b/superset/mcp_service/chart/tool/generate_chart.py index 3e241673545..70259381de8 100644 --- a/superset/mcp_service/chart/tool/generate_chart.py +++ b/superset/mcp_service/chart/tool/generate_chart.py @@ -23,7 +23,7 @@ import time from urllib.parse import parse_qs, urlparse from fastmcp import Context -from superset_core.mcp import tool +from superset_core.api.mcp import tool from superset.commands.exceptions import CommandException from superset.extensions import event_logger diff --git a/superset/mcp_service/chart/tool/get_chart_data.py b/superset/mcp_service/chart/tool/get_chart_data.py index 747eb82a579..26af5310d50 100644 --- a/superset/mcp_service/chart/tool/get_chart_data.py +++ b/superset/mcp_service/chart/tool/get_chart_data.py @@ -25,7 +25,7 @@ from typing import Any, Dict, List, TYPE_CHECKING from fastmcp import Context from flask import current_app -from superset_core.mcp import tool +from superset_core.api.mcp import tool if TYPE_CHECKING: from superset.models.slice import Slice diff --git a/superset/mcp_service/chart/tool/get_chart_info.py b/superset/mcp_service/chart/tool/get_chart_info.py index 3b86dcc8675..08e2850cba8 100644 --- a/superset/mcp_service/chart/tool/get_chart_info.py +++ b/superset/mcp_service/chart/tool/get_chart_info.py @@ -23,7 +23,7 @@ import logging from fastmcp import Context from sqlalchemy.orm import subqueryload -from superset_core.mcp import tool +from superset_core.api.mcp import tool from superset.commands.exceptions import CommandException from superset.commands.explore.form_data.parameters import CommandParameters diff --git a/superset/mcp_service/chart/tool/get_chart_preview.py b/superset/mcp_service/chart/tool/get_chart_preview.py index b691f91155b..0b8a51753c9 100644 --- a/superset/mcp_service/chart/tool/get_chart_preview.py +++ b/superset/mcp_service/chart/tool/get_chart_preview.py @@ -23,7 +23,7 @@ import logging from typing import Any, Dict, List, Protocol from fastmcp import Context -from superset_core.mcp import tool +from superset_core.api.mcp import tool from superset.commands.exceptions import CommandException from superset.exceptions import SupersetException diff --git a/superset/mcp_service/chart/tool/list_charts.py b/superset/mcp_service/chart/tool/list_charts.py index 7eccfc5f42e..60d8368d069 100644 --- a/superset/mcp_service/chart/tool/list_charts.py +++ b/superset/mcp_service/chart/tool/list_charts.py @@ -23,7 +23,7 @@ import logging from typing import cast, TYPE_CHECKING from fastmcp import Context -from superset_core.mcp import tool +from superset_core.api.mcp import tool if TYPE_CHECKING: from superset.models.slice import Slice diff --git a/superset/mcp_service/chart/tool/update_chart.py b/superset/mcp_service/chart/tool/update_chart.py index cf6e15b7356..b8739f37a98 100644 --- a/superset/mcp_service/chart/tool/update_chart.py +++ b/superset/mcp_service/chart/tool/update_chart.py @@ -23,7 +23,7 @@ import logging import time from fastmcp import Context -from superset_core.mcp import tool +from superset_core.api.mcp import tool from superset.extensions import event_logger from superset.mcp_service.chart.chart_utils import ( diff --git a/superset/mcp_service/chart/tool/update_chart_preview.py b/superset/mcp_service/chart/tool/update_chart_preview.py index fd8dc680ff1..bf8a98854dd 100644 --- a/superset/mcp_service/chart/tool/update_chart_preview.py +++ b/superset/mcp_service/chart/tool/update_chart_preview.py @@ -24,7 +24,7 @@ import time from typing import Any, Dict from fastmcp import Context -from superset_core.mcp import tool +from superset_core.api.mcp import tool from superset.extensions import event_logger from superset.mcp_service.chart.chart_utils import ( diff --git a/superset/mcp_service/dashboard/tool/add_chart_to_existing_dashboard.py b/superset/mcp_service/dashboard/tool/add_chart_to_existing_dashboard.py index 74730d799b3..dc35ba6cea9 100644 --- a/superset/mcp_service/dashboard/tool/add_chart_to_existing_dashboard.py +++ b/superset/mcp_service/dashboard/tool/add_chart_to_existing_dashboard.py @@ -25,7 +25,7 @@ import logging from typing import Any, Dict from fastmcp import Context -from superset_core.mcp import tool +from superset_core.api.mcp import tool from superset.extensions import event_logger from superset.mcp_service.dashboard.constants import ( diff --git a/superset/mcp_service/dashboard/tool/generate_dashboard.py b/superset/mcp_service/dashboard/tool/generate_dashboard.py index 29cfb61eef0..c2743b374b9 100644 --- a/superset/mcp_service/dashboard/tool/generate_dashboard.py +++ b/superset/mcp_service/dashboard/tool/generate_dashboard.py @@ -25,7 +25,7 @@ import logging from typing import Any, Dict, List from fastmcp import Context -from superset_core.mcp import tool +from superset_core.api.mcp import tool from superset.extensions import event_logger from superset.mcp_service.dashboard.constants import ( diff --git a/superset/mcp_service/dashboard/tool/get_dashboard_info.py b/superset/mcp_service/dashboard/tool/get_dashboard_info.py index 31646db3753..1ea9cac43c8 100644 --- a/superset/mcp_service/dashboard/tool/get_dashboard_info.py +++ b/superset/mcp_service/dashboard/tool/get_dashboard_info.py @@ -27,7 +27,7 @@ from datetime import datetime, timezone from fastmcp import Context from sqlalchemy.orm import subqueryload -from superset_core.mcp import tool +from superset_core.api.mcp import tool from superset.dashboards.permalink.exceptions import DashboardPermalinkGetFailedError from superset.dashboards.permalink.types import DashboardPermalinkValue diff --git a/superset/mcp_service/dashboard/tool/list_dashboards.py b/superset/mcp_service/dashboard/tool/list_dashboards.py index 3d492567374..2c503ea8c3e 100644 --- a/superset/mcp_service/dashboard/tool/list_dashboards.py +++ b/superset/mcp_service/dashboard/tool/list_dashboards.py @@ -26,7 +26,7 @@ import logging from typing import TYPE_CHECKING from fastmcp import Context -from superset_core.mcp import tool +from superset_core.api.mcp import tool if TYPE_CHECKING: from superset.models.dashboard import Dashboard diff --git a/superset/mcp_service/dataset/tool/get_dataset_info.py b/superset/mcp_service/dataset/tool/get_dataset_info.py index 35c963eb2bd..07a5cf4c09f 100644 --- a/superset/mcp_service/dataset/tool/get_dataset_info.py +++ b/superset/mcp_service/dataset/tool/get_dataset_info.py @@ -27,7 +27,7 @@ from datetime import datetime, timezone from fastmcp import Context from sqlalchemy.orm import joinedload, subqueryload -from superset_core.mcp import tool +from superset_core.api.mcp import tool from superset.extensions import event_logger from superset.mcp_service.dataset.schemas import ( diff --git a/superset/mcp_service/dataset/tool/list_datasets.py b/superset/mcp_service/dataset/tool/list_datasets.py index f33d455636d..93f65bf8841 100644 --- a/superset/mcp_service/dataset/tool/list_datasets.py +++ b/superset/mcp_service/dataset/tool/list_datasets.py @@ -26,7 +26,7 @@ import logging from typing import TYPE_CHECKING from fastmcp import Context -from superset_core.mcp import tool +from superset_core.api.mcp import tool if TYPE_CHECKING: from superset.connectors.sqla.models import SqlaTable diff --git a/superset/mcp_service/explore/tool/generate_explore_link.py b/superset/mcp_service/explore/tool/generate_explore_link.py index dca721caa8b..e2a61ac6393 100644 --- a/superset/mcp_service/explore/tool/generate_explore_link.py +++ b/superset/mcp_service/explore/tool/generate_explore_link.py @@ -26,7 +26,7 @@ from typing import Any, Dict from urllib.parse import parse_qs, urlparse from fastmcp import Context -from superset_core.mcp import tool +from superset_core.api.mcp import tool from superset.extensions import event_logger from superset.mcp_service.chart.chart_utils import ( diff --git a/superset/mcp_service/sql_lab/tool/execute_sql.py b/superset/mcp_service/sql_lab/tool/execute_sql.py index d10f700f52e..3afe7d5d361 100644 --- a/superset/mcp_service/sql_lab/tool/execute_sql.py +++ b/superset/mcp_service/sql_lab/tool/execute_sql.py @@ -28,8 +28,8 @@ import logging from typing import Any from fastmcp import Context +from superset_core.api.mcp import tool from superset_core.api.types import CacheOptions, QueryOptions, QueryResult, QueryStatus -from superset_core.mcp import tool from superset.errors import ErrorLevel, SupersetError, SupersetErrorType from superset.exceptions import SupersetErrorException, SupersetSecurityException diff --git a/superset/mcp_service/sql_lab/tool/open_sql_lab_with_context.py b/superset/mcp_service/sql_lab/tool/open_sql_lab_with_context.py index e702994c22b..440ed94dc07 100644 --- a/superset/mcp_service/sql_lab/tool/open_sql_lab_with_context.py +++ b/superset/mcp_service/sql_lab/tool/open_sql_lab_with_context.py @@ -25,7 +25,7 @@ import logging from urllib.parse import urlencode from fastmcp import Context -from superset_core.mcp import tool +from superset_core.api.mcp import tool from superset.extensions import event_logger from superset.mcp_service.sql_lab.schemas import ( diff --git a/superset/mcp_service/system/prompts/quickstart.py b/superset/mcp_service/system/prompts/quickstart.py index ec56400b3a4..d6d729a69bc 100644 --- a/superset/mcp_service/system/prompts/quickstart.py +++ b/superset/mcp_service/system/prompts/quickstart.py @@ -20,7 +20,7 @@ System prompts for general guidance """ from flask import current_app -from superset_core.mcp import prompt +from superset_core.api.mcp import prompt def _get_app_name() -> str: diff --git a/superset/mcp_service/system/tool/get_instance_info.py b/superset/mcp_service/system/tool/get_instance_info.py index 5aadd36ecbd..c3a60949442 100644 --- a/superset/mcp_service/system/tool/get_instance_info.py +++ b/superset/mcp_service/system/tool/get_instance_info.py @@ -23,7 +23,7 @@ InstanceInfoCore for flexible, extensible metrics calculation. import logging from fastmcp import Context -from superset_core.mcp import tool +from superset_core.api.mcp import tool from superset.extensions import event_logger from superset.mcp_service.mcp_core import InstanceInfoCore diff --git a/superset/mcp_service/system/tool/get_schema.py b/superset/mcp_service/system/tool/get_schema.py index c5c25f0e387..79c83124ac5 100644 --- a/superset/mcp_service/system/tool/get_schema.py +++ b/superset/mcp_service/system/tool/get_schema.py @@ -27,7 +27,7 @@ import logging from typing import Callable, Literal from fastmcp import Context -from superset_core.mcp import tool +from superset_core.api.mcp import tool from superset.extensions import event_logger from superset.mcp_service.common.schema_discovery import ( diff --git a/superset/mcp_service/system/tool/health_check.py b/superset/mcp_service/system/tool/health_check.py index 0283438e6ff..ed41b225f46 100644 --- a/superset/mcp_service/system/tool/health_check.py +++ b/superset/mcp_service/system/tool/health_check.py @@ -22,7 +22,7 @@ import logging import platform from flask import current_app -from superset_core.mcp import tool +from superset_core.api.mcp import tool from superset.extensions import event_logger from superset.mcp_service.system.schemas import HealthCheckResponse