diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index aa0bec9..754e5a0 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -28,7 +28,7 @@ jobs:
fetch-depth: 0
- name: Setup Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
@@ -40,7 +40,7 @@ jobs:
- name: Setup Pages
id: pages
- uses: actions/configure-pages@v3
+ uses: actions/configure-pages@v4
if: github.ref == 'refs/heads/main'
- name: Build documentation
@@ -51,7 +51,7 @@ jobs:
mkdocs build --clean --strict
- name: Upload Pages artifact
- uses: actions/upload-pages-artifact@v2
+ uses: actions/upload-pages-artifact@v3
if: github.ref == 'refs/heads/main'
with:
path: ./site
@@ -66,4 +66,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
- uses: actions/deploy-pages@v2
\ No newline at end of file
+ uses: actions/deploy-pages@v4
\ No newline at end of file
diff --git a/docs/architecture.md b/docs/architecture.md
index a35bb62..2c1aced 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -36,9 +36,9 @@ graph TB
end
subgraph "OAuth 2.1 Server"
- AR[/api/oauth/register]
- AT[/api/oauth/token]
- AZ[/oauth/authorize]
+ AR["Client Registration
/api/oauth/register"]
+ AT["Token Endpoint
/api/oauth/token"]
+ AZ["Authorization
/oauth/authorize"]
end
subgraph "MCP Server"
diff --git a/mkdocs.yml b/mkdocs.yml
index 76e0331..0e304e2 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -76,9 +76,9 @@ plugins:
- minify:
minify_html: true
-# Hooks
-hooks:
- - docs/hooks.py
+# Hooks (commented out for now)
+# hooks:
+# - docs/hooks.py
# Extensions
markdown_extensions:
@@ -96,9 +96,7 @@ markdown_extensions:
smart_enable: all
- pymdownx.caret
- pymdownx.details
- - pymdownx.emoji:
- emoji_generator: !!python/name:material.extensions.emoji.to_svg
- emoji_index: !!python/name:material.extensions.emoji.twemoji
+ - pymdownx.emoji
- pymdownx.highlight:
anchor_linenums: true
line_spans: __span
@@ -112,9 +110,7 @@ markdown_extensions:
repo: mcp-oauth-sample
- pymdownx.mark
- pymdownx.smartsymbols
- - pymdownx.snippets:
- auto_append:
- - includes/mkdocs.md
+ - pymdownx.snippets
- pymdownx.superfences:
custom_fences:
- name: mermaid
@@ -123,9 +119,6 @@ markdown_extensions:
- pymdownx.tabbed:
alternate_style: true
combine_header_slug: true
- slugify: !!python/object/apply:pymdownx.slugs.slugify
- kwds:
- case: lower
- pymdownx.tasklist:
custom_checkbox: true
- pymdownx.tilde
@@ -135,7 +128,6 @@ nav:
- Home: index.md
- Getting Started:
- Setup Guide: setup.md
- - Quick Start: index.md#quick-start
- Architecture:
- System Design: architecture.md
- Security Model: security.md
diff --git a/requirements.txt b/requirements.txt
index 13a56fa..c017e80 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,15 +2,8 @@
mkdocs>=1.5.3
mkdocs-material>=9.4.0
-# Plugins
+# Essential plugins
mkdocs-minify-plugin>=0.7.1
-mkdocs-redirects>=1.2.1
# Extensions
-pymdown-extensions>=10.3.1
-markdown-callouts>=0.3.0
-
-# Optional enhancements
-mkdocs-git-revision-date-localized-plugin>=1.2.0
-mkdocs-git-committers-plugin-2>=1.2.0
-mkdocs-awesome-pages-plugin>=2.9.2
\ No newline at end of file
+pymdown-extensions>=10.3.1
\ No newline at end of file
diff --git a/site/404.html b/site/404.html
new file mode 100644
index 0000000..585f646
--- /dev/null
+++ b/site/404.html
@@ -0,0 +1 @@
+
The MCP OAuth Analytics Dashboard provides comprehensive monitoring and insights for your OAuth 2.1 server and MCP (Model Context Protocol) infrastructure. This real-time analytics system tracks user activity, security events, OAuth flows, MCP tool usage, and performance metrics to help you understand and optimize your system.
The analytics dashboard is organized into three expandable sections:
ADMIN_EMAIL environment variable can access the dashboardThe security monitoring system uses the SecurityMonitor class to detect various threats in real-time:
Each security event includes a risk score (0-100): - 0-30: Low risk (informational) - 31-69: Medium risk (requires monitoring) - 70-89: High risk (requires attention) - 90-100: Critical risk (immediate action required)
Dynamic risk scoring based on excess requests
Token Reuse Detection
Detects potential token theft or sharing
Privilege Escalation Detection
Analyzes historical scope patterns
OAuth-Specific Threats
The dashboard tracks detailed client activity including:
Monitors tokens approaching expiration: - Client Name: Which client owns the expiring tokens - Token Count: Number of tokens expiring - Hours Until Expiry: Time remaining before expiration
Tracks OAuth grant type usage patterns: - Authorization Code: Standard OAuth flow usage - Refresh Token: Token refresh operations - Client Credentials: Service-to-service authentication
The analytics system uses PostgreSQL with the following key tables:
Primary table for request tracking with automatic TTL (14 days):
- id: Unique identifier
+- timestamp: Request timestamp (indexed)
+- endpoint: API endpoint accessed
+- method: HTTP method
+- statusCode: Response status
+- responseTime: Response time in ms
+- clientId/userId: Request context (indexed)
+- mcpServerId: MCP server context
+- ipAddress: Client IP (geographic enrichment)
+- userAgent: Client user agent
+- scopes: OAuth scopes (array)
+- oauthGrantType: OAuth flow type
+- usePKCE: PKCE usage flag
+- expiresAt: TTL expiration (indexed)
+Security events with risk scoring:
- id: Unique identifier
+- timestamp: Event timestamp (indexed)
+- eventType: Security event type (enum)
+- severity: Event severity level
+- riskScore: Risk score (0-100)
+- userId/clientId: Context (indexed)
+- ipAddress: Source IP
+- details: JSON event details
+- resolved: Resolution status
+- expiresAt: TTL expiration
+MCP server registry:
- id: Unique identifier
+- name: Human-readable name
+- identifier: MCP protocol identifier
+- description: Optional description
+- version: Server version
+The OptimizedAnalyticsCollector provides high-performance data collection:
IP addresses are enriched with geographic data: - External API: Uses ip-api.com for geolocation - Caching: Results cached to reduce API calls - Fallback: Mock data for localhost development - Timeout Handling: Quick timeouts prevent request delays
Required configuration:
DATABASE_URL=postgresql://... # PostgreSQL connection
+ADMIN_EMAIL=admin@example.com # Dashboard access control
+AUTH_SECRET=your-secret-key # NextAuth secret
+GOOGLE_CLIENT_ID=... # OAuth provider
+GOOGLE_CLIENT_SECRET=... # OAuth provider
+Dashboard supports multiple time ranges: - Last 1 hour - Last 6 hours - Last 24 hours (default) - Last 3 days - Last 7 days
Configurable alerting thresholds: - Error Rate: >5% critical, >1% warning - Response Time: >1000ms critical, >500ms warning - PKCE Adoption: <50% generates warning - Rate Limiting: 30 requests/minute threshold
Parameters: - hours: Time range (1-168 hours)
Response:
{
+ "performance": {
+ "totalRequests": 1234,
+ "avgResponseTime": 245,
+ "p95ResponseTime": 890,
+ "errorRate": 1.2
+ },
+ "oauth": {
+ "totalUsers": 45,
+ "activeUsers": 32,
+ "totalClients": 8,
+ "activeTokens": 67,
+ "pkceAdoption": 89.5,
+ "clients": [...],
+ "expiringTokens": [...]
+ },
+ "security": {
+ "totalEvents": 3,
+ "criticalEvents": 0,
+ "highRiskEvents": 1,
+ "eventsByOrganization": [...],
+ "privilegeEscalations": [...]
+ },
+ "toolUsage": {
+ "tools": [...],
+ "geographic": [...],
+ "timeSeries": [...],
+ "totalCalls": 456,
+ "activeUsers": 23
+ }
+}
+Parameters: - days: Number of days for security analysis
POST /api/analytics/collect
+Content-Type: application/json
+
+{
+ "timestamp": "2024-01-01T10:00:00Z",
+ "endpoint": "/mcp/sse",
+ "method": "GET",
+ "statusCode": 200,
+ "responseTime": 234,
+ "clientId": "client-123",
+ "userId": "user-456",
+ "ipAddress": "192.168.1.1",
+ "userAgent": "MCP-Client/1.0",
+ "mcpMethod": "tools/call",
+ "toolName": "add_numbers"
+}
+POST /api/analytics/security
+Content-Type: application/json
+
+{
+ "timestamp": "2024-01-01T10:00:00Z",
+ "eventType": "RATE_LIMIT_EXCEEDED",
+ "severity": "medium",
+ "ipAddress": "192.168.1.100",
+ "userAgent": "suspicious-client",
+ "details": {
+ "requestCount": 45,
+ "timeWindow": 60000
+ },
+ "riskScore": 75
+}
+POST /api/analytics/generate-threats
+Content-Type: application/json
+
+{
+ "runDetection": true,
+ "mockScenarios": [
+ "privilege_escalation",
+ "token_reuse",
+ "rate_limit_exceeded",
+ "oauth_pkce_bypass"
+ ]
+}
+# Check admin email configuration
+echo $ADMIN_EMAIL
+
+# Verify database connection
+npm run prisma:studio
+
+# Check authentication
+# Visit /api/auth/signin
+# Verify data collection
+curl -X POST http://localhost:3000/api/analytics/collect \
+ -H "Content-Type: application/json" \
+ -d '{"timestamp":"2024-01-01T10:00:00Z","endpoint":"/test","method":"GET","statusCode":200,"responseTime":100,"ipAddress":"127.0.0.1","userAgent":"test"}'
+
+# Check database
+npm run prisma:studio
+# Look for AnalyticsRequest records
+# Check database indexes
+psql $DATABASE_URL -c "\d+ AnalyticsRequest"
+
+# Monitor batch processing
+# Look for analytics logs in application output
+
+# Check TTL cleanup
+psql $DATABASE_URL -c "SELECT COUNT(*) FROM \"AnalyticsRequest\" WHERE \"expiresAt\" < NOW();"
+-- Remove expired records
+DELETE FROM "AnalyticsRequest" WHERE "expiresAt" < NOW();
+DELETE FROM "AnalyticsSecurity" WHERE "expiresAt" < NOW();
+
+-- Check table sizes
+SELECT
+ schemaname,
+ tablename,
+ pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as size
+FROM pg_tables
+WHERE schemaname = 'public'
+ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;
+-- Analyze query performance
+EXPLAIN ANALYZE SELECT * FROM "AnalyticsRequest"
+WHERE timestamp >= NOW() - INTERVAL '24 hours';
+
+-- Rebuild indexes if needed
+REINDEX TABLE "AnalyticsRequest";
+SecurityMonitor classThis analytics system provides comprehensive visibility into your MCP OAuth infrastructure, enabling proactive monitoring, security threat detection, and performance optimization.
This document provides comprehensive documentation for the MCP OAuth 2.1 server API, including authentication, OAuth endpoints, MCP integration, analytics, and administrative functions.
The MCP OAuth server provides a comprehensive OAuth 2.1 authorization server with Model Context Protocol (MCP) integration. The server supports:
All endpoints use implicit versioning. The current API version is v1.
application/json, application/x-www-form-urlencodedapplication/json.well-known/*)/mcp/*)/api/analytics/*)/api/cleanup, /api/test/*)Used for web UI and analytics dashboard access.
Dynamic client registration following RFC 7591.
Request Body:
{
+ "client_name": "My MCP Client",
+ "redirect_uris": [
+ "http://localhost:3000/callback",
+ "https://myapp.com/oauth/callback"
+ ]
+}
+Response (201 Created):
{
+ "client_id": "cluid123456789",
+ "client_secret": "secret_abc123...",
+ "redirect_uris": [
+ "http://localhost:3000/callback",
+ "https://myapp.com/oauth/callback"
+ ]
+}
+Error Responses:
cURL Example:
curl -X POST https://your-domain.com/api/oauth/register \
+ -H "Content-Type: application/json" \
+ -d '{
+ "client_name": "Test Client",
+ "redirect_uris": ["http://localhost:3000/callback"]
+ }'
+OAuth 2.1 authorization endpoint with PKCE support.
Query Parameters:
| Parameter | Required | Description |
|---|---|---|
client_id | Yes | Client identifier |
redirect_uri | Yes | Redirect URI (must match registered) |
response_type | Yes | Must be code |
state | Recommended | CSRF protection token |
code_challenge | Optional | PKCE code challenge |
code_challenge_method | Optional | S256 or plain |
resource | Optional | Target resource identifier |
Example Request:
GET /oauth/authorize?client_id=cluid123&redirect_uri=http://localhost:3000/callback&response_type=code&state=xyz&code_challenge=abc123&code_challenge_method=S256
+Success Response:
Redirect to redirect_uri with authorization code:
Error Response:
Redirect to redirect_uri with error:
Exchange authorization code or refresh token for access tokens.
Authorization Code Grant:
grant_type=authorization_code
+&code=auth_code_123
+&redirect_uri=http://localhost:3000/callback
+&client_id=cluid123
+&client_secret=secret_abc123
+&code_verifier=verifier_xyz
+&resource=https://your-domain.com
+Refresh Token Grant:
grant_type=refresh_token
+&refresh_token=refresh_abc123
+&client_id=cluid123
+&client_secret=secret_abc123
+&resource=https://your-domain.com
+Success Response (200 OK):
{
+ "access_token": "token_abc123...",
+ "refresh_token": "refresh_xyz789...",
+ "token_type": "Bearer",
+ "expires_in": 300
+}
+Error Responses:
cURL Examples:
# Authorization Code Grant
+curl -X POST https://your-domain.com/api/oauth/token \
+ -H "Content-Type: application/x-www-form-urlencoded" \
+ -d "grant_type=authorization_code&code=auth_code_123&redirect_uri=http://localhost:3000/callback&client_id=cluid123&client_secret=secret_abc123&code_verifier=verifier_xyz"
+
+# Refresh Token Grant
+curl -X POST https://your-domain.com/api/oauth/token \
+ -H "Content-Type: application/x-www-form-urlencoded" \
+ -d "grant_type=refresh_token&refresh_token=refresh_abc123&client_id=cluid123&client_secret=secret_abc123"
+Model Context Protocol endpoints for authenticated tool execution.
Authentication:
Available Tools:
Example Tool Call:
{
+ "method": "tools/call",
+ "params": {
+ "name": "add_numbers",
+ "arguments": {
+ "a": 5,
+ "b": 3
+ }
+ }
+}
+Success Response:
Error Response (401 Unauthorized):
cURL Example:
curl -X POST https://your-domain.com/mcp/sse \
+ -H "Authorization: Bearer token_abc123..." \
+ -H "Content-Type: application/json" \
+ -d '{
+ "method": "tools/call",
+ "params": {
+ "name": "add_numbers",
+ "arguments": {"a": 5, "b": 3}
+ }
+ }'
+All MCP endpoints include:
Comprehensive analytics and monitoring system.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
hours | integer | 24 | Time range in hours (1-168) |
Example Request:
Success Response (200 OK):
{
+ "performance": {
+ "totalRequests": 1250,
+ "averageResponseTime": 145.2,
+ "successRate": 98.4,
+ "activeUsers": 45
+ },
+ "topEndpoints": [
+ {
+ "endpoint": "/mcp/sse",
+ "count": 856,
+ "averageResponseTime": 120.5
+ }
+ ],
+ "geography": {
+ "byCountry": [
+ {"country": "United States", "requestCount": 750},
+ {"country": "Canada", "requestCount": 200}
+ ]
+ },
+ "oauth": {
+ "totalTokens": 123,
+ "activeTokens": 89,
+ "clients": [
+ {
+ "clientName": "Test Client",
+ "requestCount": 456,
+ "lastActivity": "2024-01-15T10:30:00Z"
+ }
+ ],
+ "expiringTokens": 5,
+ "grantTypes": [
+ {"grantType": "authorization_code", "count": 100},
+ {"grantType": "refresh_token", "count": 23}
+ ]
+ },
+ "toolUsage": {
+ "tools": [
+ {
+ "toolName": "add_numbers",
+ "usageCount": 234,
+ "uniqueUsers": 12,
+ "averageResponseTime": 95.2
+ }
+ ],
+ "totalCalls": 567,
+ "activeUsers": 23
+ },
+ "security": {
+ "totalEvents": 12,
+ "criticalEvents": 2,
+ "events": [
+ {
+ "eventType": "INVALID_TOKEN",
+ "severity": "high",
+ "timestamp": "2024-01-15T10:30:00Z",
+ "details": "Token audience mismatch"
+ }
+ ]
+ },
+ "timeRange": "72 hours",
+ "lastUpdated": "2024-01-15T12:00:00Z"
+}
+Request Body:
{
+ "timestamp": "2024-01-15T12:00:00Z",
+ "endpoint": "/mcp/sse",
+ "method": "POST",
+ "statusCode": 200,
+ "responseTime": 125,
+ "clientId": "client_123",
+ "userId": "user_456",
+ "ipAddress": "192.168.1.100",
+ "userAgent": "Mozilla/5.0...",
+ "mcpMethod": "tools/call",
+ "toolName": "add_numbers"
+}
+Response (200 OK):
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
days | integer | 30 | Time range in days |
Success Response:
{
+ "success": true,
+ "data": {
+ "totalEvents": 45,
+ "criticalEvents": 5,
+ "eventsByType": [
+ {"eventType": "INVALID_TOKEN", "count": 12},
+ {"eventType": "RATE_LIMIT_EXCEEDED", "count": 8}
+ ],
+ "eventsBySeverity": [
+ {"severity": "critical", "count": 5},
+ {"severity": "high", "count": 15}
+ ]
+ },
+ "timeRange": {
+ "startDate": "2024-01-01T00:00:00Z",
+ "endDate": "2024-01-15T12:00:00Z",
+ "days": 30
+ }
+}
+Request Body:
{
+ "timestamp": "2024-01-15T12:00:00Z",
+ "eventType": "INVALID_TOKEN",
+ "ipAddress": "192.168.1.100",
+ "userAgent": "curl/7.68.0",
+ "clientId": "client_123",
+ "details": "Token audience mismatch detected"
+}
+OAuth 2.1 and MCP discovery metadata endpoints.
Response (200 OK):
{
+ "issuer": "https://your-domain.com",
+ "authorization_endpoint": "https://your-domain.com/oauth/authorize",
+ "token_endpoint": "https://your-domain.com/api/oauth/token",
+ "registration_endpoint": "https://your-domain.com/api/oauth/register",
+ "scopes_supported": ["read", "write"],
+ "response_types_supported": ["code"],
+ "grant_types_supported": ["authorization_code", "refresh_token"],
+ "code_challenge_methods_supported": ["S256", "plain"],
+ "token_endpoint_auth_methods_supported": ["client_secret_post", "none"],
+ "resource_parameter_supported": true
+}
+Response (200 OK):
{
+ "resource": "https://your-domain.com",
+ "authorization_servers": ["https://your-domain.com"],
+ "scopes_supported": ["read", "write"],
+ "bearer_methods_supported": ["header"],
+ "mcp_endpoints": [
+ "https://your-domain.com/mcp/mcp",
+ "https://your-domain.com/mcp/sse"
+ ]
+}
+Administrative endpoints for system maintenance and testing.
Success Response:
Success Response:
{
+ "message": "TTL status retrieved successfully",
+ "data": {
+ "expiredTokens": 15,
+ "expiredAnalytics": 250,
+ "nextCleanup": "2024-01-16T00:00:00Z"
+ }
+}
+Request Body:
Available Event Types:
AUTH_FAILURE - Authentication failuresINVALID_TOKEN - Token validation failuresSUSPICIOUS_ACTIVITY - Suspicious user agents/behaviorRATE_LIMIT_EXCEEDED - API rate limit violationsTOKEN_REUSE - Cross-IP token usageUNUSUAL_LOCATION - Geographic anomaliesPRIVILEGE_ESCALATION - OAuth scope escalationBRUTE_FORCE_ATTEMPT - Credential attacksOAUTH_INVALID_CLIENT - PKCE bypass attemptsOAUTH_INVALID_GRANT - Missing resource parametersSuccess Response:
Request Body:
{
+ "runDetection": true,
+ "mockScenarios": [
+ "privilege_escalation",
+ "token_reuse",
+ "rate_limit_exceeded",
+ "oauth_pkce_bypass"
+ ]
+}
+Success Response:
{
+ "success": true,
+ "message": "SecurityMonitor detected and logged 8 realistic threats",
+ "threatsDetected": 8,
+ "scenarios": ["privilege_escalation", "token_reuse"]
+}
+All endpoints return errors in a consistent format:
{
+ "error": "error_code",
+ "error_description": "Human readable error description",
+ "details": "Additional error details (optional)"
+}
+| Code | Meaning | Description |
|---|---|---|
| 200 | OK | Successful request |
| 201 | Created | Resource created successfully |
| 400 | Bad Request | Invalid request parameters |
| 401 | Unauthorized | Authentication required |
| 403 | Forbidden | Insufficient permissions |
| 404 | Not Found | Resource not found |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server error |
| Error Code | Description |
|---|---|
invalid_request | Missing or invalid request parameters |
invalid_client | Client authentication failed |
invalid_grant | Authorization code/refresh token invalid |
unsupported_grant_type | Grant type not supported |
invalid_scope | Requested scope invalid |
server_error | Internal server error |
The server implements rate limiting on sensitive endpoints:
HTTP/1.1 429 Too Many Requests
+Content-Type: application/json
+
+{
+ "error": "rate_limit_exceeded",
+ "error_description": "Rate limit exceeded. Try again later.",
+ "retry_after": 60
+}
+All successful responses include appropriate HTTP status codes and JSON payloads.
Large result sets use cursor-based pagination:
{
+ "data": [...],
+ "pagination": {
+ "next_cursor": "cursor_abc123",
+ "has_more": true,
+ "total_count": 1250
+ }
+}
+All timestamps use ISO 8601 format in UTC:
The server includes comprehensive security monitoring:
{
+ "Access-Control-Allow-Origin": "*",
+ "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
+ "Access-Control-Allow-Headers": "Content-Type, Authorization"
+}
+curl -X POST https://your-domain.com/api/oauth/register \
+ -H "Content-Type: application/json" \
+ -d '{"client_name": "Test App", "redirect_uris": ["http://localhost:3000/callback"]}'
+// Generate code verifier and challenge
+const codeVerifier = base64URLEncode(crypto.randomBytes(32));
+const codeChallenge = base64URLEncode(crypto.createHash('sha256').update(codeVerifier).digest());
+https://your-domain.com/oauth/authorize?client_id=CLIENT_ID&redirect_uri=http://localhost:3000/callback&response_type=code&state=STATE&code_challenge=CODE_CHALLENGE&code_challenge_method=S256
+curl -X POST https://your-domain.com/api/oauth/token \
+ -H "Content-Type: application/x-www-form-urlencoded" \
+ -d "grant_type=authorization_code&code=AUTH_CODE&redirect_uri=http://localhost:3000/callback&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&code_verifier=CODE_VERIFIER"
+curl -X POST https://your-domain.com/mcp/sse \
+ -H "Authorization: Bearer ACCESS_TOKEN" \
+ -H "Content-Type: application/json" \
+ -d '{"method": "tools/call", "params": {"name": "add_numbers", "arguments": {"a": 5, "b": 3}}}'
+Generate test security events:
curl -X POST https://your-domain.com/api/test/security-events \
+ -H "Content-Type: application/json" \
+ -d '{"eventType": "INVALID_TOKEN", "count": 3}'
+Run advanced threat detection:
curl -X POST https://your-domain.com/api/analytics/generate-threats \
+ -H "Content-Type: application/json" \
+ -d '{"runDetection": true, "mockScenarios": ["privilege_escalation", "token_reuse"]}'
+A Postman collection is available with pre-configured requests for all endpoints:
Import the collection URL:
/analyticsThis MCP OAuth server provides a production-ready OAuth 2.1 authorization server with comprehensive MCP integration, enterprise-grade analytics, and advanced security monitoring. The API supports both public and confidential clients, implements PKCE for enhanced security, and provides detailed observability for production deployments.
For additional support and advanced configuration options, refer to the other documentation files in the /docs directory.
The MCP OAuth 2.1 Server is a comprehensive authentication and authorization system designed to secure Model Context Protocol (MCP) interactions. The system implements OAuth 2.1 with PKCE (Proof Key for Code Exchange) to provide secure authentication for MCP clients while maintaining compatibility with modern security standards.
graph TB
+ subgraph "Client Layer"
+ MC[MCP Client]
+ WC[Web Client]
+ API[API Client]
+ end
+
+ subgraph "Next.js Application"
+ subgraph "Authentication Layer"
+ NA[NextAuth.js]
+ GA[Google OAuth]
+ end
+
+ subgraph "OAuth 2.1 Server"
+ AR["Client Registration<br/>/api/oauth/register"]
+ AT["Token Endpoint<br/>/api/oauth/token"]
+ AZ["Authorization<br/>/oauth/authorize"]
+ end
+
+ subgraph "MCP Server"
+ MH[MCP Handler]
+ TL[Tool Library]
+ AU[Auth Middleware]
+ end
+
+ subgraph "Analytics Engine"
+ AC[Analytics Collector]
+ SM[Security Monitor]
+ RL[Request Logger]
+ end
+ end
+
+ subgraph "Data Layer"
+ PG[(PostgreSQL)]
+ RD[(Redis)]
+ end
+
+ subgraph "External Services"
+ GO[Google OAuth]
+ GEO[IP Geolocation]
+ end
+
+ MC --> MH
+ WC --> NA
+ API --> AR
+
+ AR --> PG
+ AT --> PG
+ AZ --> PG
+
+ MH --> AU
+ AU --> PG
+ MH --> TL
+
+ NA --> GA
+ GA --> GO
+
+ AC --> PG
+ SM --> PG
+ RL --> PG
+
+ MH --> RD
+ AC --> GEO The system implements OAuth 2.1 as defined in RFC 6749 with OAuth 2.1 Security Best Practices:
sequenceDiagram
+ participant C as MCP Client
+ participant AS as OAuth Server
+ participant RS as MCP Resource Server
+ participant U as User
+
+ Note over C,U: 1. Client Registration
+ C->>AS: POST /api/oauth/register
+ AS->>AS: Generate client_id & client_secret
+ AS->>C: Return credentials
+
+ Note over C,U: 2. Authorization Code Flow with PKCE
+ C->>C: Generate code_verifier & code_challenge
+ C->>AS: GET /oauth/authorize?client_id=...&code_challenge=...
+ AS->>U: Redirect to login (NextAuth)
+ U->>AS: Authenticate via Google OAuth
+ AS->>U: Show consent screen
+ U->>AS: Grant consent
+ AS->>C: Redirect with authorization code
+
+ Note over C,U: 3. Token Exchange
+ C->>AS: POST /api/oauth/token with code & code_verifier
+ AS->>AS: Verify PKCE challenge
+ AS->>AS: Generate access & refresh tokens
+ AS->>C: Return tokens
+
+ Note over C,U: 4. Resource Access
+ C->>RS: MCP request with Bearer token
+ RS->>AS: Validate token (internal)
+ AS->>RS: Token validation response
+ RS->>C: MCP response
+
+ Note over C,U: 5. Token Refresh
+ C->>AS: POST /api/oauth/token with refresh_token
+ AS->>AS: Rotate refresh token (public clients)
+ AS->>C: Return new tokens The system implements PKCE (Proof Key for Code Exchange) as specified in RFC 7636:
// PKCE validation in token endpoint
+if (authCode.codeChallenge) {
+ if (authCode.codeChallengeMethod === 'S256') {
+ const hash = createHash('sha256').update(code_verifier).digest();
+ const base64url = hash.toString('base64')
+ .replace(/\+/g, '-')
+ .replace(/\//g, '_')
+ .replace(/=+$/, '');
+ pkceValid = base64url === authCode.codeChallenge;
+ }
+}
+The MCP server is implemented using the @vercel/mcp-adapter and provides secure access to tools and resources through OAuth 2.1 authentication.
graph LR
+ subgraph "MCP Handler"
+ REQ[Request]
+ AUTH[Auth Middleware]
+ TOOLS[Tool Registry]
+ RESP[Response]
+ end
+
+ subgraph "Tool Library"
+ T1[add_numbers]
+ T2[calculate_circle_area]
+ T3[generate_random_number]
+ T4[format_text]
+ T5[check_prime_number]
+ T6[trigger_security_events]
+ end
+
+ REQ --> AUTH
+ AUTH --> TOOLS
+ TOOLS --> T1
+ TOOLS --> T2
+ TOOLS --> T3
+ TOOLS --> T4
+ TOOLS --> T5
+ TOOLS --> T6
+ TOOLS --> RESP The MCP server implements comprehensive authentication middleware:
async function authenticateRequest(request: NextRequest) {
+ const authHeader = request.headers.get('authorization');
+ const token = authHeader?.split(' ')[1];
+
+ // Validate token against database
+ const accessToken = await prisma.accessToken.findUnique({
+ where: { token },
+ include: { client: true, user: true }
+ });
+
+ // Check expiration
+ if (accessToken.expiresAt < new Date()) {
+ return null;
+ }
+
+ // Validate token audience (critical security requirement)
+ const currentResource = `${protocol}://${host}`;
+ if (accessToken.resource && accessToken.resource !== currentResource) {
+ return null;
+ }
+
+ return accessToken;
+}
+Tools are implemented using Zod schema validation and provide structured responses:
server.tool(
+ "add_numbers",
+ "Adds two numbers together and returns the sum",
+ {
+ a: z.number().describe("First number to add"),
+ b: z.number().describe("Second number to add"),
+ },
+ async ({ a, b }) => {
+ return {
+ content: [
+ {
+ type: "text",
+ text: `The sum of ${a} and ${b} is ${a + b}`,
+ },
+ ],
+ };
+ }
+);
+The system supports multiple MCP transport mechanisms:
/mcp/sse - Server-Sent Events for real-time communication/mcp/mcp - Standard HTTP request/responseThe database schema is designed to support both OAuth 2.1 requirements and comprehensive analytics collection:
erDiagram
+ User {
+ string id PK
+ string name
+ string email UK
+ datetime emailVerified
+ string image
+ }
+
+ Account {
+ string id PK
+ string userId FK
+ string provider
+ string providerAccountId
+ string refresh_token
+ string access_token
+ }
+
+ Client {
+ string id PK
+ string clientId UK
+ string clientSecret
+ string name
+ string[] redirectUris
+ string userId FK
+ datetime createdAt
+ datetime updatedAt
+ }
+
+ AccessToken {
+ string id PK
+ string token UK
+ datetime expiresAt
+ string clientId FK
+ string userId FK
+ string resource
+ datetime createdAt
+ }
+
+ AuthCode {
+ string id PK
+ string code UK
+ datetime expiresAt
+ string clientId FK
+ string userId FK
+ string redirectUri
+ string codeChallenge
+ string codeChallengeMethod
+ string resource
+ datetime createdAt
+ }
+
+ RefreshToken {
+ string id PK
+ string token UK
+ datetime expiresAt
+ string clientId FK
+ string userId FK
+ string resource
+ datetime createdAt
+ }
+
+ AnalyticsRequest {
+ string id PK
+ datetime timestamp
+ string endpoint
+ string method
+ int statusCode
+ int responseTime
+ string clientId FK
+ string userId FK
+ string mcpServerId FK
+ string ipAddress
+ string userAgent
+ string mcpMethod
+ string toolName
+ string oauthGrantType
+ boolean usePKCE
+ datetime expiresAt
+ }
+
+ AnalyticsSecurity {
+ string id PK
+ datetime timestamp
+ SecurityEventType eventType
+ string severity
+ string userId FK
+ string clientId FK
+ string ipAddress
+ string userAgent
+ json details
+ int riskScore
+ boolean resolved
+ datetime expiresAt
+ }
+
+ MCPServer {
+ string id PK
+ string name
+ string identifier UK
+ string description
+ string version
+ datetime createdAt
+ datetime updatedAt
+ }
+
+ User ||--o{ Account : "has"
+ User ||--o{ Client : "owns"
+ User ||--o{ AccessToken : "has"
+ User ||--o{ AuthCode : "has"
+ User ||--o{ RefreshToken : "has"
+ User ||--o{ AnalyticsRequest : "generates"
+ User ||--o{ AnalyticsSecurity : "triggers"
+
+ Client ||--o{ AccessToken : "issues"
+ Client ||--o{ AuthCode : "issues"
+ Client ||--o{ RefreshToken : "issues"
+ Client ||--o{ AnalyticsRequest : "generates"
+ Client ||--o{ AnalyticsSecurity : "triggers"
+
+ MCPServer ||--o{ AnalyticsRequest : "serves"
+ MCPServer ||--o{ AnalyticsSecurity : "monitors" Critical indexes for optimal performance:
-- Request analytics indexes
+CREATE INDEX idx_analytics_timestamp ON "AnalyticsRequest"(timestamp);
+CREATE INDEX idx_analytics_endpoint ON "AnalyticsRequest"(endpoint);
+CREATE INDEX idx_analytics_client_time ON "AnalyticsRequest"(timestamp, "clientId");
+CREATE INDEX idx_analytics_user_time ON "AnalyticsRequest"(timestamp, "userId");
+
+-- Security event indexes
+CREATE INDEX idx_security_timestamp ON "AnalyticsSecurity"(timestamp);
+CREATE INDEX idx_security_event_type ON "AnalyticsSecurity"("eventType");
+CREATE INDEX idx_security_risk_score ON "AnalyticsSecurity"("riskScore");
+
+-- OAuth token indexes
+CREATE UNIQUE INDEX idx_access_token ON "AccessToken"(token);
+CREATE INDEX idx_access_token_expiry ON "AccessToken"("expiresAt");
+CREATE UNIQUE INDEX idx_refresh_token ON "RefreshToken"(token);
+The API is organized into several logical categories:
| Endpoint | Method | Purpose | OAuth 2.1 Spec |
|---|---|---|---|
/api/oauth/register | POST | Dynamic client registration | RFC 7591 |
/api/oauth/token | POST | Token exchange and refresh | RFC 6749 |
/oauth/authorize | GET | Authorization endpoint | RFC 6749 |
| Endpoint | Method | Purpose | Transport |
|---|---|---|---|
/mcp/sse | GET/POST | MCP over Server-Sent Events | SSE |
/mcp/mcp | GET/POST | MCP over HTTP | HTTP |
| Endpoint | Method | Purpose | Access |
|---|---|---|---|
/api/analytics/collect | POST | Request analytics collection | Internal |
/api/analytics/security | POST | Security event logging | Internal |
/api/analytics | GET | Analytics dashboard data | Authenticated |
| Endpoint | Method | Purpose | Provider |
|---|---|---|---|
/api/auth/signin | GET/POST | User authentication | Google OAuth |
/api/auth/callback | GET/POST | OAuth callback | Google OAuth |
/api/auth/signout | POST | User sign out | NextAuth |
sequenceDiagram
+ participant C as Client
+ participant MW as Middleware
+ participant EP as Endpoint
+ participant DB as Database
+ participant AN as Analytics
+
+ C->>MW: HTTP Request
+ MW->>MW: CORS handling
+ MW->>MW: Rate limiting
+ MW->>EP: Forward request
+ EP->>DB: Database operations
+ DB->>EP: Response data
+ EP->>AN: Log request (async)
+ AN->>DB: Store analytics
+ EP->>MW: Response
+ MW->>C: HTTP Response The system implements comprehensive error handling following OAuth 2.1 specifications:
{
+ "error": "invalid_client",
+ "error_description": "Client authentication failed",
+ "error_uri": "https://example.com/errors#invalid_client"
+}
+{
+ "jsonrpc": "2.0",
+ "id": "request_id",
+ "error": {
+ "code": -32600,
+ "message": "Invalid Request",
+ "data": { "details": "Authentication required" }
+ }
+}
+The system implements a multi-layer security model combining user authentication, client authentication, and resource authorization:
graph TD
+ subgraph "User Authentication Layer"
+ UA[User Login]
+ GO[Google OAuth]
+ SE[Session Management]
+ end
+
+ subgraph "Client Authentication Layer"
+ CR[Client Registration]
+ CC[Client Credentials]
+ PKCE[PKCE Verification]
+ end
+
+ subgraph "Resource Authorization Layer"
+ TA[Token Validation]
+ AU[Audience Validation]
+ SC[Scope Checking]
+ end
+
+ subgraph "Security Monitoring Layer"
+ SM[Security Monitor]
+ AL[Audit Logging]
+ TH[Threat Detection]
+ end
+
+ UA --> GO
+ GO --> SE
+ SE --> CR
+ CR --> CC
+ CC --> PKCE
+ PKCE --> TA
+ TA --> AU
+ AU --> SC
+ SC --> SM
+ SM --> AL
+ AL --> TH // NextAuth configuration
+export const authConfig = {
+ adapter: PrismaAdapter(prisma),
+ providers: [
+ Google({
+ clientId: process.env.GOOGLE_CLIENT_ID!,
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
+ }),
+ ],
+ callbacks: {
+ // Session and JWT callbacks for enhanced security
+ },
+ trustHost: true,
+};
+// Dynamic client registration
+const newClient = await prisma.client.create({
+ data: {
+ name: client_name,
+ redirectUris: redirect_uris,
+ clientSecret: clientSecret, // Hashed in production
+ userId: null, // Allow unauthenticated clients
+ },
+});
+// Authorization endpoint with PKCE
+const authorizationCode = randomBytes(16).toString('hex');
+await prisma.authCode.create({
+ data: {
+ code: authorizationCode,
+ expiresAt: new Date(Date.now() + 10 * 60 * 1000), // 10 minutes
+ clientId: client.id,
+ userId: session.user.id,
+ redirectUri: redirectUri,
+ codeChallenge: code_challenge,
+ codeChallengeMethod: code_challenge_method,
+ resource: resource,
+ },
+});
+// Token exchange with PKCE verification
+if (authCode.codeChallenge) {
+ if (authCode.codeChallengeMethod === 'S256') {
+ const hash = createHash('sha256').update(code_verifier).digest();
+ const base64url = hash.toString('base64')
+ .replace(/\+/g, '-')
+ .replace(/\//g, '_')
+ .replace(/=+$/, '');
+ pkceValid = base64url === authCode.codeChallenge;
+ }
+}
+The system maintains security context across all layers:
The system implements multiple layers of security controls:
graph LR
+ subgraph "Security Events"
+ AF[Auth Failures]
+ IT[Invalid Tokens]
+ SA[Suspicious Activity]
+ RL[Rate Limit Exceeded]
+ UA[Unauthorized Access]
+ end
+
+ subgraph "Detection Engine"
+ ER[Event Rules]
+ RS[Risk Scoring]
+ TH[Threat Hunting]
+ end
+
+ subgraph "Response Actions"
+ AL[Alert Generation]
+ BL[Blacklisting]
+ TR[Token Revocation]
+ IN[Incident Response]
+ end
+
+ AF --> ER
+ IT --> ER
+ SA --> ER
+ RL --> ER
+ UA --> ER
+
+ ER --> RS
+ RS --> TH
+ TH --> AL
+ TH --> BL
+ TH --> TR
+ TH --> IN The system monitors and responds to various security events:
enum SecurityEventType {
+ AUTH_FAILURE = "AUTH_FAILURE",
+ INVALID_TOKEN = "INVALID_TOKEN",
+ SUSPICIOUS_ACTIVITY = "SUSPICIOUS_ACTIVITY",
+ RATE_LIMIT_EXCEEDED = "RATE_LIMIT_EXCEEDED",
+ UNAUTHORIZED_ACCESS = "UNAUTHORIZED_ACCESS",
+ TOKEN_REUSE = "TOKEN_REUSE",
+ UNUSUAL_LOCATION = "UNUSUAL_LOCATION",
+ PRIVILEGE_ESCALATION = "PRIVILEGE_ESCALATION",
+ MALFORMED_REQUEST = "MALFORMED_REQUEST",
+ BRUTE_FORCE_ATTEMPT = "BRUTE_FORCE_ATTEMPT"
+}
+Security events are scored based on multiple factors:
The analytics system is designed for high-performance data collection and real-time analysis:
graph TB
+ subgraph "Data Collection Layer"
+ RC[Request Collector]
+ SC[Security Collector]
+ BC[Batch Processor]
+ end
+
+ subgraph "Data Processing Layer"
+ AE[Analytics Engine]
+ GE[Geography Enricher]
+ RS[Risk Scorer]
+ end
+
+ subgraph "Data Storage Layer"
+ PG[(PostgreSQL)]
+ TS[(Time Series)]
+ CH[(ClickHouse)]
+ end
+
+ subgraph "Analysis Layer"
+ RT[Real-time Analytics]
+ BA[Batch Analytics]
+ ML[Machine Learning]
+ end
+
+ subgraph "Presentation Layer"
+ DB[Dashboard]
+ AL[Alerts]
+ RP[Reports]
+ end
+
+ RC --> BC
+ SC --> BC
+ BC --> AE
+ AE --> GE
+ AE --> RS
+ GE --> PG
+ RS --> PG
+
+ PG --> RT
+ PG --> BA
+ BA --> ML
+
+ RT --> DB
+ RT --> AL
+ BA --> RP
+ ML --> AL class OptimizedAnalyticsCollector {
+ private requestBatch: RequestAnalytics[] = [];
+ private readonly BATCH_SIZE = 100;
+ private readonly FLUSH_INTERVAL = 15000; // 15 seconds
+
+ async logRequest(data: RequestAnalytics) {
+ this.requestBatch.push(data);
+
+ if (this.requestBatch.length >= this.BATCH_SIZE) {
+ await this.flushRequests();
+ }
+ }
+
+ private async flushRequests() {
+ await prisma.$transaction(async (tx) => {
+ await tx.analyticsRequest.createMany({
+ data: this.requestBatch.map(req => ({...req})),
+ skipDuplicates: true
+ });
+ });
+ }
+}
+-- Optimized performance metrics query
+SELECT
+ COUNT(*) as total_requests,
+ AVG("responseTime") as avg_response_time,
+ PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY "responseTime") as p95_response_time,
+ CASE
+ WHEN COUNT(*) = 0 THEN 0
+ ELSE COUNT(CASE WHEN "statusCode" >= 400 THEN 1 END) * 100.0 / COUNT(*)
+ END as error_rate
+FROM "AnalyticsRequest"
+WHERE timestamp >= $1;
+// Automatic data cleanup with TTL
+model AnalyticsRequest {
+ // TTL field - automatically set to 14 days from creation
+ expiresAt DateTime @default(dbgenerated("NOW() + INTERVAL '14 days'"))
+
+ @@index([expiresAt])
+}
+
+// Cleanup job
+async cleanupOldData(daysOld = 30) {
+ const cutoff = new Date(Date.now() - daysOld * 24 * 60 * 60 * 1000);
+
+ await prisma.analyticsRequest.deleteMany({
+ where: { timestamp: { lt: cutoff } }
+ });
+}
+mcp-oauth-sample/
+โโโ app/ # Next.js App Router
+โ โโโ api/ # API routes
+โ โ โโโ auth/ # NextAuth.js endpoints
+โ โ โ โโโ [...nextauth]/ # Dynamic auth routes
+โ โ โโโ oauth/ # OAuth 2.1 endpoints
+โ โ โ โโโ register/ # Client registration
+โ โ โ โโโ token/ # Token endpoint
+โ โ โโโ analytics/ # Analytics endpoints
+โ โ โ โโโ collect/ # Data collection
+โ โ โ โโโ security/ # Security events
+โ โ โ โโโ generate-threats/ # Test data generation
+โ โ โโโ cleanup/ # Data cleanup jobs
+โ โโโ mcp/ # MCP server implementation
+โ โ โโโ [transport]/ # Dynamic transport routes
+โ โโโ oauth/ # OAuth UI pages
+โ โ โโโ authorize/ # Authorization consent
+โ โโโ analytics/ # Analytics dashboard
+โ โโโ auth.ts # NextAuth configuration
+โ โโโ prisma.ts # Prisma client setup
+โ โโโ layout.tsx # Root layout component
+โ โโโ page.tsx # Home page
+โโโ components/ # Reusable React components
+โ โโโ analytics/ # Analytics components
+โ โ โโโ dashboard-header.tsx # Dashboard header
+โ โ โโโ metric-card.tsx # Metric display cards
+โ โ โโโ oauth-overview.tsx # OAuth metrics
+โ โ โโโ security-panel.tsx # Security dashboard
+โ โ โโโ tool-usage-panel.tsx # MCP tool usage
+โ โโโ ui/ # Base UI components
+โ โ โโโ button.tsx # Button component
+โ โ โโโ card.tsx # Card component
+โ โ โโโ chart.tsx # Chart components
+โ โ โโโ ... # Other UI components
+โ โโโ theme-provider.tsx # Theme context
+โ โโโ theme-toggle.tsx # Dark/light mode toggle
+โโโ lib/ # Utility libraries
+โ โโโ analytics-db.ts # Analytics database layer
+โ โโโ security-monitor.ts # Security monitoring
+โ โโโ utils.ts # General utilities
+โโโ prisma/ # Database schema and migrations
+โ โโโ schema.prisma # Prisma schema definition
+โโโ docs/ # Documentation
+โ โโโ architecture.md # This file
+โ โโโ setup.md # Setup instructions
+โโโ middleware.ts # Next.js middleware
+โโโ next.config.ts # Next.js configuration
+โโโ package.json # Dependencies and scripts
+โโโ tailwind.config.js # Tailwind CSS configuration
+โโโ tsconfig.json # TypeScript configuration
+โโโ README.md # Project overview
+app/auth.ts - NextAuth.js configuration with Google OAuth provider and Prisma adapter
app/prisma.ts - Prisma client singleton with optimized connection handling
prisma/schema.prisma - Complete database schema with OAuth 2.1 and analytics models
app/api/oauth/token/route.ts - OAuth 2.1 token endpoint with PKCE support and refresh token rotation
app/api/oauth/register/route.ts - Dynamic client registration per RFC 7591
app/mcp/[transport]/route.ts - MCP server with authentication middleware and tool implementations
lib/analytics-db.ts - High-performance analytics collection with batching and optimized queries
lib/security-monitor.ts - Security event detection and threat analysis
app/api/analytics/collect/route.ts - Analytics data collection endpoint
app/analytics/page.tsx - Main analytics dashboard with real-time metrics
components/analytics/ - Specialized analytics components for different metric types
app/oauth/authorize/page.tsx - OAuth authorization consent screen
This MCP OAuth 2.1 Server represents a comprehensive implementation of modern authentication and authorization patterns specifically designed for Model Context Protocol interactions. The architecture emphasizes security, performance, and observability while maintaining compliance with relevant standards and specifications.
The system's modular design allows for easy extension and customization, while the comprehensive analytics and security monitoring provide the visibility needed for production deployment. The technology choices reflect current best practices in web development, security, and database design.
For questions or contributions, please refer to the project documentation and follow the established development workflows.