mcp-gateway
MCP Gateway
Ein leichtgewichtiges, selbstgehostetes MCP-Aggregator-Gateway: ein öffentlicher MCP-Endpunkt vor beliebig vielen geschützten Backend-MCP-Servern, mit einem spezifikationskonformen OAuth-2.1-Autorisierungsserver, der dem MCP-Client zugewandt ist – das Element, das den meisten vorhandenen Gateways fehlt.
Claude Code / Claude.ai ──OAuth 2.1 (DCR/CIMD + PKCE)──▶ MCP Gateway ──own credentials──▶ GitHub MCP
│ ▶ Microsoft Learn MCP
└── /mcp (Streamable HTTP) ▶ …more backendsEntwickelt mit FastAPI + FastMCP, konfiguriert über eine einzelne YAML-Datei, speichert seinen Zustand in einer einzigen verschlüsselten SQLite-Datenbank und wird als ein kleiner, eigenständiger Container ausgeliefert – kein Reverse-Proxy erforderlich, man kann jedoch einen davor setzen, wenn TLS benötigt wird.
Funktionen
Client-seitig (MCP-Autorisierungsspezifikation, 2025-11-25):
OAuth-2.1-Autorisierungscode-Ablauf mit verpflichtendem PKCE (S256)
Dynamische Client-Registrierung (RFC 7591) unter
/register—claude mcp addfunktioniert ohne vorab geteilte ZugangsdatenClient-ID-Metadaten-Dokumente (CIMD) – HTTPS-URLs als Client-IDs, einschließlich
private_key_jwt-Client-Authentifizierung, bekanntgegeben überclient_id_metadata_document_supported: trueAutorisierungsserver-Metadaten (RFC 8414) + OIDC-Discovery-Alias
Metadaten der geschützten Ressource (RFC 9728); 401-Antworten enthalten
WWW-Authenticate: Bearer resource_metadata="…", wie es der Connector von Claude verlangtRessourcenindikatoren (RFC 8707) werden akzeptiert und an die ausgegebenen Token gebunden
Kurzlebige, undurchschaubare Zugriffstokens, rotierende Refresh-Tokens, einmalig nutzbare Autorisierungscodes – alle nur gehasht gespeichert; Client-Datensätze im Ruhezustand verschlüsselt
Loopback-Weiterleitungs-URIs werden portunabhängig abgeglichen (die Claude-Code-CLI registriert einen Port und autorisiert mit einem anderen); Nicht-Loopback-URIs erfordern die exakte Registrierung
Schlanke Svelte-5-Benutzeroberfläche für Login und Zustimmung (eine einzige lokale Identität aus der Konfigurationsdatei)
Backend-seitig:
none– öffentliche Server (z. B. Microsoft Learn MCP)bearer– statische Token-Injektion (Authorization: Bearer …, z. B. PATs)headers– beliebige statische Header (API-Schlüssel)oauth– vollwertiger OAuth-Client nach der MCP-Spezifikation: Metadaten-Discovery, CIMD, sofern das Upstream-AS dies unterstützt (das Gateway hostet sein eigenes Client-Metadaten-Dokument), DCR-Fallback, PKCE, automatisches Refresh. Einmal über den Browser verbunden; Token werden verschlüsselt (Fernet) in SQLite gespeichert.Das Gateway-Token des Clients wird nie weiter übergeben an den Upstream (kein Token-Passthrough, wie von der Spezifikation gefordert); Backends sehen ausschließlich Zugangsdaten, die das Gateway hält.
Aggregation:
Tools/Ressourcen/Prompts werden pro Backend namespacediert:
github_create_issue,msdocs_microsoft_docs_search, …Live-Proxy über Streamable HTTP; ein heruntergefahrenes oder noch nicht verbundenes Backend entfernt nur seine eigenen Tools, anstatt das Gateway zu beeinträchtigen
Integriertes
gateway_status-Tool
Related MCP server: MCP OAuth Test
Schnellstart
cp config.example.yaml config.yaml
$EDITOR config.yaml # set public_url, users, backends
cp .env.example .env
$EDITOR .env # set MCP_GATEWAY_ENCRYPTION_KEY (openssl rand -base64 32)
docker compose up -dDas Gateway läuft eigenständig und lauscht auf :8000; docker compose übernimmt MCP_GATEWAY_ENCRYPTION_KEY automatisch aus .env. Platzieren Sie es hinter einem Reverse-Proxy Ihrer Wahl für TLS oder legen Sie den Port direkt offen.
Erzeugen Sie einen Passwort-Hash für die Konfigurationsdatei:
docker compose run --rm mcp-gateway mcp-gateway hash-passwordClaude Code verbinden (CLI)
claude mcp add --transport http gateway https://mcp.example.com/mcpClaude Code entdeckt den Autorisierungsserver des Gateaways, registriert sich über DCR oder seine CIMD-Client-ID und öffnet Ihren Browser: Melden Sie sich mit einem Benutzer aus config.yaml an, genehmigen Sie alles, fertig. Keine Token müssen eingefügt werden.
Claude.ai / Claude Code Web verbinden (benutzerdefinierter Connector)
Fügen Sie https://mcp.example.com/mcp als benutzerdefinierten Connector hinzu. Die Browser-Weiterleitung an https://claude.ai/api/mcp/auth_callback durchläuft denselben Login-/Zustimmungsablauf.
OAuth-Backends verbinden
Öffnen Sie https://mcp.example.com/ui/backends, melden Sie sich an und drücken Sie Verbinden bei jedem OAuth-Backend (z. B. GitHub MCP). Sie werden genau einmal zum Autorisierungsserver des Backends umgeleitet; anschließend erneuert das Gateway Token automatisch.
Konfiguration
Alles befindet sich in einer YAML-Datei (siehe config.example.yaml). Werte unterstützen ${ENV_VAR} beziehungsweise ${ENV_VAR:-default}-Erweiterung.
server:
public_url: https://mcp.example.com # behind your reverse proxy
auth:
encryption_key: ${MCP_GATEWAY_ENCRYPTION_KEY} # encrypts secrets at rest
users:
- username: admin
password_hash: "$2b$12$…" # mcp-gateway hash-password
access_token_expiry_seconds: 3600
refresh_token_expiry_seconds: 2592000
storage:
path: /data/gateway.db # SQLite; the only state
backends:
github: # → tools namespaced github_*
url: https://api.githubcopilot.com/mcp/
auth:
type: oauth
# GitHub's authorization server supports neither CIMD nor DCR, so
# register a GitHub OAuth App and provide its credentials directly:
client_id: ${GITHUB_OAUTH_CLIENT_ID}
client_secret: ${GITHUB_OAUTH_CLIENT_SECRET}
microsoft-docs: # → tools namespaced microsoft-docs_*
url: https://learn.microsoft.com/api/mcp
auth: { type: none }
something-with-a-pat:
url: https://example.com/mcp
auth: { type: bearer, token: "${SOME_PAT}" }Das Hinzufügen eines Backends ist reine Konfiguration – keine Codeänderungen.
Backend-Authentifizierungsreferenz
Typ | Felder | Verhalten |
| – | keine Zugangsdaten gesendet |
|
|
|
|
| statische Header (API-Schlüssel usw.) |
|
| vollwertiger OAuth-Client: CIMD → DCR-Fallback, PKCE, Refresh, verschlüsselter Speicher |
Bei oauth-Backends hostet das Gateway sein eigenes Client-ID-Metadaten-Dokument unter <public_url>/oauth/client-metadata.json und verwendet es als Client-ID, sobald der Upstream-AS CIMD-Unterstützung bewirbt (dann ist eine HTTPS-public_url erforderlich). Andernfalls wird die Dynamische Client-Registrierung (DCR) verwendet. Wenn nicht der das Upstream-AS keines von beiden unterstützt (z. B. der von GitHub), setzen Sie client_id (und client_secret, falls die App vertraulich ist), um einen vorregistrierten OAuth-Client zu verwenden – CIMD/DCR werden dann vollständig übersprungen.
Logging
Das Gateway protokolliert nach stdout/stderr (docker logs, docker compose logs -f), on standard INFO: Start/Herunterfahren, Konfigurationsübersicht, Anmeldeversuche, OAuth-Autorisierung-/Einwilligung/Token-Ausgabe, Backend-Verbindung/Trennung sowie den Mount-Status der Backends. DEBUG fügt feinkörniger Details hinzu (Client-Konstruktion, Token-Rotation, CIMD-Aktualisierung, Haushaltsführung des Speichers). Zu keiner Protokollstufe werden jemals Zugangsdaten oder Token protokolliert.
Legen Sie die Stufe über die Umgebungsvariable MCP_GATEWAY_LOG_LEVEL fest (debug, info, warning, error oder critical):
# .env (picked up by docker compose)
MCP_GATEWAY_LOG_LEVEL=debug# or inline
docker compose run --rm -e MCP_GATEWAY_LOG_LEVEL=debug mcp-gatewaydocker-compose.yml übergibt diese Variable jetzt bereits an die Entiät; wenn keine gesetzt ist, wird standardmäßig info verwendet.
Außerhalb von Docker funktioniert --log-level bei mcp-gateway run genauso und hat Vorrang vor der Umgebungsvariable:
mcp-gateway run -c config.yaml --log-level debugEndpunkte
Pfad | Zweck |
| MCP-Endpunkt (Streamable-Web) |
| Metadaten der geschützten Ressource (RFC 9728) |
| Autorisierungsserver-Metadaten (RFC 8414) + OIDC-Alias |
| OAuth-2.1-Endpunkte (PKCE, DCR, Widerruf) |
| Login / Zustimmung (Svelte 5) |
| Backend-Verbindungsstatus / verbinden / trennen |
| eigener CIMD-Dokument des Gateways (Upstream-Strecke) |
| Upstream-OAuth-Verbindungsablauf |
| Liveness-Check |
Sicherheitshinweise
PKCE (S256) ist verpflichtend; Autorisierungscodes sind einmalig nutzbar und verfallen nach 5 Minuten.
Refresh-Tokens rotieren bei jeder Verwendung (Anforderung für öffentliche Clients in OAuth 2.1).
Zugriffs-, Refresh-Tokens und Autorisierungscodes werden ausschließlich als SHA-256-Hashes gespeichert.
Registrierte Client-Datensätze und Upstream-Zugangsdaten werden im Ruhezustand mit Fernet verschlüsselt (
auth.encryption_key; Passphrasen werden mit scrypt und pro Datenbank Salt abgeleitet).Der Zustimmungsbildschirm nennt den Client und das exakte Umleitungsziel und warnt bei Loopback-Weiterleitungen (gemäß CIMD-Vorgaben zur Vermeidung von Localhost-Impersonation).
Tokens, die an MCP-Clients ausgegeben werden, werden niemals an Backends weitergeleitet; Backend-Zugangsdaten erreichen nie MCP-Clients.
Sitzungen sind signiert (
itsdangerous),HttpOnly,SameSite=Lax,Securebei HTTPS.Zugangsdaten werden nicht protokolliert.
Entwicklung
uv venv && uv pip install -e ".[dev]" # or: pip install -e ".[dev]"
(cd ui && npm install && npm run build) # build the Svelte UI
pytest # 35 tests incl. full e2e OAuth flows
mcp-gateway run -c config.yamlDie Testsuite startet echte Gateways (und eine zweite Instanz, die als OAuth-geschützter Upstream dient) und durchläuft vollständige DCR/CIMD- und PKCE-Abläufe über HTTP.
Architektur
src/mcp_gateway/oauth_server.py– der client-zugewandte OAuth-AS. Er baut auf den Autorisierungsserver-Handlern der MCP-SDK und dem CIMD-Manager von FastMCP auf, statt Protokollcode von Hand zu schreiben; das Gateway ergänzt SQLite-Persistenz, den Login-/Zustimmungs-Transaktions Flow und die Richtlinie für Token-Ausgabe/-Rotation.src/mcp_gateway/upstream.py– Backend-Clients. OAuth-Backends verwenden den offiziellenOAuthClientProviderdes SDK (Discovery, CIMD/DCR, Refresh) mit verschlüsseltem SQLite-Tokenspeicher und einem über Browser gesteuerten Verbindungsablauf.src/mcp_gateway/gateway.py– FastMCP-Server; jedes Backend wird als Live-Proxy unter seinem Namespace eingebunden.src/mcp_gateway/app.py/web.py– FastAPI-App: JSON-API für die UI, Upstream-Callback, CIMD-Dokument, statische Svelte-App; die FastMCP-App (MCP-Endpunkt + OAuth-Routen + Well-Known) wird im Root-Verzeichnis gemounted.ui/– Svelte 5 + Vite SPA (Anmeldung, Zustimmung, Backends).
Bewusst als Ein-Instanz-Design (SQLite + In-Memory-Verbindungsabläufe). Läuft eigenständig; Sie können es hinterbringen vorhandenen Reverse-Proxy für TLS-Terminierung und sichern eine einzige Datei.
This server cannot be deployed
Maintenance
Related MCP Connectors
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
One MCP endpoint for your company's tools, with per-person sign-in, policy and audit.
Self-hosted federated MCP gateway: one OAuth 2.1 MCP server in front of N apps, user-level scopes.
MCP server for mandates, delegation, policy-gated execution, credential grants, and audit.
Related MCP Servers
- FlicenseNot gradedqualityNot gradedmaintenanceAggregates multiple MCP servers behind a single, secure endpoint with unified tool/resource discovery, OAuth authentication, and resilient request routing. Enables users to manage and interact with multiple MCP backends through one centralized interface with load balancing and circuit breakers.2-
- FlicenseNot gradedqualityDmaintenanceMulti-tenant MCP server with OAuth 2.1 authorization, enabling tenant-scoped tool access and audit logging.-
- AlicenseAqualityCmaintenanceA federated MCP gateway that consolidates multiple plain-HTTP backends into a single, OAuth-protected MCP server, enabling agents to access diverse tools through one endpoint with centralized authentication and audit.512MIT
- AlicenseNot gradedqualityDmaintenanceAuthenticating reverse proxy for MCP servers providing credential isolation, OAuth2 token management, and composite tool aggregation.BSD Zero Clause