angee.mcp.server
The process-wide MCP server: one FastMCP instance, tools from addon manifests.
Each installed addon contributes tools through the mcp_tools seam — an mcp_tools.py module exposing a register(server: FastMCP) -> None callable, inferred by convention (an addon.toml [mcp].tools entry overrides the dotted reference). It resolves the same way the GraphQL schemas seam does, through the shared :func:angee.addons.resolve_addon_reference. The server authenticates the inbound bearer with :class:~angee.mcp.verifier.RebacTokenVerifier and brackets every tool call in the authenticated REBAC actor with :class:~angee.mcp.middleware.ActorMiddleware. It is mounted as a StreamableHTTP ASGI app by :mod:angee.mcp.asgi; :mod:angee.asgi owns its lifespan, so the server holds no per-request lifecycle of its own.
stateless_http keeps each call independent and json_response returns a buffered JSON body the agent's HTTP client folds without an SSE reader (both passed to :meth:~fastmcp.FastMCP.http_app). DNS-rebinding protection is off by default (FastMCP passes no transport-security settings); Django's ALLOWED_HOSTS already terminates the request and the bearer + REBAC actor resolution is the real authorization boundary.
ToolRegistrar
An addon's register(server) callable — it adds tools to the MCP server.
MOUNT_PATH
The external StreamableHTTP path the server mounts at (see :mod:angee.mcp.asgi).
mcp_server
@cache
def mcp_server() -> FastMCPReturn the process-wide FastMCP server, built and tool-registered once.
mcp_app
@cache
def mcp_app() -> StarletteReturn the server's StreamableHTTP ASGI app (built once, lifespan owned by the entrypoint).
has_tools
def has_tools() -> boolReturn whether any installed addon contributes MCP tools.