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]

Reply via email to