MCP Server implementations and gateway infrastructure
/admin, /dashboard, /dashboard/status, and all /users/* and /keys/* endpoints were publicly accessible with no authentication, exposing user management, API key generation, and backend topology to anyone. - /dashboard and /dashboard/status now require Bearer token - /admin (user management UI) now requires Bearer token - All /users/* and /keys/revoke routes now require Bearer token - /health scrubbed of sensitive fields (token counts, client counts) - /linkedin/* left public (required for OAuth callback flow) Auth checks use GATEWAY_STATIC_API_KEY or valid OAuth access tokens, consistent with the existing /mcp and /status endpoints. |
||
|---|---|---|
| dashboard | ||
| erpnext-mcp | ||
| forgejo-mcp | ||
| gateway-proxy | ||
| homeassistant-mcp | ||
| linkedin-mcp | ||
| memory-bank-mcp | ||
| puppeteer-mcp | ||
| scripts | ||
| sequential-thinking-mcp | ||
| ssh-mcp | ||
| truenas-mcp | ||
| wave-mcp | ||
| .env | ||
| .gitignore | ||
| API_CREDENTIALS_SETUP.md | ||
| ARCHITECTURE.md | ||
| DASHBOARD_SETUP.md | ||
| DEPLOYMENT_CHECKLIST.md | ||
| docker-compose.yml | ||
| FORGEJO_IMPLEMENTATION_SUMMARY.md | ||
| FORGEJO_SETUP.md | ||
| LINKEDIN_QUICK_START.md | ||
| LINKEDIN_TOKEN_GENERATION.md | ||
| MCP_STACK_UPDATE.md | ||
| openai_adapter.py | ||
| OPENAI_INTEGRATION.md | ||
| OPENUI_OAUTH_FIX.md | ||
| OPENUI_OAUTH_QUICK_FIX.txt | ||
| OPENUI_SCHEMA_FIX.md | ||
| QUICK_OPENUI_FIX.txt | ||
| README.md | ||
| README_OPENAI.md | ||
| RFP_SCRAPER_SETUP.md | ||
| SETUP_OPEN_UI.md | ||
| USER_MANAGEMENT_SETUP.md | ||
MCP Gateway Stack
Aggregates multiple MCP backend servers behind a single Streamable HTTP endpoint with OAuth 2.1 authentication, exposed via Tailscale Funnel.
Architecture
claude.ai / Claude Mobile / Claude Code
│
│ OAuth 2.1 (PKCE + DCR)
▼
┌─────────────────────────────┐
│ MCP Gateway Proxy (:4444) │ ← mcp.wilddragon.net via Tailscale Funnel
│ OAuth Provider + Aggregator│
└────┬──────────┬─────────┬───┘
│ │ │
▼ ▼ ▼
ERPNext TrueNAS Home
MCP MCP Assistant
(:32802) (:8100) MCP (:8200)
OAuth 2.1 Flow
When claude.ai connects to https://mcp.wilddragon.net/mcp:
- Gateway returns 401 with
WWW-Authenticateheader pointing to resource metadata - Claude discovers
/.well-known/oauth-protected-resource→ finds authorization server - Claude discovers
/.well-known/oauth-authorization-server→ finds all OAuth endpoints - Claude calls
/oauth/register(Dynamic Client Registration) to get aclient_id - Claude opens
/oauth/authorizein browser → you see a consent page → enter your password - Gateway issues an authorization code, redirects to Claude's callback
- Claude exchanges the code at
/oauth/token(with PKCE verification) → gets access + refresh tokens - Claude sends MCP requests to
/mcpwithAuthorization: Bearer <token> - Tokens auto-refresh via the refresh token grant
Setup
- Copy
.env.exampleto.envand fill in your values - Set a strong
OAUTH_PASSWORD— this is what you type in the consent page - Set
OAUTH_ISSUER_URLto your public gateway URL (e.g.,https://mcp.wilddragon.net) - Build and start:
docker compose up -d --build - In claude.ai → Settings → Connectors → Add → paste
https://mcp.wilddragon.net/mcp - Complete the OAuth flow when prompted (enter your gateway password)
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
OAUTH_ISSUER_URL |
Yes | https://mcp.wilddragon.net |
Public URL of the gateway |
OAUTH_PASSWORD |
Yes | — | Password for the consent page |
OAUTH_ACCESS_TOKEN_TTL |
No | 3600 |
Access token lifetime (seconds) |
OAUTH_REFRESH_TOKEN_TTL |
No | 2592000 |
Refresh token lifetime (seconds) |
ERPNEXT_URL |
Yes | — | ERPNext instance URL |
ERPNEXT_API_KEY |
Yes | — | ERPNext API key |
ERPNEXT_API_SECRET |
Yes | — | ERPNext API secret |
TRUENAS_URL |
Yes | — | TrueNAS API URL |
TRUENAS_API_KEY |
Yes | — | TrueNAS API key |
HASS_URL |
Yes | — | Home Assistant URL |
HASS_TOKEN |
Yes | — | Home Assistant long-lived token |
Endpoints
| Endpoint | Auth | Purpose |
|---|---|---|
GET /health |
None | Health check |
GET /status |
Bearer | Detailed backend status |
GET /.well-known/oauth-protected-resource |
None | RFC 9728 resource metadata |
GET /.well-known/oauth-authorization-server |
None | RFC 8414 server metadata |
POST /oauth/register |
None | RFC 7591 dynamic client registration |
GET /oauth/authorize |
None | Authorization page (consent form) |
POST /oauth/token |
None | Token exchange / refresh |
POST /mcp |
Bearer | MCP JSON-RPC endpoint |
Testing
# Health check
curl https://mcp.wilddragon.net/health
# Check OAuth metadata
curl https://mcp.wilddragon.net/.well-known/oauth-authorization-server
# Check resource metadata
curl https://mcp.wilddragon.net/.well-known/oauth-protected-resource
# Verify 401 on unauthenticated MCP request
curl -X POST https://mcp.wilddragon.net/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}'
Adding New Backends
Add a new MCP_BACKEND_<NAME> env var to the gateway service in docker-compose.yml and rebuild. Tools will be auto-discovered and prefixed with the backend name.