rubenandre opened a new issue, #41001:
URL: https://github.com/apache/superset/issues/41001
### Bug description
When the MCP service is enabled with RBAC (MCP_RBAC_ENABLED=True), calling
list_dashboards (or get_dashboard_info) on any dashboard that has
dashboard-level roles assigned raises a DetachedInstanceError during response
serialization, and the tool call fails
**Root cause**
In superset/mcp_service/dashboard/schemas.py, both serialization paths build
the roles field via:
```
roles=[
RoleInfo.model_validate(role, from_attributes=True)
for role in dashboard.roles
]
```
* serialize_dashboard_object() : schemas.py ~line 714–718
* build_dashboard_info() : schemas.py ~line 795–799
RoleInfo (in superset/mcp_service/system/schemas.py, line 175) declares:
```
class RoleInfo(BaseModel):
id: int | None = None
name: str | None = None
permissions: List[str] | None = None # line 178
```
With from_attributes=True, pydantic reads the ORM attribute
role.permissions, which is a List[PermissionView] (FAB), and tries to coerce
each PermissionView into a str to satisfy List[str]. Coercing PermissionView ->
str invokes PermissionView.__repr__, which reads self.permission, a
lazily-loaded relationship.
By the time the MCP response is serialized, the loading DB session is gone,
so the lazy load fails:
sqlalchemy.orm.exc.DetachedInstanceError: Instance <PermissionView at
0x...> is not bound to a Session;
lazy load operation of attribute 'permission' cannot proceed
(With a still-live session it instead fails pydantic validation: Input
should be a valid string ... input PermissionView.)
The bug is self-evident in the same file: the dedicated helper
serialize_role_object() (schemas.py line 137) does it correctly:
return RoleInfo(
id=getattr(role, "id", None),
name=getattr(role, "name", None),
permissions=[perm.name for perm in getattr(role, "permissions", [])]
if hasattr(role, "permissions")
else None,
)
…but the model_validate(role, from_attributes=True) paths bypass this helper
and feed raw PermissionView objects straight into the List[str] field.
**Reproduction steps**
1. Deploy Superset 6.1.0 with the MCP service enabled and RBAC on
(MCP_RBAC_ENABLED=True).
2. In the UI, assign at least one Role to any dashboard (Dashboard →
Properties → Roles).
3. From an MCP client, call the list_dashboards tool (or get_dashboard_info
for that dashboard).
4. Observe: the tool call fails with DetachedInstanceError while
serializing dashboard.roles. Dashboards with no roles assigned serialize fine.
### Screenshots/recordings
_No response_
### Superset version
6.1.0
### Python version
3.10
### Node version
Not applicable
### Browser
Not applicable
### Additional context
Triggers for any dashboard with RBAC roles assigned; affects
list_dashboards, get_dashboard_info, and likely any other MCP tool serializing
roles through these schema paths. Verified against the upstream 6.1.0 tag
(superset/mcp_service/dashboard/schemas.py lines 137, 714–718, 795–799;
superset/mcp_service/system/schemas.py line 175–178)
**Representative stacktrace:**
sqlalchemy.orm.exc.DetachedInstanceError: Instance <PermissionView at 0x...>
is not bound to a Session; lazy load operation of attribute 'permission' cannot
proceed
```
...
File ".../superset/mcp_service/dashboard/schemas.py", line 715, in
serialize_dashboard_object
RoleInfo.model_validate(role, from_attributes=True)
File ".../pydantic/main.py", line ..., in model_validate
...
```
### Checklist
- [x] I have searched Superset docs and Slack and didn't find a solution to
my problem.
- [x] I have searched the GitHub issue tracker and didn't find a similar bug
report.
- [x] I have checked Superset's logs for errors and if I found a relevant
Python stacktrace, I included it here as text in the "additional context"
section.
--
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]