hoon-e opened a new pull request, #41404:
URL: https://github.com/apache/superset/pull/41404
## SUMMARY
Fix MCP dashboard role permission serialization to handle Flask-AppBuilder
`PermissionView` objects safely.
Previously, dashboard role serialization assumed permissions were simple
objects with a direct `name` attribute. FAB role permissions are
often represented as `PermissionView` objects, where the effective
permission name is composed from `permission.name` and `view_menu.name`
such as `can_read on Dashboard`. This could cause MCP dashboard
serialization to fail when role permission data was accessed.
This change makes role permission serialization defensive by:
- supporting direct permission names
- supporting FAB `PermissionView` objects
- handling detached or non-iterable permission relationships safely
- preserving existing MCP dashboard privacy behavior
Related to #41001
## AS-IS
- MCP dashboard role serialization expected role permissions to expose a
simple `name`.
- FAB `PermissionView` objects were not serialized into the expected
permission string format.
- Accessing detached or unavailable permission relationships could raise
serialization errors.
- In the latest dashboard MCP response path, sensitive access-list fields
such as `roles` remain stripped from dashboard output.
## TO-BE
- Role permission objects are serialized defensively.
- FAB permission/view-menu pairs are represented as strings like `can_read
on Dashboard`.
- Detached or unavailable permission relationships no longer break
serialization.
- Dashboard MCP privacy behavior is preserved: requesting `roles` does not
expose role data in dashboard list responses.
## TESTING INSTRUCTIONS
Verified locally with Docker using the current branch build.
1. Built and started Superset light Docker stack:
```bash
docker compose -f docker-compose-light.yml up --build -d superset-light
2. Started the MCP server from the built image on port 5008.
3. Called the actual MCP HTTP endpoint with FastMCP client and requested
dashboard fields including roles:
await client.call_tool(
"list_dashboards",
{
"request": {
"page": 1,
"page_size": 3,
"select_columns": ["id", "dashboard_title", "roles"],
}
},
)
Result:
- MCP call succeeded.
- No DetachedInstanceError.
- No role serialization traceback.
- No Error calling tool.
- Response returned dashboards successfully.
- roles was stripped from columns_requested and columns_loaded, matching
current MCP dashboard privacy behavior.
Observed response summary:
{
"count": 3,
"columns_requested": ["id", "dashboard_title"],
"columns_loaded": ["id", "dashboard_title"],
"columns_available_has_roles": false,
"first_dashboard_keys": ["dashboard_title", "id"]
}
Also verified the tool-search proxy path:
- search_tools found list_dashboards
- call_tool successfully invoked list_dashboards
Static validation:
python3 -m compileall -q superset/mcp_service/dashboard/schemas.py
tests/unit_tests/mcp_service/dashboard/tool/test_dashboard_tools.py
git show --check --stat HEAD
## ADDITIONAL INFORMATION
This PR does not re-expose dashboard owners or roles in MCP dashboard list
responses. Those fields are intentionally stripped by the current MCP privacy
policy.
--
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]