closedmcp
A small Python wrapper for Log in with ClosedMCP. It protects Streamable HTTP requests made to the official SDK’s Server or built-in FastMCP, or standalone FastMCP 2, verifies a signed pass on every call, and serves MCP protected-resource metadata.
Add to an existing server
Keep your existing official mcp.server.fastmcp.FastMCP or standalone fastmcp.FastMCP 2 instance. Replace its HTTP serving call with:
import os
from closedmcp import current_user, serve_with_closedmcp
serve_with_closedmcp(app, resource=os.environ["MCP_URL"], allowed_domains=os.environ["ALLOWED_DOMAINS"].split(","))
In any tool, use current_user().email or current_user().org. For an existing ASGI host, serve closedmcp_app(app, resource=..., allowed_domains=...) instead. Install with pip install closedmcp for the official SDK or pip install 'closedmcp[fastmcp]' for standalone FastMCP 2.
Hello
from mcp.server.fastmcp import FastMCP
from closedmcp import current_user, serve_with_closedmcp
app = FastMCP("hello")
@app.tool()
def hello() -> str:
return f"Hello {current_user().email}"
serve_with_closedmcp(
app,
resource="https://example.com/mcp",
allowed_domains=["example.com"])
Replace the first import with from fastmcp import FastMCP to use standalone FastMCP 2. Install with pip install closedmcp for the official SDK or pip install 'closedmcp[fastmcp]' for both. This repository also has a runnable template: install the package locally with pip install -e ., then run MCP_URL=https://example.com/mcp ALLOWED_DOMAINS=example.com python template/server.py. Set PORT and HOST for the listening socket. CLOSEDMCP_ORIGIN and CLOSEDMCP_JWKS_URL are available for local integration tests.
resource is the exact public MCP URL and JWT audience. allowed_domains must contain at least one verified company domain. The wrapper checks an EdDSA pass against the issuer's JWKS, issuer, exact audience, expiry, five-minute maximum lifetime, required identity claims, and company domain. Unknown key IDs trigger a JWKS refresh through PyJWT. current_user() returns a Person with id, email, company, org, and optional aiApp; it raises outside a verified request. aiApp is a client supplied display value.
For /mcp, metadata is at /.well-known/oauth-protected-resource/mcp and the generic metadata path. A missing or invalid pass receives 401 with WWW-Authenticate: Bearer resource_metadata="<metadata URL>". Authenticated non-POST requests receive 405. To use another ASGI server, call closedmcp_app(app, resource=..., allowed_domains=...) and serve the returned ASGI app. Its lifespan must be run by the ASGI server.
See the ClosedMCP documentation.
Metadata
Release files for closedmcp 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 | |
|---|---|---|---|
| closedmcp-0.1.0.tar.gz | 12.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| closedmcp-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 21.8 kB
Release files / closedmcp-0.1.0.tar.gz
| Download URL | closedmcp-0.1.0.tar.gz |
|---|---|
| Size | 12.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
560d0564ced9532ba88add324182a928dad2635f45258e00ff142e2a049eee4f
|
|
BLAKE2b-256 checksum How to use checksums |
fa48a9c2a258d75597138e3f8a2a75fcc76205903fbabae97dd357967edd133f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / closedmcp-0.1.0-py3-none-any.whl
| Download URL | closedmcp-0.1.0-py3-none-any.whl |
|---|---|
| Size | 9.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
685994c349c011e2ab753d2943d8e390b5a8d5f224aafda644b163fa605384c8
|
|
BLAKE2b-256 checksum How to use checksums |
5a28bdc3fea1c7497b4c322084fc08139d5bc148809a78538c78ebce0f602129
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|