JWE authentication middleware for MCP/Starlette applications
Project description
mcp-auth-middleware
JWE authentication middleware for HTTP MCP servers. Encrypt user data end-to-end so that only your MCP server can read it.
What it does
mcp-auth-middleware gives your MCP server two things:
- A middleware that decrypts a JWE Bearer token, enforces configured JWT scopes, and exposes the authenticated user's claims via
get_user(). - A CLI (
mcp-auth-middleware) that generates RSA key pairs in JWKS format, outputs Kubernetes Secret YAML, and securely deletes local keys when you're done.
The middleware also publishes:
/.well-known/jwks.jsonfor public key discovery/.well-known/fhswf-scopesfor required scope discovery
Installation
pip install mcp-auth-middleware
Testing
python -m pip install -r requirements.txt
python -m pip install -e .
pytest --cov=mcp_auth_middleware --cov-report=term-missing --cov-fail-under=80
Quick start
1. Generate keys
mcp-auth-middleware generate
This writes:
.keys/mcp-private.json
.keys/mcp-public.json
2. Configure the private key
MCP_KEY_FILE_PATH=.keys/mcp-private.json
3. Add the middleware
import uvicorn
from fastmcp import FastMCP
from mcp_auth_middleware import JWKSAuthMiddleware, get_user
mcp = FastMCP("My Server")
required_scopes = [
{"scope": "name"},
{"scope": "email"},
]
@mcp.tool()
def whoami() -> str:
user = get_user()
return f"Hello, {user.name}!"
app = mcp.http_app()
app.add_middleware(JWKSAuthMiddleware, scopes=required_scopes)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
4. Discover required scopes
GET /.well-known/fhswf-scopes returns exactly the scopes configured on that server:
{
"scopes_supported": [
{ "scope": "name" },
{ "scope": "email" }
]
}
The endpoint is public and includes permissive CORS headers.
5. Missing scope response
If a verified token is missing one or more configured fields, the middleware rejects the request with 403 Forbidden:
{
"error": "missing_scopes",
"missing": [{ "scope": "email" }]
}
API reference
JWKSAuthMiddleware
Attach it to any Starlette-based MCP server app:
app.add_middleware(
JWKSAuthMiddleware,
scopes=[
{"scope": "name"},
],
verifier=None,
jwks_path="/.well-known/jwks.json",
scopes_path="/.well-known/fhswf-scopes",
)
Rules:
scopesis required and must contain at least one scope.- Every configured scope is mandatory.
- Scope names must match JWT field names.
get_user() -> AuthUser
Returns the authenticated user's claims for the current request.
user = get_user()
user.email
user["email"]
ScopeDefinition
Optional helper dataclass for typed configuration:
from mcp_auth_middleware import ScopeDefinition
scope = ScopeDefinition(
scope="email",
)
JWETokenVerifier
Lower-level verifier if you need token verification outside the middleware:
from mcp_auth_middleware import JWETokenVerifier
verifier = JWETokenVerifier()
claims = await verifier.verify_token(token_string)
public_jwks = verifier.get_jwks()
verify_token() returns None when token decryption fails or when the decrypted payload is not a JSON object.
Browser access
/.well-known/fhswf-scopes already includes CORS headers.
If browser clients also need /.well-known/jwks.json, add CORS middleware after JWKSAuthMiddleware:
from starlette.middleware.cors import CORSMiddleware
app.add_middleware(JWKSAuthMiddleware, scopes=required_scopes)
app.add_middleware(CORSMiddleware, allow_origins=["*"])
Kubernetes deployment
Generate a Secret manifest:
mcp-auth-middleware k8s | kubectl apply -f -
Clean up local key material:
mcp-auth-middleware clean
Mount the generated private key and set:
MCP_KEY_FILE_PATH=/etc/mcp/secrets/key.json
A full example Deployment + Service is in examples/k8s-deployment.yaml.
Environment variables
| Variable | Required | Description |
|---|---|---|
MCP_KEY_FILE_PATH |
Yes | Path to the private JWKS JSON file |
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_auth_middleware-0.1.5.tar.gz.
File metadata
- Download URL: mcp_auth_middleware-0.1.5.tar.gz
- Upload date:
- Size: 14.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
af1b9ad3eb44b4e3a7229d18974686a06c30273eb5381df37fbd95bf59720a50
|
|
| MD5 |
a216ab5cd25dfafae5e1c6e53d9cd60b
|
|
| BLAKE2b-256 |
30a922ea0949c79e483434691ef9403212eda536c25fa5aadc5f9b33520292e9
|
Provenance
The following attestation bundles were made for mcp_auth_middleware-0.1.5.tar.gz:
Publisher:
publish.yml on fhswf/mcp-auth-middleware
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_auth_middleware-0.1.5.tar.gz -
Subject digest:
af1b9ad3eb44b4e3a7229d18974686a06c30273eb5381df37fbd95bf59720a50 - Sigstore transparency entry: 1083560674
- Sigstore integration time:
-
Permalink:
fhswf/mcp-auth-middleware@6b486681daa9034873297e7aacb995ac67f2b259 -
Branch / Tag:
refs/tags/v0.1.5 - Owner: https://github.com/fhswf
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6b486681daa9034873297e7aacb995ac67f2b259 -
Trigger Event:
release
-
Statement type:
File details
Details for the file mcp_auth_middleware-0.1.5-py3-none-any.whl.
File metadata
- Download URL: mcp_auth_middleware-0.1.5-py3-none-any.whl
- Upload date:
- Size: 10.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f9a85a4da737a244ada0aa1575f29a47abdfc6569d351710128e576131710e6a
|
|
| MD5 |
cba22b4cd6ee9eae32fe1d4bc6281aee
|
|
| BLAKE2b-256 |
08a751ba374a25b5419078b039a6a4b0a55501cec572217f5538c591932c75e2
|
Provenance
The following attestation bundles were made for mcp_auth_middleware-0.1.5-py3-none-any.whl:
Publisher:
publish.yml on fhswf/mcp-auth-middleware
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_auth_middleware-0.1.5-py3-none-any.whl -
Subject digest:
f9a85a4da737a244ada0aa1575f29a47abdfc6569d351710128e576131710e6a - Sigstore transparency entry: 1083560792
- Sigstore integration time:
-
Permalink:
fhswf/mcp-auth-middleware@6b486681daa9034873297e7aacb995ac67f2b259 -
Branch / Tag:
refs/tags/v0.1.5 - Owner: https://github.com/fhswf
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6b486681daa9034873297e7aacb995ac67f2b259 -
Trigger Event:
release
-
Statement type: