aminghadersohi opened a new pull request, #35835:
URL: https://github.com/apache/superset/pull/35835
### SUMMARY
This PR adds the first two MCP tools for chart access along with reusable
core infrastructure for building additional MCP tools.
**Built on top of:** PR #1 (feat/mcp_service_pr1_scaffold) - MCP service
scaffold
**What's Included:**
## New MCP Tools
**list_charts** - Paginated chart listing
- Filter by: slice_name, viz_type, datasource_name
- Search across chart fields
- Sort by: id, slice_name, viz_type, changed_on, created_on
- 1-based pagination (page, page_size parameters)
- Returns: ChartList with chart metadata
**get_chart_info** - Retrieve chart details
- Lookup by integer ID or UUID string
- Returns: Complete chart metadata (name, viz_type, params, owners, etc.)
- Consistent error responses with ChartError schema
## Core Infrastructure (297 lines)
**mcp_core.py** - Reusable base classes for MCP tools:
- **BaseCore**: Flask app context management
- **ModelListCore**: Generic paginated listing with filtering/search/sorting
- Type-safe with `Generic[L]` for proper type inference
- Handles pagination, filters, search, ordering
- Works with any Superset DAO (ChartDAO, DashboardDAO, etc.)
- **ModelGetInfoCore**: Generic single-item retrieval by ID/UUID
- Automatic ID vs UUID detection
- Consistent error handling
**auth.py** (98 lines) - Minimal authentication:
- `@mcp_auth_hook` decorator for tool authentication
- Admin user fallback for development
- `has_dataset_access()` for dataset permission checking
- Flask `g.user` context integration
**middleware.py** (74 lines) - Basic error handling:
- Request/response logging
- Error response formatting
- Flask context integration
**utils/** (29 lines) - Shared utilities:
- `_is_uuid()` helper for ID validation
## Schemas (Pydantic)
**chart/schemas.py** (283 lines):
- `ChartInfo`: Detailed chart metadata model
- `ChartList`: Paginated list response with PaginationInfo
- `ChartError`: Consistent error responses
- `ChartFilter`: Filter specification (col, opr, value)
- `ListChartsRequest`, `GetChartInfoRequest`: Tool request models
- `ColumnRef`, `TableChartConfig`, `XYChartConfig`: For future chart
creation tools
**system/schemas.py** (expanded from 40 to 87 lines):
- `UserInfo`: User metadata (id, username, first_name, last_name, roles)
- `TagInfo`: Tag information
- `PaginationInfo`: Pagination metadata (count, page, page_size, total_count)
- `RoleInfo`: Role metadata (for future use)
**common/cache_schemas.py** (143 lines):
- `CacheControl`: Unified cache behavior configuration
- Flags: use_cache, force_refresh, cache_timeout, refresh_metadata
- Consistent caching interface for all tools
## Testing (408 lines)
**test_list_charts.py** (172 lines):
- Schema validation tests for ChartInfo, ChartList, ChartFilter
- Request/response model validation
- Filter specification tests
**test_mcp_core.py** (204 lines):
- ModelListCore tests: pagination, filtering, search, ordering
- ModelGetInfoCore tests: ID lookup, UUID lookup, not found cases
- Error handling tests
**Apache license headers** on all __init__.py files
## Integration
**app.py** (4 line change):
```python
import superset.mcp_service.chart.tool # noqa: F401, E402
```
This single import registers both tools via their `@mcp.tool` decorators.
## Architecture & Patterns
This PR establishes the pattern for all future MCP tools:
1. **Create tool** using `@mcp.tool` decorator
2. **Use core classes**: ModelListCore for listing, ModelGetInfoCore for
retrieval
3. **Define schemas**: Pydantic models for type-safe requests/responses
4. **Add tests**: Unit tests for schemas and tool logic
5. **Register**: Import tool module in app.py
**Type safety:**
- Modern Python 3.10+ type hints (`T | None` instead of `Optional[T]`)
- Generic types for proper inference (`ModelListCore[ChartList]`)
- All code is mypy compliant
**Reusability:**
- Core classes work with any Superset entity (charts, dashboards, datasets,
etc.)
- Just provide the DAO class and schema - the rest is handled automatically
- Same pattern used for upcoming dashboard and dataset tools
### BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
N/A - Backend MCP service infrastructure only, no UI changes.
**Example tool usage via Claude Desktop:**
```
User: "List the most recently updated bar charts"
Claude calls: list_charts({
"filters": [{"col": "viz_type", "opr": "eq", "value": "bar"}],
"order_column": "changed_on",
"order_direction": "desc"
})
User: "Show me details for chart ID 123"
Claude calls: get_chart_info({"identifier": 123})
```
### TESTING INSTRUCTIONS
**Prerequisites:**
- Superset running with PR #1 (MCP scaffold) merged
- Python 3.10 or 3.11
- fastmcp installed (`pip install -e .[development]`)
**Setup:**
```bash
# 1. Ensure database is initialized
export FLASK_APP=superset
superset db upgrade
superset init
# 2. Create admin user (if not already done)
superset fab create-admin \
--username admin \
--firstname Admin \
--lastname Admin \
--email admin@localhost \
--password admin
# 3. Load example data (for testing)
superset load-examples
```
**Run Tests:**
```bash
# Run all MCP service unit tests
pytest tests/unit_tests/mcp_service/ -v
# Should see:
# - test_list_charts.py: 16 schema tests passing
# - test_mcp_core.py: 11 core infrastructure tests passing
# Total: 27 tests passing
```
**Test with MCP Server:**
```bash
# Terminal 1: Start Superset
superset run -p 9001
# Terminal 2: Start MCP service
superset mcp run --port 5008 --debug
# Terminal 3: Test with curl
curl http://localhost:5008/health
# Expected: {"status": "ok", "timestamp": "...", ...}
```
**Test Tools via Claude Desktop:**
Configure Claude Desktop with:
```json
{
"mcpServers": {
"superset": {
"command": "superset",
"args": ["mcp", "run", "--port", "5008"]
}
}
}
```
Then test queries:
- "List all charts" → Should call list_charts tool
- "Show me chart 1" → Should call get_chart_info tool
- "List bar charts" → Should call list_charts with viz_type filter
**Verify Error Handling:**
```python
# Test in Python shell with Flask app context
from superset.mcp_service.chart.tool import list_charts, get_chart_info
# Test pagination
result = list_charts(page=1, page_size=10)
assert result.pagination.page == 1
# Test filtering
result = list_charts(filters=[{"col": "viz_type", "opr": "eq", "value":
"bar"}])
assert all(c.viz_type == "bar" for c in result.charts)
# Test not found
result = get_chart_info(identifier=99999)
assert result.error is not None
```
### ADDITIONAL INFORMATION
- [ ] Has associated issue:
- [ ] Required feature flags: None
- [ ] Changes UI: No
- [ ] Includes DB Migration: No
- [x] Introduces new feature or API: Yes - MCP chart tools and core
infrastructure
- [ ] Removes existing feature or API: No
**Stats:**
- 18 files changed
- 1,649 insertions, 5 deletions
- 408 lines of tests (27 test cases)
- 100% mypy compliant
- All pre-commit hooks passing
**Future PRs will add:**
- Dashboard tools (list_dashboards, get_dashboard_info, etc.)
- Dataset tools (list_datasets, get_dataset_info, etc.)
- Chart creation tools (generate_chart, update_chart, etc.)
- SQL Lab integration tools
- Advanced authentication (JWT, OAuth)
- Field-level permissions and audit logging
**Notes:**
- Builds cleanly on PR #1 (MCP scaffold)
- Minimal changes to existing code (only app.py import)
- No database migrations
- No UI changes
- Optional dependency (fastmcp in development requirements only)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]