Skip to content

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

python
@cache
def mcp_server() -> FastMCP

Return the process-wide FastMCP server, built and tool-registered once.

mcp_app

python
@cache
def mcp_app() -> Starlette

Return the server's StreamableHTTP ASGI app (built once, lifespan owned by the entrypoint).

has_tools

python
def has_tools() -> bool

Return whether any installed addon contributes MCP tools.

Released under the AGPL-3.0 License.