A production-ready MCP server demonstrating OAuth 2.0 authentication with Keycard's Security Token Service (STS). This project showcases best practices for building secure, type-safe, and modular MCP servers with enterprise-grade observability.
- π OAuth 2.0 Authentication - Secure authentication via Keycard STS
- β¨ Type Safety - Full TypeScript with Zod runtime validation
- ποΈ Modular Architecture - Clean separation of concerns for easy extension
- π Production Ready - Error handling, validation, and comprehensive logging
- π Educational - Well-documented code showing MCP best practices
- π§ͺ Testing Framework - Jest with coverage, integration tests, and watch modes
- π Observability - OpenTelemetry integration with traces and metrics
βββββββββββββββ ββββββββββββββββ βββββββββββββββ
β Cursor βββββΆβ MCP Server βββββΆβ Keycard STS β
β IDE β β (localhost: β β β
β β β 8888) β β β
βββββββββββββββ ββββββββββββββββ βββββββββββββββ
β β β
OAuth Flow JWT Validation Token Issuance
- Cursor discovers OAuth endpoints from MCP server
- User authenticates via Keycard STS (redirected to identity provider)
- Keycard STS issues JWT access tokens
- MCP Server validates tokens and grants access to tools
- Node.js 18+ and npm
- Cursor IDE (or any MCP-compatible client)
- Keycard account with access to the Console
- Configured Keycard zone (for authentication)
git clone https://github.com/keycardai/hello-mcp-server.git
cd hello-mcp-server
npm installCreate a .env file:
# Required: Your Keycard STS issuer URL
KEYCARD_STS_ISSUER_URL=https://your-zone-id.keycard.cloud
# Optional: Server configuration
PORT=8888
HOST=localhostπ‘ Finding your Zone ID:
- Log into the Keycard Console
- Navigate to Zone Settings
- Copy the Zone ID (e.g.,
j434uokph8th1ia1npxiaykh7p) - Replace
your-zone-idin your STS URL
Note: Use the zone ID, not the zone name or label.
# Development mode with auto-reload
npm run dev
# Production mode
npm run build && npm startYou should see:
π Keycard Hello MCP Server started!
π MCP Endpoint: http://localhost:8888/mcp
π STS Issuer: https://your-zone-id.keycard.cloud
π οΈ Available Tools: keycard-logo, whoami
Add to your Cursor MCP settings:
{
"mcpServers": {
"keycard-hello-mcp": {
"url": "http://localhost:8888/mcp"
}
}
}- Restart Cursor to pick up the new MCP server
- Cursor will show "needs login" for the server
- Click to authenticate β complete OAuth flow
- Use the tools:
keycard-logo,whoami
Displays the official Keycard ASCII art logo.
Provides detailed information about the authenticated user including:
- Client ID and authentication scopes
- JWT payload with user information
- Token expiration and timing details
- Custom claims and metadata
| Variable | Description | Default | Required |
|---|---|---|---|
KEYCARD_STS_ISSUER_URL |
Keycard STS issuer URL (single-tenant mode) | - | β * |
ISSUER_BASE_DOMAIN |
Base domain for STS (multi-tenant mode) | - | β * |
MCP_BASE_DOMAIN |
Base domain for MCP server (multi-tenant mode) | - | β * |
PORT |
Server port | 8888 |
|
HOST |
Server host | localhost |
|
LOG_LEVEL |
Logging level | INFO |
|
ENABLE_OTEL |
Enable OpenTelemetry | true |
|
OTEL_SERVICE_NAME |
Service name for telemetry | hello-mcp-server |
|
OTEL_ENVIRONMENT |
Environment for telemetry | development |
*Either KEYCARD_STS_ISSUER_URL (single-tenant) OR ISSUER_BASE_DOMAIN + MCP_BASE_DOMAIN (multi-tenant) is required.
For multi-tenant deployments (serving multiple organizations/zones), use these environment variables instead:
# Multi-tenant mode
ISSUER_BASE_DOMAIN=keycard.cloud
MCP_BASE_DOMAIN=mcp.example.com
# Other configuration
PORT=8888
ENABLE_OTEL=trueThis enables dynamic issuer discovery based on subdomain routing, allowing one deployment to serve multiple Keycard zones.
The server includes comprehensive observability features:
- Structured Logging: Environment-aware logging with trace correlation
- Request Tracing: Full distributed tracing with OpenTelemetry
- Metrics Collection: Performance and usage metrics
- Health Checks: Available at
/health
In development, logs are formatted for console readability. In production, logs are sent to configured OTLP endpoints.
src/
βββ config.ts # Configuration management
βββ index.ts # Application entry point
βββ server.ts # Express server setup
βββ middleware/ # Express middlewares
β βββ auth.ts # Authentication middleware
β βββ logging.ts # Request logging and tracing
βββ observability/ # Telemetry and logging
β βββ logger.ts # Structured logger
β βββ telemetry.ts # OpenTelemetry setup
βββ tools/ # MCP tools
β βββ index.ts # Tool registration
β βββ logo.ts # Keycard logo tool
β βββ whoami.ts # User information tool
βββ types/ # Type definitions
βββ auth.ts # Authentication types
βββ index.ts # Exported types
# Run all tests
npm test
# Run tests with coverage
npm run test:coverage
# Run integration tests
npm run test:integration
# Watch mode for development
npm run test:watch# Lint code
npm run lint
# Fix linting issues
npm run lint:fix
# Format code
npm run format
# Check all (lint + format)
npm run check
# Fix all issues
npm run check:fix- Start the server:
npm run dev - In Cursor, go to Settings > MCP Servers
- Add server:
http://localhost:8888/mcp
The server provides a health check endpoint at /health:
curl http://localhost:8888/healthResponse:
{
"status": "healthy",
"timestamp": "2024-01-01T00:00:00.000Z",
"service": "hello-mcp-server",
"version": "1.0.0"
}- Fork the repository
- Create a feature branch
- Make your changes
- Run tests and quality checks
- Submit a pull request
Apache-2.0 License - see LICENSE file for details.