delegus-mcp
Delegus for Python MCP servers. An ASGI middleware checks every MCP
tools/call against the calling agent's delegated authority before your tool
runs. It works with the official Python MCP SDK's MCPServer over streamable
HTTP, with Starlette, and with FastAPI. It follows the same rules as the Node
middleware, delegus.mcp() in @delegus/sdk.
pip install delegus-mcp
import os
from mcp.server.mcpserver import MCPServer
from delegus_mcp import DelegusMCPMiddleware
mcp = MCPServer("tickets")
@mcp.tool()
def create_ticket(title: str) -> str:
return f"created ticket: {title}"
app = DelegusMCPMiddleware(
mcp.streamable_http_app(),
api_key=os.environ["DELEGUS_RP_KEY"],
public_base_url="https://tools.example.com",
)
Run it with any ASGI server, for example uvicorn server:app.
public_base_url is the address agents call and sign for; behind a proxy,
it's the public one. For FastAPI or Starlette, wrap the app the same way, or
use app.add_middleware(DelegusMCPMiddleware, api_key=…, public_base_url=…).
Options:
tools: a list or a predicate, to enforce only some tools (others pass unchecked);relying_party: skips a lookup when credentials are missing;on_decision: called with each decision, for logs;max_body_bytes: default 1 MiB; a larger body is refused;api_base_url;timeout_seconds.
What happens to each request
-
tools/call: the agent'sDelegus-GrantandDelegus-Proofheaders are checked, including that the Proof was signed for this tool at this address.- On ALLOW, the tool runs. The receipt is in
scope["state"]["delegus"](in Starlette,request.state.delegus) and the response carriesDelegus-Receipt-Id. - On DENY, the middleware answers HTTP 403 with JSON-RPC error
-32040and the Delegus reason, and the tool never runs.
- On ALLOW, the tool runs. The receipt is in
-
Anything it can't read is refused:
- a missing, unparseable or oversized body, or one with duplicate keys
(
REQUEST_UNREADABLE); - a JSON-RPC batch carrying a checked tool call (
BATCH_NOT_SUPPORTED); - a tool call without a string tool name (
TOOL_NAME_INVALID).
These are the middleware's own refusals and carry no signed receipt.
- a missing, unparseable or oversized body, or one with duplicate keys
(
-
Delegus can't be reached: 403
SERVICE_UNAVAILABLE. It fails closed. -
Everything that can't run a tool passes through:
initialize,tools/list,ping, notifications, JSON-RPC responses,GET(the SSE stream),HEAD,OPTIONS, and aDELETEthat ends a session. -
The app receives exactly the bytes that were checked.
Limits
- No stdio. It checks HTTP requests, so it covers MCP servers served over HTTP, not stdio-only servers.
- No argument inspection. Delegus v0.2 binds the tool, not its
arguments: a permission can allow
create_ticket, not "tickets under a priority". Validate arguments in the tool. - Server-to-client messages aren't checked. Requests your server sends to the client on an SSE stream (sampling, elicitation) pass as they are.
- Only requests that reach this app are checked. If the same tools are exposed some other way, those routes aren't protected.
Tested against
The shared MCP request-shape suite in @delegus/conformance: the same rows
the Node middleware and the Delegus MCP gateway run. It asserts that a refused
request never reaches the tool, and that a forwarded one arrives byte for
byte. End to end, with the official Python MCP SDK (mcp 2.x) and a local
Delegus:
- a delegated call runs with a receipt;
- after a revoke, the same call is refused with
AUTHORITY_REVOKED; - a batch is refused.
Python 3.9 or later. Apache-2.0.
Release files for delegus-mcp 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| delegus_mcp-0.1.0.tar.gz | 13.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| delegus_mcp-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 26.3 kB
Release files / delegus_mcp-0.1.0.tar.gz
| Download URL | delegus_mcp-0.1.0.tar.gz |
|---|---|
| Size | 13.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e7bdd8ebfadf22b4902228a5fb914233cf71b3658f6aee2628918966e0264a9d
|
|
BLAKE2b-256 checksum How to use checksums |
5dd4409e83c6ad5b98d0ce43323be1d4fbf5a48eb4cf594eb4354af8f36fb2c0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|
Release files / delegus_mcp-0.1.0-py3-none-any.whl
| Download URL | delegus_mcp-0.1.0-py3-none-any.whl |
|---|---|
| Size | 12.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
aabbdc530af32afaa8b306266595f52ec948a9ab1629e1207f54cf52bb544db8
|
|
BLAKE2b-256 checksum How to use checksums |
e4fc278f69753148b38ab59b845132255b0fcd1777a46f44a7a173a47fa76e05
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|