Skip to content

feat(mcp): add create_plugin tool for registering dynamic plugins#40357

Draft
aminghadersohi wants to merge 1 commit into
apache:masterfrom
aminghadersohi:amin/mcp-create-plugin
Draft

feat(mcp): add create_plugin tool for registering dynamic plugins#40357
aminghadersohi wants to merge 1 commit into
apache:masterfrom
aminghadersohi:amin/mcp-create-plugin

Conversation

@aminghadersohi
Copy link
Copy Markdown
Contributor

SUMMARY

Adds a new MCP mutation tool create_plugin that allows admin users to register dynamic (custom) plugins via the MCP service.

The tool lives under superset/mcp_service/plugin/ and follows the established mutation pattern used by create_virtual_dataset.

Key details:

  • Tool name: create_plugin
  • Fields: name (required), key (required, unique plugin identifier matching package.json), bundle_url (required, full URL to the built plugin bundle)
  • Permission: DynamicPlugin / write — admin-only, same access level as the existing DynamicPluginsView
  • Feature-gated: returns a structured error if the DYNAMIC_PLUGINS feature flag is disabled
  • Handles duplicate-field IntegrityError gracefully without raising
  • Registered in mcp_service/app.py and included in the tool listing in instructions

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

N/A — backend-only change.

TESTING INSTRUCTIONS

  1. Enable the DYNAMIC_PLUGINS feature flag in superset_config.py
  2. Connect to the MCP service as an admin user
  3. Call create_plugin with valid name, key, and bundle_url
  4. Verify the plugin appears in the Superset UI under Settings → Custom Plugins
  5. Verify that calling create_plugin with a duplicate key returns a structured error (not an exception)
  6. Verify that calling create_plugin without admin permissions is rejected

ADDITIONAL INFORMATION

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

Adds a new MCP mutation tool `create_plugin` under `mcp_service/plugin/`
that allows admin users to register dynamic (custom) plugins by providing
a name, unique key, and bundle URL. The tool checks the DYNAMIC_PLUGINS
feature flag and handles duplicate-field errors gracefully.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented May 22, 2026

Codecov Report

❌ Patch coverage is 48.07692% with 27 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.19%. Comparing base (5966bb1) to head (d008dde).

Files with missing lines Patch % Lines
superset/mcp_service/plugin/tool/create_plugin.py 25.00% 24 Missing ⚠️
superset/mcp_service/plugin/schemas.py 82.35% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #40357      +/-   ##
==========================================
- Coverage   64.20%   64.19%   -0.01%     
==========================================
  Files        2592     2595       +3     
  Lines      139004   139056      +52     
  Branches    32273    32275       +2     
==========================================
+ Hits        89241    89266      +25     
- Misses      48231    48258      +27     
  Partials     1532     1532              
Flag Coverage Δ
hive 39.30% <48.07%> (+<0.01%) ⬆️
mysql 58.80% <48.07%> (-0.01%) ⬇️
postgres 58.88% <48.07%> (-0.01%) ⬇️
presto 40.97% <48.07%> (+<0.01%) ⬆️
python 60.44% <48.07%> (-0.02%) ⬇️
sqlite 58.52% <48.07%> (-0.01%) ⬇️
unit 100.00% <ø> (ø)

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.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a new MCP mutation tool (create_plugin) to let authorized users register dynamic (custom) plugins via the MCP service, and wires it into MCP app registration and the default instructions.

Changes:

  • Introduces create_plugin MCP tool that creates DynamicPlugin rows (with feature-flag gating and duplicate handling).
  • Adds Pydantic request/response schemas for the tool under superset/mcp_service/plugin/.
  • Registers the tool in superset/mcp_service/app.py and documents it in the default instructions.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
superset/mcp_service/plugin/tool/create_plugin.py New MCP mutation tool implementation for registering dynamic plugins
superset/mcp_service/plugin/tool/init.py Exports the new tool from the plugin tool package
superset/mcp_service/plugin/schemas.py Adds Pydantic schemas for create_plugin request/response
superset/mcp_service/plugin/init.py Makes the new MCP plugin package discoverable as a Python package
superset/mcp_service/app.py Registers the tool with the MCP app and lists it in default instructions

Comment on lines +58 to +105
try:
from sqlalchemy.exc import IntegrityError

from superset import is_feature_enabled
from superset.extensions import db
from superset.models.dynamic_plugins import DynamicPlugin

if not is_feature_enabled("DYNAMIC_PLUGINS"):
await ctx.warning("DYNAMIC_PLUGINS feature flag is not enabled")
return CreatePluginResponse(
error=(
"The DYNAMIC_PLUGINS feature flag is not enabled on this instance."
)
)

with event_logger.log_context(action="mcp.create_plugin.create"):
plugin = DynamicPlugin(
name=request.name,
key=request.key,
bundle_url=request.bundle_url,
)
db.session.add(plugin)
db.session.commit()

await ctx.info(
"Dynamic plugin registered: id=%s, key=%r" % (plugin.id, plugin.key)
)

return CreatePluginResponse(
id=plugin.id,
name=plugin.name,
key=plugin.key,
bundle_url=plugin.bundle_url,
)

except IntegrityError as exc:
db.session.rollback()
msg = str(exc.orig) if exc.orig else str(exc)
await ctx.warning("Plugin creation failed (duplicate field): %s" % (msg,))
return CreatePluginResponse(
error=(
"A plugin with the same name, key, or bundle_url already exists. "
"Each field must be unique."
)
)
except Exception as exc:
db.session.rollback()
await ctx.error(
Comment on lines +26 to +46
name: str = Field(
...,
min_length=1,
description="Human-friendly name for the plugin.",
)
key: str = Field(
...,
min_length=1,
description=(
"Unique plugin key. Should match the package name from the plugin's "
"package.json (e.g. '@my-org/my-chart-plugin')."
),
)
bundle_url: str = Field(
...,
min_length=1,
description=(
"Full URL pointing to the built plugin bundle "
"(e.g. a CDN-hosted JavaScript file)."
),
)
Comment on lines +47 to +49
Requires the DYNAMIC_PLUGINS feature flag to be enabled and admin write
access to DynamicPlugin. The ``key`` must match the package name from the
plugin's package.json and be unique across all registered plugins.
- add_chart_to_existing_dashboard: Add a chart to an existing dashboard (requires write access)

Plugin Management:
- create_plugin: Register a new dynamic plugin by name, key, and bundle URL (requires admin write access and DYNAMIC_PLUGINS feature flag)
Comment on lines +32 to +45
@tool(
tags=["mutate"],
class_permission_name="DynamicPlugin",
method_permission_name="write",
annotations=ToolAnnotations(
title="Register a dynamic plugin",
readOnlyHint=False,
destructiveHint=False,
),
)
async def create_plugin(
request: CreatePluginRequest, ctx: Context
) -> CreatePluginResponse:
"""Register a new dynamic (custom) plugin in Superset.
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.

2 participants