-
-
Notifications
You must be signed in to change notification settings - Fork 108
OAuth 2.1 Setup Guide
Complete guide for setting up OAuth 2.1 Dynamic Client Registration with MCP Memory Service to enable Claude Code HTTP transport and team collaboration features.
MCP Memory Service v7.0.0 introduces OAuth 2.1 Dynamic Client Registration (RFC 7591) for enterprise-ready authentication. This enables:
- 🔗 Claude Code HTTP Transport: Direct team collaboration support
- 🔐 Automatic Client Registration: Zero-configuration setup for OAuth clients
- 🛡️ Enterprise Security: JWT-based authentication with proper scope validation
- 🔄 Backward Compatibility: Existing API key authentication continues to work
Set the OAuth environment variable and start the server:
# Enable OAuth 2.1
export MCP_OAUTH_ENABLED=true
# Start HTTP server with OAuth
uv run memory server --http
# Your server now supports OAuth at http://localhost:8000
Verify OAuth is working:
# Test OAuth discovery
curl http://localhost:8000/.well-known/oauth-authorization-server/mcp
# Test client registration
curl -X POST http://localhost:8000/oauth/register \
-H "Content-Type: application/json" \
-d '{"client_name": "Test Client"}'
Claude Code will automatically discover and register:
# Add HTTP transport server
claude mcp add --transport http memory-service http://localhost:8000/mcp
# Claude Code automatically:
# ✅ Discovers OAuth endpoints
# ✅ Registers as OAuth client
# ✅ Completes authorization
# ✅ Uses JWT tokens for requests
Essential OAuth configuration variables:
Variable | Default | Description |
---|---|---|
MCP_OAUTH_ENABLED |
true |
Enable/disable OAuth 2.1 endpoints |
MCP_OAUTH_SECRET_KEY |
Auto-generated | JWT signing key (set for persistence) |
MCP_OAUTH_ISSUER |
Auto-detected | OAuth issuer URL |
MCP_OAUTH_ACCESS_TOKEN_EXPIRE_MINUTES |
60 |
Access token lifetime |
MCP_OAUTH_AUTHORIZATION_CODE_EXPIRE_MINUTES |
10 |
Authorization code lifetime |
Secure Production Setup:
# Essential production settings
export MCP_OAUTH_ENABLED=true
export MCP_OAUTH_SECRET_KEY="your-secure-256-bit-secret-key"
export MCP_OAUTH_ISSUER="https://your-domain.com"
export MCP_HTTPS_ENABLED=true
# Optional security enhancements
export MCP_OAUTH_ACCESS_TOKEN_EXPIRE_MINUTES=30 # Shorter token lifetime
export MCP_API_KEY="fallback-api-key" # Dual authentication
Development Configuration:
# Local development settings
export MCP_OAUTH_ENABLED=true
export MCP_OAUTH_ISSUER="http://localhost:8000" # Match server port
export MCP_HTTPS_ENABLED=false # Optional for localhost
OAuth clients use these for automatic discovery:
-
GET /.well-known/oauth-authorization-server/mcp
- OAuth server metadata -
GET /.well-known/openid-configuration/mcp
- OpenID Connect discovery
Core OAuth 2.1 flow endpoints:
-
POST /oauth/register
- Dynamic client registration -
GET /oauth/authorize
- Authorization endpoint -
POST /oauth/token
- Token endpoint
For debugging and administration:
-
GET /oauth/clients/{client_id}
- Client information
Claude Code automatically handles the complete OAuth flow:
-
Discovery: Requests
/.well-known/oauth-authorization-server/mcp
- Registration: Automatically registers as OAuth client
- Authorization: Completes authorization (auto-approved in current version)
- Token Exchange: Exchanges authorization code for access token
- API Access: Uses Bearer token for all MCP-over-HTTP requests
Simple Setup:
# Start OAuth-enabled server
export MCP_OAUTH_ENABLED=true
uv run memory server --http
# Add to Claude Code (automatic OAuth)
claude mcp add --transport http memory-service http://localhost:8000/mcp
For custom OAuth settings:
{
"memoryService": {
"protocol": "http",
"http": {
"endpoint": "http://localhost:8000",
"oauth": {
"enabled": true,
"discoveryUrl": "http://localhost:8000/.well-known/oauth-authorization-server/mcp",
"clientName": "My Claude Code Instance"
}
}
}
}
Primary authentication method for HTTP transport:
# Get access token via OAuth flow
export ACCESS_TOKEN="your-jwt-access-token"
# Use Bearer token for API requests
curl -H "Authorization: Bearer $ACCESS_TOKEN" \
http://localhost:8000/api/memories
Continues to work for backward compatibility:
# Legacy API key authentication
export MCP_API_KEY="your-api-key"
curl -H "Authorization: Bearer $MCP_API_KEY" \
http://localhost:8000/api/memories
Both methods can be used simultaneously:
# Environment supports both
export MCP_OAUTH_ENABLED=true # OAuth for new clients
export MCP_API_KEY="fallback-key" # API key for legacy clients
OAuth supports fine-grained permissions:
-
read
: Access to read-only endpoints -
write
: Access to create/update endpoints -
admin
: Access to administrative endpoints
- ✅ Use HTTPS: Always enable HTTPS for production deployments
- ✅ Set Secret Key: Provide secure
MCP_OAUTH_SECRET_KEY
for JWT signing - ✅ Secure Storage: Use persistent storage for production client data
- ✅ Monitor Access: Implement logging and monitoring for OAuth endpoints
- ✅ Rate Limiting: Consider rate limiting for OAuth registration/token endpoints
The implementation follows OAuth 2.1 security best practices:
- 🔒 HTTPS required for non-localhost URLs
- 🔑 Secure client credential generation
- 🎫 JWT access tokens with proper validation
- ⏰ Authorization code expiration (configurable)
- 🎯 Proper redirect URI validation
OAuth endpoints return 404:
# Check if OAuth is enabled
echo $MCP_OAUTH_ENABLED # Should be 'true'
# Restart server after configuration changes
uv run memory server --http
Claude Code connection fails:
# Test OAuth discovery
curl http://localhost:8000/.well-known/oauth-authorization-server/mcp
# Check server logs
tail -f logs/mcp-memory-service.log | grep -i oauth
# Verify HTTPS configuration for production
openssl s_client -connect your-domain.com:443
Invalid token errors:
# Check JWT secret consistency
echo $MCP_OAUTH_SECRET_KEY
# Verify token hasn't expired
# Check server logs for JWT validation errors
Test Complete OAuth Flow:
# 1. Test discovery
curl http://localhost:8000/.well-known/oauth-authorization-server/mcp
# 2. Test client registration
curl -X POST http://localhost:8000/oauth/register \
-H "Content-Type: application/json" \
-d '{"client_name": "Debug Client", "redirect_uris": ["http://localhost:3000/callback"]}'
# 3. Check server health with OAuth status
curl http://localhost:8000/api/health
Enable Debug Logging:
# Start with OAuth debug logging
export LOG_LEVEL=DEBUG
export MCP_OAUTH_ENABLED=true
uv run memory server --http --debug
# Monitor OAuth activity
tail -f logs/mcp-memory-service.log | grep -E "(oauth|jwt|auth)"
{
"client_name": "My Application",
"redirect_uris": ["https://myapp.com/callback"],
"grant_types": ["authorization_code"],
"response_types": ["code"],
"scope": "read write"
}
{
"client_id": "mcp_client_abc123",
"client_secret": "secret_xyz789",
"redirect_uris": ["https://myapp.com/callback"],
"grant_types": ["authorization_code"],
"response_types": ["code"],
"token_endpoint_auth_method": "client_secret_basic"
}
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read write"
}
# Test OAuth functionality
python tests/integration/test_oauth_flow.py
# Run full OAuth test suite
pytest tests/ -k oauth -v
# Manual OAuth flow testing
./scripts/test_oauth_flow.sh
# Example Python OAuth client
import requests
# Step 1: Register client
registration_data = {
"client_name": "My Custom Client",
"redirect_uris": ["http://localhost:3000/callback"]
}
response = requests.post(
"http://localhost:8000/oauth/register",
json=registration_data
)
client_info = response.json()
# Step 2: Start authorization flow
auth_url = f"http://localhost:8000/oauth/authorize?" \
f"client_id={client_info['client_id']}&" \
f"response_type=code&" \
f"redirect_uri=http://localhost:3000/callback&" \
f"scope=read write"
# Step 3: Exchange code for token (after user authorization)
token_data = {
"grant_type": "authorization_code",
"code": "received_auth_code",
"redirect_uri": "http://localhost:3000/callback",
"client_id": client_info['client_id'],
"client_secret": client_info['client_secret']
}
token_response = requests.post(
"http://localhost:8000/oauth/token",
data=token_data
)
access_token = token_response.json()['access_token']
# Step 4: Use access token for API requests
headers = {"Authorization": f"Bearer {access_token}"}
memories = requests.get("http://localhost:8000/api/memories", headers=headers)
- Integration Guide - Complete integration instructions
- Advanced Configuration - Advanced OAuth settings
- Troubleshooting - OAuth-specific troubleshooting
- Claude Code Commands Wiki - Claude Code integration details
- OAuth 2.1 Specification - OAuth 2.1 standard
- RFC 7591 - Dynamic Client Registration
- RFC 8414 - Authorization Server Metadata
- JWT RFC 7519 - JSON Web Token standard
Ready to enable enterprise-grade team collaboration? Follow this guide to set up OAuth 2.1 with Claude Code HTTP transport!