Install
$ agentstack add mcp-atrawog-mcp-oauth-gateway ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ● Shell / process execution Used
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
MCP OAuth Gateway
An OAuth 2.1 Authorization Server that adds authentication to any MCP (Model Context Protocol) server without code modification. The gateway acts as an OAuth Authorization Server while using GitHub as the Identity Provider (IdP) for user authentication.
📖 View Documentation | 🔧 Installation Guide | 🏗️ Architecture Overview
⚠️ Important Notice
This is a reference implementation and test platform for the MCP protocol.
- Primary Purpose: Reference implementation for MCP protocol development and testing
- Experimental Nature: Used as a test platform for future MCP protocol iterations
- Security Disclaimer: While this implementation strives for security best practices, this implementation likely contains bugs and security vulnerabilities
- Production Warning: NOT recommended for production use without thorough security review
- Use at Your Own Risk: This is experimental software intended for development and testing
🏗️ Architecture
Overview
The MCP OAuth Gateway is a zero-modification authentication layer for MCP servers. It implements OAuth 2.1 with dynamic client registration (RFC 7591/7592) and leverages GitHub as the identity provider for user authentication. The architecture follows these core principles:
- Complete Separation of Concerns: Authentication, routing, and MCP protocol handling are strictly isolated
- No MCP Server Modifications: Official MCP servers run unmodified, wrapped only for HTTP transport
- Standards Compliance: Full OAuth 2.1, RFC 7591/7592, and MCP protocol compliance
- Production-Ready Security: HTTPS everywhere, PKCE mandatory, JWT tokens, secure session management
- Dynamic Service Discovery: Services can be enabled/disabled via configuration
System Components
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ EXTERNAL CLIENTS │
│ (Claude.ai, MCP CLI tools, IDE extensions, Custom integrations) │
└─────────────────────────────────────────────────────────────────────────────────────┘
│
HTTPS │ :443
↓
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ TRAEFIK REVERSE PROXY │
│ (Layer 1: Routing & TLS Termination) │
├─────────────────────────────────────────────────────────────────────────────────────┤
│ • Let's Encrypt automatic HTTPS certificates for all subdomains │
│ • Priority-based routing rules (OAuth > Verify > MCP > Catch-all) │
│ • ForwardAuth middleware for MCP endpoints → Auth Service /verify │
│ • Request routing based on subdomain and path: │
│ - auth.domain.com/* → Auth Service (no auth required) │
│ - *.domain.com/.well-known/* → Auth Service (OAuth discovery) │
│ - *.domain.com/mcp → MCP Services (auth required via ForwardAuth) │
│ • Docker service discovery via labels │
└─────────────────────────────────────────────────────────────────────────────────────┘
│ │
│ OAuth/Auth Requests │ MCP Requests
│ (unauthenticated) │ (authenticated)
↓ ↓
┌───────────────────────────────────────────┐ ┌─────────────────────────────────────┐
│ AUTH SERVICE │ │ MCP SERVICES │
│ (Layer 2: OAuth Authorization Server) │ │ (Layer 3: Protocol Handlers) │
├───────────────────────────────────────────┤ ├─────────────────────────────────────┤
│ Container: auth:8000 │ │ Containers: │
│ Package: mcp-oauth-dynamicclient │ │ • mcp-echo-stateful:3000 │
│ │ │ • mcp-echo-stateless:3000 │
│ │ │ • mcp-fetch:3000 │
│ OAuth Endpoints: │ │ • mcp-memory:3000 │
│ • POST /register (RFC 7591) │ │ • mcp-time:3000 │
│ • GET /authorize + /callback │ │ • ... (dynamically enabled) │
│ • POST /token │ │ │
│ • GET /.well-known/* (RFC 8414) │ │ Architecture: │
│ • POST /revoke, /introspect │ │ • mcp-streamablehttp-proxy wrapper │
│ │ │ • Spawns official MCP stdio servers │
│ Management Endpoints (RFC 7592): │ │ • Bridges stdio ↔ HTTP/SSE │
│ • GET/PUT/DELETE /register/{client_id} │ │ • No OAuth knowledge │
│ │ │ • Receives user identity in headers │
│ Internal Endpoints: │ │ │
│ • GET/POST /verify (ForwardAuth) │ │ Protocol Endpoints: │
│ │ │ • POST /mcp (JSON-RPC over HTTP) │
│ External Integration: │←---│ • GET /mcp (SSE for async messages) │
│ • GitHub OAuth (user authentication) │ │ • Health checks on /health │
└───────────────────────────────────────────┘ └─────────────────────────────────────┘
│ ↑
│ │
└──────────────┬───────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ REDIS STORAGE LAYER │
│ (Persistent State Management) │
├─────────────────────────────────────────────────────────────────────────────────────┤
│ Container: redis:6379 │
│ Persistence: AOF + RDB snapshots │
│ │
│ Data Structures: │
│ • oauth:client:{client_id} → OAuth client registrations (90 days / eternal) │
│ • oauth:state:{state} → Authorization flow state (5 minutes) │
│ • oauth:code:{code} → Authorization codes + user info (1 year) │
│ • oauth:token:{jti} → JWT token tracking for revocation (30 days) │
│ • oauth:refresh:{token} → Refresh token data (1 year) │
│ • oauth:user_tokens:{username} → User's active tokens index │
│ • redis:session:{id}:state → MCP session state (managed by proxy) │
│ • redis:session:{id}:messages → MCP message queues │
└─────────────────────────────────────────────────────────────────────────────────────┘
NETWORK TOPOLOGY: • All services connected via 'public' Docker network • Internal service communication only (except Traefik ingress) • Redis exposed on localhost:6379 for debugging only • Each MCP service runs in isolated container with no shared state
Security Architecture
Authentication Layers
- TLS/HTTPS: Enforced by Traefik for all external communication
- OAuth Client Authentication: clientid + clientsecret at token endpoint
- User Authentication: GitHub OAuth with ALLOWEDGITHUBUSERS whitelist
- Token Authentication: JWT Bearer tokens for API access
- PKCE Protection: Mandatory S256 code challenges
Security Boundaries
- Public Access: Only /register and /.well-known/* endpoints
- Client-Authenticated: /token endpoint requires client credentials
- User-Authenticated: /authorize requires GitHub login
- Bearer-Authenticated: All /mcp endpoints require valid JWT
- Registration-Token-Authenticated: Client management endpoints (RFC 7592)
Token Types and Scopes
- registrationaccesstoken: Bearer token for client management only (RFC 7592)
- accesstoken: JWT containing user identity + clientid for MCP access
- refresh_token: Opaque token for obtaining new access tokens
- authorization_code: One-time code binding user to client
Architectural Decisions
Why Three Layers?
- Traefik (Routing): Centralizes TLS, routing, and auth enforcement
- Auth Service (OAuth): Isolated OAuth implementation, no MCP knowledge
- MCP Services (Protocol): Pure MCP protocol handlers, no auth knowledge
Why mcp-streamablehttp-proxy?
- Wraps official stdio-based MCP servers without modification
- Provides HTTP transport required for web clients
- Manages subprocess lifecycle and session state
- Enables horizontal scaling possibilities
Why Redis?
- Fast, reliable state storage for OAuth flows
- Supports atomic operations for security
- Built-in TTL for automatic cleanup
- Enables distributed deployment if needed
Why GitHub OAuth?
- Trusted identity provider for developers
- No password management needed
- Strong security with 2FA support
- Rich user profile information
OAuth Architecture: Client Credentials + User Authentication
The gateway implements a multi-layered OAuth 2.1 authorization system that integrates client credential authentication with GitHub OAuth identity federation:
The gateway implements a sophisticated OAuth 2.1 system with three distinct authentication flows:
- GitHub Device Flow (RFC 8628) - For command-line/browserless scenarios
- GitHub OAuth Web Flow - For browser-based end-user authentication
- Dynamic Client Registration (RFC 7591) - For MCP client registration
Authentication Flow Decision Tree
Need Authentication?
├─> For Gateway's Own GitHub Access?
│ └─> Use Device Flow: `just generate-github-token`
│ - Shows code: "Visit github.com/login/device"
│ - No browser redirect needed
│ - Stores GITHUB_PAT in .env
│
├─> For MCP Client Token?
│ └─> Use Device Flow: `just mcp-client-token`
│ - Client uses device flow for browserless auth
│ - Stores MCP_CLIENT_ACCESS_TOKEN in .env
│
└─> For End User Access (Browser)?
└─> Use Standard OAuth Flow
- User visits protected resource
- Redirected to GitHub for login
- Redirected back to gateway
- JWT issued with user+client identity
The gateway implementation combines client credential authentication with GitHub user authentication:
╔═══════════════════════════════════════════════════════════════════════════════════╗
║ OAUTH CLIENT REGISTRATION (RFC 7591/7592) ║
╠═══════════════════════════════════════════════════════════════════════════════════╣
║ ║
║ 📝 STEP 1: CLIENT REGISTRATION (No Authentication Required) ║
║ ┌─────────────────────────────────────────────────────────────────────────────┐ ║
║ │ POST /register │ ║
║ │ • Public endpoint - any MCP client can register │ ║
║ │ • Creates OAuth client application credentials │ ║
║ │ │ ║
║ │ Request Body: │ ║
║ │ { │ ║
║ │ "redirect_uris": ["https://example.com/callback"], │ ║
║ │ "client_name": "My MCP Client" │ ║
║ │ } │ ║
║ │ │ ║
║ │ Response: │ ║
║ │ • client_id: "client_abc123..." ← OAuth client credentials │ ║
║ │ • client_secret: "secret_xyz789..." ← Used at /token endpoint │ ║
║ │ • registration_access_token: "reg_tok..."← ONLY for client management │ ║
║ │ • registration_client_uri: "https://auth.../register/client_abc123" │ ║
║ └─────────────────────────────────────────────────────────────────────────────┘ ║
║ ║
║ 🔧 OPTIONAL: CLIENT MANAGEMENT (Requires registration_access_token) ║
║ ┌─────────────────────────────────────────────────────────────────────────────┐ ║
║ │ Authorization: Bearer │ ║
║ │ │ ║
║ │ • GET /register/{client_id} - View client configuration │ ║
║ │ • PUT /register/{client_id} - Update redirect URIs, etc. │ ║
║ │ • DELETE /register/{client_id} - Delete client registration │ ║
║ │ │ ║
║ │ Note: This token is ONLY for managing the client registration, │ ║
║ │ NOT for accessing MCP resources! │ ║
║ └─────────────────────────────────────────────────────────────────────────────┘ ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════════════╝
↓
Client has credentials, now needs user authorization
↓
╔═══════════════════════════════════════════════════════════════════════════════════╗
║ USER AUTHENTICATION FLOW (GitHub OAuth) ║
╠═══════════════════════════════════════════════════════════════════════════════════╣
║ ║
║ 👤 STEP 2: USER AUTHORIZATION (Human authenticates via GitHub) ║
║ ┌─────────────────────────────────────────────────────────────────────────────┐ ║
║ │ GET /authorize?client_id=client_abc123&redirect_uri=...&code_challenge=... │ ║
║ │ │ ║
║ │ 1. Gateway validates client_id exists │ ║
║ │ 2. Redirects user to GitHub OAuth: │ ║
║ │ → User logs into GitHub │ ║
║ │ → GitHub authenticates the human user │ ║
║ │ → Returns to gateway /callback with GitHub user info │ ║
║ │ 3. Gateway checks ALLOWED_GITHUB_USERS whitelist │ ║
║ │ 4. Creates authorization code tied to: │ ║
║ │ • The OA
…
## Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [atrawog](https://github.com/atrawog)
- **Source:** [atrawog/mcp-oauth-gateway](https://github.com/atrawog/mcp-oauth-gateway)
- **License:** Apache-2.0
- **Homepage:** https://atrawog.github.io/mcp-oauth-gateway/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.