outsystems-mcp-relay
outsystems-mcp-relay
Ein leichtgewichtiges, generisches stdio → Remote-MCP-Relay mit OAuth, plus einem RFC-9207-Issuer-Override für Remote-Server, deren veröffentlichte OAuth-Metadaten nicht mit der Autorisierungsantwort übereinstimmen. Keine Laufzeitabhängigkeiten. Eine einzige Datei.
stdio (your MCP client) ⇄ outsystems-mcp-relay ⇄ remote MCP server (Streamable HTTP)Warum es das gibt
Einige Remote-MCP-Bereitstellungen sind ein Reverse-Proxy vor Keycloak (das OutSystems Developer Cloud MCP-Gateway ist eines davon). Sie veröffentlichen OAuth-Metadaten, deren issuer die Proxy-URL ist (z. B. https://<tenant>/mcp), aber der Autorisierungsserver stempelt seinen echten Issuer in den iss-Parameter der Autorisierungsantwort (z. B. https://<tenant>/auth/realms/<realm>).
RFC-9207-konforme Clients müssen diese Abweichung ablehnen, daher schlägt der OAuth-Login auf jeder Plattform fehl — Claude Code, pi, Cursor, Codex, um nur einige zu nennen. Dieses Relay ermöglicht es dir, iss gegen den echten Backend-Issuer zu validieren, während alle anderen OAuth-Prüfungen streng bleiben. Für normale Server verhält es sich wie ein einfaches Relay.
Related MCP server: mcp-auth-proxy
Wann man es verwenden sollte
Probiere zuerst die offizielle direkte Verbindung aus — richte deine Plattform direkt auf die Remote-MCP-URL aus, ohne Relay dazwischen. Greife nur dann zu diesem Relay, wenn das mit dem obigen RFC-9207-Issuer-Mismatch-Fehler fehlschlägt.
Das existiert ausschließlich, um diesen einen serverseitigen Bug zu umgehen. Es macht nichts besser als der offizielle Weg, sobald der Bug nicht mehr vorhanden ist — also wenn OutSystems es mandantenweit behebt oder dein Mandant das Problem nie hatte, entferne das Relay und verbinde dich direkt. Das Relay teilt dir mit, wann das der Fall ist: Bei einem erfolgreichen Login prüft es, ob eine Issuer-Korrektur tatsächlich nötig war, und wenn nicht, gibt es einen Hinweis auf stderr aus. Warte nicht auf eine „Wird das noch gebraucht?"-Überprüfung — wenn du diesen Hinweis siehst, wechsle sofort zurück zur offiziellen direkten Verbindung.
Installation
Erfordert Node.js ≥ 20. Keine Abhängigkeiten — nur die Datei.
npm install -g outsystems-mcp-relay # recommended
# or, without a global install:
npx outsystems-mcp-relay <remote-url> ...Du musst dieses Repo nicht klonen, um das Relay zu nutzen. Installiere es über npm (oder verwende npx) und fertig. Klone es nur, wenn du den Quellcode (eine einzelne Datei mit ~500 Zeilen) prüfen oder dazu beitragen möchtest.
Verwendung
outsystems-mcp-relay <remote-url> [options]
--as-metadata-url <url> OAuth AS metadata URL (default: discover from remote-url)
--expected-issuer <url> Override the RFC 9207 expected issuer (the proxy fix)
--client-id <id> Pre-registered client id (skips dynamic registration)
--bearer <token> Static bearer token mode (skips OAuth entirely)
--force Ignore cached tokens and re-authenticate
--no-open Print the authorization URL instead of opening a browser
--help Show helpGenerisches Beispiel (normaler Remote-Server)
// mcp.json
{
"mcpServers": {
"my-remote": {
"command": "outsystems-mcp-relay",
"args": ["https://api.example.com/mcp"]
}
}
}OutSystems-Beispiel (Issuer-Mismatch)
{
"mcpServers": {
"outsystems": {
"command": "outsystems-mcp-relay",
"args": ["https://<tenant>.outsystems.dev/mcp"]
}
}
}Kein --expected-issuer nötig — das Relay erkennt automatisch den echten Autorisierungsserver-Issuer aus der Autorisierungs-Weiterleitung (Keycloak-Realm-Setups). Füge nur dann
--expected-issuer https://<tenant>.outsystems.dev/auth/realms/<realm-id> hinzu, wenn die automatische Erkennung fehlschlägt (ein Nicht-Keycloak-Server): Die OAuth-Fehlermeldung gibt den Realm aus — der empfangene Wert ist der zu verwendende Wert. Die automatische Erkennung übernimmt einen Cross-Origin-Kandidaten nur, wenn dessen Issuer durch die eigenen Metadaten des Realms bestätigt wird (über die Origin-Allowlist erreichbar); für einen wirklich separaten IdP-Host übergib --expected-issuer (oder --as-metadata-url, um ihn vorab auf die Allowlist zu setzen).
Beim ersten Aufruf öffnet das Relay einen Browser zur Anmeldung (oder gibt die URL mit --no-open aus). Tokens werden zwischengespeichert und automatisch aktualisiert.
Installation über eine KI (diesen Text einfügen)
Füge dies in Claude Code, pi, Cursor oder eine beliebige KI-Plattform ein:
Install the OutSystems MCP fix (outsystems-mcp-relay). The official OutSystems
MCP fails OAuth on every AI harness with an RFC 9207 issuer mismatch — a
server-side bug in the gateway's Keycloak setup.
Step 1: run `npm install -g outsystems-mcp-relay`.
Step 2: ask me for my OutSystems tenant hostname (something like
`mycompany.outsystems.dev`).
Step 3: when I tell you, replace the broken server:
`claude mcp remove outsystems`
`claude mcp add -s user --transport stdio outsystems -- outsystems-mcp-relay https://<my-tenant>/mcp`
(substitute my actual tenant. No other flags needed — the relay auto-detects
the real authorization-server issuer; if auto-detection can't, ask me to paste
the OAuth error and use its "received" URL as `--expected-issuer`.)
Step 4: tell me to restart Claude Code, then ask anything OutSystems-related.
The first tool call opens a browser for sign-in (or prints the URL with
`--no-open`).Claude-Code-Schnellstart (OutSystems-Issuer-Mismatch)
Der Fehler, den du siehst, sieht so aus:
Issuer mismatch in authorization response (RFC 9207):
expected "https://<tenant>.outsystems.dev/mcp",
received "https://<tenant>.outsystems.dev/auth/realms/<realm-id>"In einem Terminal (nicht innerhalb von Claude Code):
npm install -g outsystems-mcp-relay
# 1. remove the broken HTTP entry
claude mcp remove outsystems
# 2. add the relay as a local stdio server — no other flags needed: it
# auto-detects the real authorization-server issuer
claude mcp add -s user --transport stdio outsystems -- \
outsystems-mcp-relay \
https://<tenant>.outsystems.dev/mcpStarte dann Claude Code neu. Beim ersten OutSystems-Toolaufruf öffnet das Relay einen Browser zur Anmeldung (füge --no-open hinzu, wenn du die URL lieber selbst einfügen möchtest). Tokens werden zwischengespeichert, sodass spätere Sitzungen die Anmeldung überspringen. Überprüfe mit /mcp (der Server sollte verbunden sein) und einem einfachen „list my environments".
Du musst den Realm-Issuer nicht selbst ermitteln. Das Relay erkennt ihn automatisch aus der Autorisierungs-Weiterleitung. Falls die automatische Erkennung nicht funktioniert (ein Nicht-Keycloak-Server), gibt die Fehlermeldung den empfangenen Wert aus — dieser ist der
--expected-issuer-Wert.
So funktioniert es
Protokollagnostische Durchreichung: liest zeilenweise JSON-RPC von stdin, sendet jeden Frame unverändert per POST an den Remote-Server und schreibt die JSON-RPC-Antwort zurück nach stdout. Keine Tool-Semantik hier — funktioniert für Tools, Ressourcen, Prompts, alles.
Behandelt Streamable-HTTP-Details:
Mcp-Session-Id-Echo, direkte JSON-Antworten und202/text/event-stream-Antworten (SSE-Zusammenführung).OAuth: ermittelt die Autorisierungsserver-Metadaten, registriert dynamisch einen öffentlichen Client (PKCE S256), öffnet den Browser, validiert
stateundiss, tauscht den Code aus und aktualisiert Tokens bei 401.--expected-issuerlegt den Issuer fest, gegen denissvalidiert wird — die Lösung für Proxy/Keycloak-Mismatches.Anfragen werden serialisiert (keine verschachtelten Antworten auf stdout).
Sicherheit
RFC 9207 durchgesetzt:
isswird nur validiert, wenn der Autorisierungsserver es tatsächlich sendet (fehlt es = der AS implementiert RFC 9207 nicht, keine Prüfung; vorhanden = strikter String-Vergleich gegen den erwarteten Issuer).--expected-issuerermöglicht einen anderen erwarteten Wert — es deaktiviert niemals die Validierung.Origin-Allowlist: Das Relay kontaktiert nur die konfigurierte Remote-Origin (und eine explizit angegebene
--as-metadata-url). Weiterleitungen werden manuell durchlaufen und jeder Hop ist auf der Allowlist (307/308 erhalten den Request-Body; 301/302/303 wechseln gemäß HTTP-Semantik zu GET), undAuthorization/Cookiewerden entfernt, wenn eine Weiterleitung die Origin wechselt (wie beim nativen fetch). Kein SSRF.PKCE S256 + zufälliger
state(validiert) + Callback-Server nur auf localhost mit einem ephemeren Port.Protokolliert niemals Geheimnisse: Tokens und Autorisierungscodes erscheinen nie in der Ausgabe (alle Diagnosen gehen nach stderr; stdout transportiert nur Protokollnachrichten).
Tokens werden unter
~/.mcp-auth/outsystems-mcp-relay-<sha1(url)>.jsonmit0600-Berechtigungen gespeichert — die Ökosystem-Konvention (gleiche Speicherstruktur wiemcp-remote). OS-Keychain-Speicherung ist eine geplante Erweiterung; siehe Nicht-Ziele.
Testen
npm test # mock-server protocol test (passthrough, session-id, SSE, 401)
npm run test:e2e -- <remote-url> --expected-issuer <issuer> # real-tenant round tripFehlerbehebung
Symptom | Lösung |
| Normalerweise erledigt die automatische Erkennung das ohne zusätzliche Flags. Falls nicht, übergib die empfangene URL als |
| Das zwischengespeicherte Token ist abgelaufen und die Aktualisierung fehlgeschlagen. Führe es mit |
Browser öffnet sich nicht | Füge |
Dynamische Client-Registrierung schlägt fehl | Der Registrierungs-Endpunkt des Servers ist eingeschränkt (z. B. durch Keycloaks Trusted-Hosts-Richtlinie). Falls es das OutSystems-Proxy ist, sollte das nicht passieren; andernfalls registriere einen Client selbst und übergib |
Etwas anderes | Öffne ein Issue mit dem vollständigen Fehlertext (alle Diagnosen gehen nach stderr — schwärze alle Tokens). |
Nicht-Ziele (v1)
OS-Keychain-Token-Speicherung (derzeit Datei mit 0600-Berechtigungen)
Multi-Server-Aggregation / -Verwaltung (verwende dafür ein Gateway)
Vom Server initiierte Benachrichtigungs-Streams über die Durchreichung hinaus
Benutzerdefinierte CA-Flags
Lizenz
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
- QuallaaOAuthcom.quallaa
Talk to your public-facing AI from any MCP client — Claude, ChatGPT, Cursor, Cline, Windsurf.
Hosted OAuth MCP at https://www.taskade.com/mcp, or local @taskade/mcp-server.
Enable secure connectivity between Sentry issues and debugging data, and LLM clients, using a Model Context Protocol (MCP) server.
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
Related MCP Servers
- AlicenseAqualityCmaintenanceLocal stdio proxy for Uno MCP Gateway that enables MCP clients without OAuth support to securely connect to authenticated remote servers.821 PyPI1MIT
- FlicenseNot gradedqualityDmaintenanceBridges stdio-based LLM harnesses to OAuth-protected remote MCP servers via Streamable HTTP, handling PKCE browser login and token refresh automatically.5 npm-
- AlicenseNot gradedqualityAmaintenanceBridge that lets stdio-only MCP clients connect to remote MCP servers with OAuth and other auth support, enabling local clients to use remote, authorized MCP servers.19 npm54MIT
- FlicenseNot gradedqualityCmaintenanceEnables local MCP clients to access tools from a remote FastMCP server over stdio, handling OAuth authentication and Streamable HTTP communication.-