| Filename | Latest commit message | Latest commit date |
|---|---|---|
Server starts immediately and retries auth connection in background. Splash page and health endpoint remain accessible in degraded mode. |
||
| .. | ||
| src | ||
| eslint.config.mjs | ||
| jest.config.js | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
MCP Server - Resource Server with External OAuth
MCP resource server demonstrating token validation with external OAuth providers.
Purpose
This server shows how to build an MCP server that delegates all OAuth operations to external providers:
- No OAuth authorization code in the MCP server
- Token validation via introspection API (RFC 7662)
- Focus on serving MCP resources
- Authentication handled by external provider (Auth0, Okta, etc.)
Quick Start
# This server requires the auth server to be running!
# Option 1: Start both servers from repo root
cd .. && npm run dev
# Option 2: Start servers individually
# Terminal 1:
cd ../auth-server && npm run dev
# Terminal 2:
cd ../mcp-server && npm run dev
# Server starts on http://localhost:3232
Architecture
This server:
- Advertises the external OAuth server in its metadata
- Receives MCP requests with Bearer tokens
- Validates tokens via the OAuth server's
/introspectendpoint - Serves MCP resources after token validation
- Manages MCP sessions tied to validated users
The server does not issue tokens or handle user authentication.
Key Components
src/index.ts
Main entry point. Notable aspects for external auth:
- No OAuth endpoints (handled by auth server)
- Uses
ExternalAuthVerifierto validate tokens - Fetches auth metadata from external server on startup
- Serves MCP endpoints only
src/auth/external-verifier.ts
ExternalAuthVerifier - Validates tokens with external auth server:
async verifyAccessToken(token: string): Promise<AuthInfo> {
// Calls POST /introspect on auth server
// Validates token is active and intended for this MCP server
// Returns user info and scopes
}
src/services/mcp.ts
MCP server implementation with all features:
- 7 demonstration tools
- 100 paginated resources
- 3 prompts with argument support
- Sampling, completions, logging
src/services/redisTransport.ts
Redis-backed transport enabling:
- Horizontal scaling
- Session state management
- Message routing across instances
MCP Endpoints
# Streamable HTTP (recommended)
GET/POST/DELETE /mcp
# SSE (legacy)
GET /sse
POST /message
All endpoints require Authorization: Bearer <token> header.
Configuration
Environment variables in .env:
BASE_URI=http://localhost:3232 # This MCP server's URL
PORT=3232 # MCP server port
AUTH_SERVER_URL=http://localhost:3001 # External auth server URL
REDIS_URL=redis://localhost:6379
Token Validation Flow
- Client sends request with
Authorization: Bearer <token> - MCP server extracts token from header
- MCP server calls
POST AUTH_SERVER_URL/introspectwith token - Auth server returns token info (active, user_id, scopes, expiry)
- MCP server validates:
- Token is active
- Token audience matches this server (BASE_URI)
- Token hasn't expired
- Request proceeds with user context
Testing
npm test # 67 unit tests
npm run lint # Lint code
npm run typecheck # Type checking
npm run build # Build to dist/
Production Adaptation
To use a commercial OAuth provider:
- Update
.envwith provider URL:
AUTH_SERVER_URL=https://your-tenant.auth0.com
- Modify
src/auth/external-verifier.tsfor provider-specific introspection:
const response = await fetch(`${this.authServerUrl}/oauth/introspect`, {
// Add provider-specific authentication
})
- Adjust response parsing if the introspection format differs from RFC 7662 standard
The MCP server code otherwise remains unchanged.
References
Related Documentation
- Main README - Complete project documentation
- Auth Server README - The demo OAuth provider
- OAuth Patterns - OAuth architecture patterns
- OAuth Flow - Detailed OAuth flow analysis
- Session Ownership - Session management details