MCP OAuth Dynamic Client Registration Server - OAuth 2.1 and RFC 7591 compliant
Project description
MCP OAuth Dynamic Client
A production-ready OAuth 2.1 authorization server with RFC 7591 dynamic client registration support, designed specifically for the MCP OAuth Gateway.
Features
- OAuth 2.1 Compliant - Modern OAuth implementation with mandatory PKCE
- Dynamic Client Registration - RFC 7591 compliant automatic client setup
- Client Management Protocol - RFC 7592 compliant CRUD operations
- GitHub OAuth Integration - User authentication via GitHub
- JWT Token Management - RS256 (recommended) and HS256 support
- ForwardAuth Compatible - Works seamlessly with Traefik
- Redis State Storage - Scalable token and client storage
- Token Introspection - RFC 7662 compliant token validation
- Token Revocation - RFC 7009 compliant token lifecycle
Installation
Using pip
pip install mcp-oauth-dynamicclient
Using pixi
pixi add --pypi mcp-oauth-dynamicclient
Docker Deployment
FROM python:3.11-slim
# Install the package
RUN pip install mcp-oauth-dynamicclient
# Set environment variables (configure via .env or docker-compose)
ENV HOST=0.0.0.0
ENV PORT=8000
# Expose the port
EXPOSE 8000
# Run the server
CMD ["mcp-oauth-server", "--host", "0.0.0.0", "--port", "8000"]
Quick Start
1. Set up environment variables
Create a .env file with required configuration:
# GitHub OAuth App credentials
GITHUB_CLIENT_ID=your_github_client_id
GITHUB_CLIENT_SECRET=your_github_client_secret
# JWT Configuration
JWT_SECRET=your_jwt_secret_key
JWT_ALGORITHM=RS256 # or HS256
JWT_PRIVATE_KEY_B64=your_base64_encoded_rsa_key # For RS256
# Domain configuration
BASE_DOMAIN=yourdomain.com
# Redis configuration
REDIS_URL=redis://localhost:6379/0
REDIS_PASSWORD=your_redis_password # Optional
# Token lifetimes (in seconds)
ACCESS_TOKEN_LIFETIME=1800 # 30 minutes
REFRESH_TOKEN_LIFETIME=31536000 # 1 year
SESSION_TIMEOUT=300 # 5 minutes
CLIENT_LIFETIME=7776000 # 90 days (0 = never expires)
# Access control
ALLOWED_GITHUB_USERS=user1,user2,user3 # or '*' for any GitHub user
# MCP Protocol version
MCP_PROTOCOL_VERSION=2025-06-18
2. Run the server
Using the CLI:
mcp-oauth-server --host 0.0.0.0 --port 8000
Using Python:
from mcp_oauth_dynamicclient import create_app, Settings
import uvicorn
settings = Settings() # Loads from .env
app = create_app(settings)
uvicorn.run(app, host="0.0.0.0", port=8000)
3. Register a client
import httpx
import asyncio
async def register_client():
async with httpx.AsyncClient() as client:
response = await client.post(
"https://auth.yourdomain.com/register",
json={
"redirect_uris": ["https://myapp.com/callback"],
"client_name": "My Application",
"scope": "openid profile email"
}
)
if response.status_code == 201:
result = response.json()
print(f"Client ID: {result['client_id']}")
print(f"Client Secret: {result['client_secret']}")
print(f"Registration Token: {result['registration_access_token']}")
# Save these credentials securely!
asyncio.run(register_client())
API Endpoints
Public Endpoints
POST /register- Register a new OAuth client (RFC 7591)GET /.well-known/oauth-authorization-server- Server metadataGET /jwks- JSON Web Key Set for token verification
OAuth Flow Endpoints
GET /authorize- Start authorization flowPOST /token- Exchange authorization code for tokensGET /callback- GitHub OAuth callback handler
Protected Endpoints (Require Bearer Token)
GET /verify- Verify token for ForwardAuthPOST /revoke- Revoke a tokenPOST /introspect- Introspect token details
Client Management (Require Registration Access Token)
GET /register/{client_id}- Get client configurationPUT /register/{client_id}- Update client configurationDELETE /register/{client_id}- Delete client registration
OAuth Flow
-
Client Registration
- Client POSTs to
/registerwith metadata - Receives
client_id,client_secret, andregistration_access_token
- Client POSTs to
-
Authorization
- Client redirects user to
/authorizewith PKCE challenge - User authenticates via GitHub
- Server redirects back with authorization code
- Client redirects user to
-
Token Exchange
- Client POSTs code to
/tokenwith PKCE verifier - Receives JWT access token and refresh token
- Client POSTs code to
-
Token Usage
- Client includes token in
Authorization: Bearer <token>header - Server validates token on each request
- Client includes token in
Security Features
- PKCE Required - Only S256 code challenge method supported
- JWT Tokens - Cryptographically signed with RS256 or HS256
- Token Expiration - Configurable lifetimes with automatic cleanup
- GitHub User Validation - Restrict access to specific GitHub users
- Redis Token Storage - Tokens can be revoked immediately
- Registration Access Tokens - Secure client management
Docker Deployment
The service is designed to run in Docker with the MCP OAuth Gateway:
services:
auth:
image: mcp-oauth-dynamicclient:latest
environment:
- GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID}
- GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET}
- JWT_SECRET=${JWT_SECRET}
- JWT_ALGORITHM=RS256
- JWT_PRIVATE_KEY_B64=${JWT_PRIVATE_KEY_B64}
- BASE_DOMAIN=${BASE_DOMAIN}
- REDIS_URL=redis://redis:6379/0
- REDIS_PASSWORD=${REDIS_PASSWORD}
- ACCESS_TOKEN_LIFETIME=1800
- REFRESH_TOKEN_LIFETIME=31536000
- SESSION_TIMEOUT=300
- CLIENT_LIFETIME=7776000
- ALLOWED_GITHUB_USERS=${ALLOWED_GITHUB_USERS}
- MCP_PROTOCOL_VERSION=2025-06-18
depends_on:
- redis
networks:
- internal
labels:
- "traefik.enable=true"
- "traefik.http.routers.auth.rule=Host(`auth.${BASE_DOMAIN}`)"
- "traefik.http.routers.auth.tls=true"
- "traefik.http.routers.auth.tls.certresolver=letsencrypt"
Traefik Integration
Configure Traefik to use this service for authentication:
# ForwardAuth middleware
- "traefik.http.middlewares.auth.forwardauth.address=http://auth:8000/verify"
- "traefik.http.middlewares.auth.forwardauth.authResponseHeaders=X-User-Id,X-User-Name,X-Auth-Token"
# Apply to protected services
- "traefik.http.routers.myservice.middlewares=auth"
Development
Running tests
# Start dependencies
docker-compose up -d redis
# Run tests
pytest
Development mode
# Install in development mode
pip install -e .
# Run with auto-reload
mcp-oauth-server --reload
Configuration Reference
| Environment Variable | Description | Default | Required |
|---|---|---|---|
GITHUB_CLIENT_ID |
GitHub OAuth App Client ID | - | Yes |
GITHUB_CLIENT_SECRET |
GitHub OAuth App Client Secret | - | Yes |
JWT_SECRET |
Secret key for HS256 JWT signing | - | Yes |
JWT_ALGORITHM |
JWT signing algorithm (RS256 or HS256) | - | Yes |
JWT_PRIVATE_KEY_B64 |
Base64 encoded RSA private key (RS256 only) | - | If RS256 |
BASE_DOMAIN |
Base domain for OAuth URLs | - | Yes |
REDIS_URL |
Redis connection URL | - | Yes |
REDIS_PASSWORD |
Redis password | - | No |
ACCESS_TOKEN_LIFETIME |
Access token lifetime in seconds | - | Yes |
REFRESH_TOKEN_LIFETIME |
Refresh token lifetime in seconds | - | Yes |
SESSION_TIMEOUT |
OAuth state timeout in seconds | - | Yes |
CLIENT_LIFETIME |
Client registration lifetime (0=never) | - | Yes |
ALLOWED_GITHUB_USERS |
Comma-separated GitHub usernames or '*' | - | Yes |
MCP_PROTOCOL_VERSION |
MCP protocol version | - | Yes |
License
Apache-2.0 License
Contributing
Contributions are welcome! Please ensure:
- All tests pass with real Redis (no mocks!)
- Code follows the established patterns
- New endpoints are RFC compliant
- Documentation is updated
See CLAUDE.md for detailed development guidelines.
Project details
Release history Release notifications | RSS feed
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_oauth_dynamicclient-0.2.0.tar.gz.
File metadata
- Download URL: mcp_oauth_dynamicclient-0.2.0.tar.gz
- Upload date:
- Size: 33.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
deb37ea9f1288466424afeb8bbc5329499fa798477f2cfd143d832e2b0cfa332
|
|
| MD5 |
e5669bae7588dea339c365304754deed
|
|
| BLAKE2b-256 |
31bfc5cedfb49026ee7f6e5dd3a0b7a026b84b9dd023664840e07754d3daa88e
|
File details
Details for the file mcp_oauth_dynamicclient-0.2.0-py3-none-any.whl.
File metadata
- Download URL: mcp_oauth_dynamicclient-0.2.0-py3-none-any.whl
- Upload date:
- Size: 35.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b1ee361fa4ff06916155143bf521f8d8b317c25d75b75ac3ec21939fb5600b1b
|
|
| MD5 |
b2296254d799e157d7fcc882fe6bf065
|
|
| BLAKE2b-256 |
3aa564fc05e962a417867b883d5f286b3e64f24b66b9f3848b40b9eacdf0a11d
|