Skip to main content

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:

  1. A middleware that decrypts a JWE Bearer token, enforces configured JWT scopes, and exposes the authenticated user's claims via get_user().
  2. 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.json for public key discovery
  • /.well-known/openid-configuration for OpenID 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. OpenID discovery

GET /.well-known/openid-configuration returns the issuer, JWKS URI, and configured scopes:

{
  "issuer": "http://localhost:8000",
  "jwks_uri": "http://localhost:8000/.well-known/jwks.json",
  "scopes_supported": ["name", "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",
    openid_configuration_path="/.well-known/openid-configuration",
    issuer=None,
)

Rules:

  • scopes is 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/openid-configuration 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

mcp_auth_middleware-0.1.7.tar.gz (14.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcp_auth_middleware-0.1.7-py3-none-any.whl (10.9 kB view details)

Uploaded Python 3

File details

Details for the file mcp_auth_middleware-0.1.7.tar.gz.

File metadata

  • Download URL: mcp_auth_middleware-0.1.7.tar.gz
  • Upload date:
  • Size: 14.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for mcp_auth_middleware-0.1.7.tar.gz
Algorithm Hash digest
SHA256 b87bbf837e9f3bb3b225e37f94737ce909b8855f338c8e2183a7877dab2d9e27
MD5 8cf1ad660a06dbdc7bf1c6eb9f969f15
BLAKE2b-256 a604e24da7ede2ce20fd16d30ac4f15020d8fd1f321ea891313254ac4fbfb4f5

See more details on using hashes here.

Provenance

The following attestation bundles were made for mcp_auth_middleware-0.1.7.tar.gz:

Publisher: publish.yml on fhswf/mcp-auth-middleware

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mcp_auth_middleware-0.1.7-py3-none-any.whl.

File metadata

File hashes

Hashes for mcp_auth_middleware-0.1.7-py3-none-any.whl
Algorithm Hash digest
SHA256 038a4f558e65e765d9fce6645ced952dface18dd0fc2b55563cac5e82bd07d00
MD5 58307afa17b0b4bdaae6b0d45a0ec666
BLAKE2b-256 1d28e8d3b1b7e6067fb990d356a23d31578ba08a7c97fb143cf19ba076b9daee

See more details on using hashes here.

Provenance

The following attestation bundles were made for mcp_auth_middleware-0.1.7-py3-none-any.whl:

Publisher: publish.yml on fhswf/mcp-auth-middleware

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page