Service Implementations#
The MCP OAuth Gateway consists of infrastructure services and MCP services, all orchestrated through Docker Compose following the divine architectural separation.
Service Architecture#
Service Categories#
🏗️ Infrastructure Services#
Core services that provide authentication, routing, and storage:
🔧 MCP Services - Proxy Pattern#
Services that wrap official MCP stdio servers using mcp-streamablehttp-proxy
:
Service |
Purpose |
Wrapped Server |
---|---|---|
Web content fetching |
mcp-server-fetch |
|
File operations |
mcp-server-filesystem |
|
Persistent storage |
@modelcontextprotocol/server-memory |
|
Time/date operations |
mcp-server-time |
|
Comprehensive toolset |
mcp-server-everything |
|
Browser automation |
@modelcontextprotocol/server-playwright |
|
Sequential reasoning |
@modelcontextprotocol/server-sequential-thinking |
|
Terminal multiplexer |
mcp-server-tmux |
🚀 MCP Services - Native Pattern#
Services with direct StreamableHTTP implementation:
Service |
Purpose |
Implementation |
---|---|---|
Native fetch with SSRF protection |
mcp-fetch-streamablehttp-server |
|
Stateful diagnostic echo |
mcp-echo-streamablehttp-server-stateful |
|
Stateless production echo |
mcp-echo-streamablehttp-server-stateless |
Common Service Patterns#
Docker Compose Structure#
Each service follows the blessed pattern:
services:
service-name:
<<: *mcp-service # Inherit common config
build:
context: ./service-name
dockerfile: Dockerfile
environment:
- SERVICE_CONFIG=${SERVICE_CONFIG}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
labels:
# Traefik routing labels
- "traefik.enable=true"
- "traefik.http.routers.service.rule=Host(`service.${BASE_DOMAIN}`)"
- "traefik.http.routers.service.priority=2"
- "traefik.http.routers.service.middlewares=mcp-auth@docker"
Health Check Patterns#
For Proxy Services#
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
For Native MCP Services#
healthcheck:
test: ["CMD", "sh", "-c", "curl -X POST http://localhost:3000/mcp \
-H 'Content-Type: application/json' \
-d '{\"jsonrpc\":\"2.0\",\"method\":\"initialize\",...}' \
| grep -q '\"protocolVersion\"'"]
Authentication Pattern#
All MCP services:
Receive requests through Traefik
Traefik validates token via ForwardAuth
Service receives pre-authenticated request
No OAuth code in MCP services
Service Configuration#
Enable/Disable Services#
In .env
:
# MCP Services
MCP_FETCH_ENABLED=true
MCP_FILESYSTEM_ENABLED=false
MCP_MEMORY_ENABLED=true
# ... etc
Service URLs#
Services are accessible at:
https://service-name.${BASE_DOMAIN}/mcp
With multiple URLs supported:
MCP_FETCH_URLS=https://fetch.example.com/mcp,https://mcp-fetch.example.com/mcp
Deployment Patterns#
Development#
# Start specific services
just up auth mcp-fetch mcp-echo-stateful
# Watch logs
just logs -f mcp-fetch
Production#
# Start all enabled services
just up
# Check health
just check-health
Scaling#
# Scale stateless services
docker compose up -d --scale mcp-echo-stateless=3
Monitoring#
Service Status#
# Check all services
just status
# Check specific service
docker compose ps mcp-fetch
Logs#
# Container logs
just logs mcp-fetch
# File-based logs
just logs-files mcp-fetch
Health Endpoints#
Infrastructure:
/health
MCP Services:
/health
or protocol check
Troubleshooting#
Service Won’t Start#
Check logs:
just logs <service>
Verify dependencies running
Check health endpoint manually
Review environment variables
Authentication Issues#
Verify token is valid
Check Traefik middleware
Review auth service logs
Test
/verify
endpoint
Network Issues#
Ensure on
public
networkCheck service discovery
Verify Traefik routing
Test internal connectivity
Best Practices#
Use Health Checks: Every service must prove readiness
Central Logging: All logs to
./logs/
Environment Config: All config via
.env
Graceful Shutdown: Handle SIGTERM properly
Resource Limits: Set appropriate limits
Security First: Never bypass auth layer