docs: clarify Daedalus-Pallas integration auth model
Refine the phase-2 integration spec to reflect implementation details: - Change `resolved_libraries` from `set[str]` to ordered `list[str]` - Document `MCPToken.allowed_libraries` as JSONField (not M2M) since Library lives in Neo4j, not Django's ORM - Clarify that `Library.workspace_id` is a content-routing attribute, not an authorization axis - Describe retirement of the three-branch `_WORKSPACE_SCOPE_CLAUSE` in favor of a single `lib.uid IN $resolved_libraries` check - Specify team JWT resolution via `TeamWorkspaceAssignment` DB join - Note admin UI materializes full Library UID list explicitly
This commit is contained in:
@@ -1,10 +1,35 @@
|
||||
"""Helpers for accessing the request-scoped MCP user/token from inside tools."""
|
||||
"""Helpers for accessing the request-scoped MCP auth state from inside tools.
|
||||
|
||||
The authoritative values are set by :class:`mcp_server.auth.MCPAuthMiddleware`
|
||||
on the FastMCP ``Context``:
|
||||
|
||||
* ``STATE_KEY_USER`` — the Django user the bearer resolved to (synthetic
|
||||
service user for JWT callers, concrete ``mcp_tokens.user`` for opaque
|
||||
MCPToken callers, ``None`` for team JWTs which are not tied to any
|
||||
per-user account).
|
||||
* ``STATE_KEY_TOKEN`` — the ``MCPToken`` row for opaque-token callers;
|
||||
``None`` for JWT callers.
|
||||
* ``STATE_KEY_CLAIMS`` — the JWT claims dict for JWT callers; ``None``
|
||||
for opaque-token callers. Intentionally exposed for debugging /
|
||||
metrics; tools should NOT branch on claim shape for authorization,
|
||||
they should read :func:`get_mcp_resolved_libraries` instead.
|
||||
* ``STATE_KEY_RESOLVED_LIBRARIES`` — the authorization-resolved Library
|
||||
UID set for this request. ``None`` means the caller is unauthenticated
|
||||
or the auth middleware was bypassed (shouldn't happen in practice);
|
||||
``[]`` means the caller is authenticated but scoped to zero libraries
|
||||
(fail-closed); a non-empty list enumerates the UIDs the caller may read.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from fastmcp.server.context import Context
|
||||
|
||||
from .auth import STATE_KEY_CLAIMS, STATE_KEY_TOKEN, STATE_KEY_USER
|
||||
from .auth import (
|
||||
STATE_KEY_CLAIMS,
|
||||
STATE_KEY_RESOLVED_LIBRARIES,
|
||||
STATE_KEY_TOKEN,
|
||||
STATE_KEY_USER,
|
||||
)
|
||||
|
||||
|
||||
async def get_mcp_user(ctx: Context | None):
|
||||
@@ -24,3 +49,23 @@ async def get_mcp_claims(ctx: Context | None) -> dict | None:
|
||||
if ctx is None:
|
||||
return None
|
||||
return await ctx.get_state(STATE_KEY_CLAIMS)
|
||||
|
||||
|
||||
async def get_mcp_resolved_libraries(ctx: Context | None) -> list[str] | None:
|
||||
"""Return the authorization-resolved Library UID list for this request.
|
||||
|
||||
Semantics (matching ``SearchRequest.resolved_libraries``):
|
||||
|
||||
* ``None`` — no auth information available (e.g. the middleware did
|
||||
not run, or the tool was invoked outside a request context). Tools
|
||||
should treat this as fail-closed and refuse to return content.
|
||||
* ``[]`` — the caller was authenticated but is scoped to zero
|
||||
libraries. Tools MAY proceed and return empty results.
|
||||
* ``["lib_x", …]`` — the caller may read exactly these libraries.
|
||||
|
||||
See ``docs/DAEDALUS_PALLAS_INTEGRATION_v1.md`` §3.3 for the unified
|
||||
auth model that populates this value.
|
||||
"""
|
||||
if ctx is None:
|
||||
return None
|
||||
return await ctx.get_state(STATE_KEY_RESOLVED_LIBRARIES)
|
||||
|
||||
Reference in New Issue
Block a user