outsystems-mcp-relay
outsystems-mcp-relay
Un relé MCP remoto genérico y ligero de stdio con OAuth, además de una anulación del emisor RFC 9207 para servidores remotos cuyos metadatos OAuth publicados no coinciden con la respuesta de autorización. Cero dependencias en tiempo de ejecución. Un solo archivo.
stdio (your MCP client) ⇄ outsystems-mcp-relay ⇄ remote MCP server (Streamable HTTP)Por qué existe
Algunos despliegues remotos de MCP son un proxy inverso delante de Keycloak (la puerta de enlace MCP de OutSystems Developer Cloud es uno de ellos). Publican metadatos OAuth cuyo issuer es la URL del proxy (p. ej. https://<tenant>/mcp), pero el servidor de autorización sella su emisor real en el parámetro iss de la respuesta de autorización (p. ej. https://<tenant>/auth/realms/<realm>).
Los clientes compatibles con RFC 9207 deben rechazar esa discrepancia, por lo que el inicio de sesión OAuth falla en cualquier entorno — Claude Code, pi, Cursor, Codex, los que sea. Este relé te permite validar iss contra el emisor real del backend mientras mantiene estrictas todas las demás comprobaciones OAuth. Para servidores normales se comporta como un relé simple.
Related MCP server: mcp-auth-proxy
Cuándo usar esto
Prueba primero la conexión directa oficial: apunta tu entorno directamente a la URL MCP remota, sin relé en medio. Recurre a este relé solo si eso falla con el error de discrepancia de emisor RFC 9207 mencionado arriba.
Esto existe únicamente para solucionar ese bug del lado del servidor. No hace nada mejor que la vía oficial una vez que el bug no está — así que si OutSystems lo corrige en todo el tenant, o tu tenant nunca lo tuvo, deja el relé y conéctate directamente. El relé te avisa cuando ese es el caso: en un inicio de sesión correcto comprueba si realmente fue necesaria alguna corrección del emisor y, si no, imprime una nota en stderr indicándolo. No esperes a una revisión de «¿todavía hace falta?» — si ves esa nota, vuelve a la conexión directa oficial de inmediato.
Instalación
Requiere Node.js ≥ 20. Sin dependencias: solo el archivo.
npm install -g outsystems-mcp-relay # recommended
# or, without a global install:
npx outsystems-mcp-relay <remote-url> ...No necesitas clonar este repositorio para usar el relé. Instálalo desde npm (o usa npx) y listo. Clónalo solo para auditar el código fuente (un único archivo de ~500 líneas) o para contribuir.
Uso
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 helpEjemplo genérico (servidor remoto normal)
// mcp.json
{
"mcpServers": {
"my-remote": {
"command": "outsystems-mcp-relay",
"args": ["https://api.example.com/mcp"]
}
}
}Ejemplo de OutSystems (discrepancia de emisor)
{
"mcpServers": {
"outsystems": {
"command": "outsystems-mcp-relay",
"args": ["https://<tenant>.outsystems.dev/mcp"]
}
}
}No se necesita --expected-issuer: el relé detecta automáticamente el emisor real del servidor de autorización a partir de la redirección de autorización (configuraciones de realm de Keycloak). Añade --expected-issuer https://<tenant>.outsystems.dev/auth/realms/<realm-id> solo si falla la detección automática (un servidor que no sea Keycloak): el mensaje de error OAuth imprime el realm — su valor recibido es el valor que hay que usar. La detección automática solo adopta un candidato de otro origen cuando su emisor es confirmado por los metadatos del propio realm (accesibles a través de la lista de orígenes permitidos); para un host IdP realmente separado, pasa --expected-issuer (o --as-metadata-url para incluirlo de antemano en la lista de permitidos).
En la primera llamada, el relé abre un navegador para iniciar sesión (o imprime la URL con --no-open). Los tokens se guardan en caché y se renuevan automáticamente.
Instalación mediante un asistente de IA (pega esto)
Pégalo en Claude Code, pi, Cursor o cualquier entorno de IA:
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`).Inicio rápido con Claude Code (discrepancia de emisor de OutSystems)
El error que estás viendo tiene este aspecto:
Issuer mismatch in authorization response (RFC 9207):
expected "https://<tenant>.outsystems.dev/mcp",
received "https://<tenant>.outsystems.dev/auth/realms/<realm-id>"En una terminal (no dentro de 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/mcpDespués reinicia Claude Code. En la primera llamada a una herramienta de OutSystems, el relé abre un navegador para iniciar sesión (añade --no-open si prefieres pegar la URL). Los tokens se guardan en caché, así que las sesiones posteriores omiten el inicio de sesión. Verifícalo con /mcp (el servidor debería estar conectado) y un simple «lista mis entornos».
No necesitas buscar el emisor del realm. El relé lo detecta automáticamente a partir de la redirección de autorización. Si la detección automática no puede (un servidor que no sea Keycloak), el mensaje de error lo imprime: el valor recibido en el error ES el valor de
--expected-issuer.
Cómo funciona
Paso directo agnóstico del protocolo: lee JSON-RPC delimitado por saltos de línea desde stdin, envía cada trama tal cual mediante POST al servidor remoto y escribe la respuesta JSON-RPC de vuelta en stdout. Aquí no hay semántica de herramientas: funciona para herramientas, recursos, prompts, cualquier cosa.
Gestiona los detalles de Streamable HTTP: eco de
Mcp-Session-Id, respuestas JSON directas y respuestas202/text/event-stream(reensamblado de SSE).OAuth: descubre los metadatos del servidor de autorización, registra dinámicamente un cliente público (PKCE S256), abre el navegador, valida
stateeiss, intercambia el código y renueva los tokens ante un 401.--expected-issuerestablece el emisor contra el que se validaiss— la solución para las discrepancias de proxy/Keycloak.Las peticiones se serializan (sin respuestas intercaladas en stdout).
Seguridad
RFC 9207 aplicado:
isssolo se valida cuando el servidor de autorización realmente lo envía (ausente = el AS no implementa RFC 9207, sin comprobación; presente = coincidencia estricta de cadena con el emisor esperado).--expected-issueropta por un valor esperado diferente — nunca desactiva la validación.Lista de orígenes permitidos: el relé solo contacta con el origen remoto configurado (y con un
--as-metadata-urlproporcionado explícitamente). Las redirecciones se recorren manualmente y cada salto está en la lista de permitidos (307/308 conservan el cuerpo de la petición; 301/302/303 degradan a GET según la semántica HTTP), yAuthorization/Cookiese eliminan cuando una redirección cambia de origen (igual que el fetch nativo). Sin SSRF.PKCE S256 +
statealeatorio (validado) + servidor de callback solo en localhost en un puerto efímero.Nunca registra secretos: los tokens y los códigos de autorización nunca aparecen en la salida (todos los diagnósticos van a stderr; stdout solo lleva mensajes de protocolo).
Los tokens se almacenan en
~/.mcp-auth/outsystems-mcp-relay-<sha1(url)>.jsoncon permisos0600— la convención del ecosistema (misma forma de almacenamiento quemcp-remote). El almacenamiento en el llavero del sistema operativo es una mejora planificada; consulta Fuera de alcance.
Pruebas
npm test # mock-server protocol test (passthrough, session-id, SSE, 401)
npm run test:e2e -- <remote-url> --expected-issuer <issuer> # real-tenant round tripSolución de problemas
Síntoma | Solución |
| Normalmente la detección automática lo resuelve sin opciones. Si no puede, pasa la URL recibida como |
| El token en caché expiró y la renovación falló. Vuelve a ejecutarlo con |
El navegador nunca se abre | Añade |
Fallo en el registro dinámico de clientes | El endpoint de registro del servidor está restringido (p. ej. la política Trusted-Hosts de Keycloak). Si es el proxy de OutSystems esto no debería ocurrir; de lo contrario, registra un cliente tú mismo y pasa |
Cualquier otra cosa | Abre un issue con el texto completo del error (todos los diagnósticos van a stderr — redacta cualquier token) |
Fuera de alcance (v1)
Almacenamiento de tokens en el llavero del sistema operativo (por ahora, archivo con permisos 0600)
Agregación / gestión de múltiples servidores (usa una puerta de enlace para eso)
Transmisión de notificaciones iniciadas por el servidor más allá del paso directo
Opciones de CA personalizadas
Licencia
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceLocal stdio proxy for Uno MCP Gateway that enables MCP clients without OAuth support to securely connect to authenticated remote servers.1MIT
- FlicenseNot gradedqualityDmaintenanceBridges stdio-based LLM harnesses to OAuth-protected remote MCP servers via Streamable HTTP, handling PKCE browser login and token refresh automatically.9
- FlicenseNot gradedqualityDmaintenanceEnables AI clients like Claude to interact with Cartena tools via MCP, supporting remote OAuth or local stdio authentication.
- AlicenseNot gradedqualityAmaintenanceA local stdio MCP server that authenticates to remote OAuth-protected MCP servers using the client_credentials grant, handling token acquisition and request forwarding.251Apache 2.0
Related MCP Connectors
Access Kernel's cloud-based browsers and app actions via MCP (remote HTTP + OAuth).
StremAI MCP: shared memory for AI coding agents. Connected agents can recall. OAuth + local stdio.
Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/izambasiron/outsystems-mcp-relay'
If you have feedback or need assistance with the MCP directory API, please join our Discord server