outsystems-mcp-relay
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@outsystems-mcp-relayConnect me to my OutSystems MCP server"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
outsystems-mcp-relay
A lightweight, generic stdio → remote MCP relay with OAuth, plus an RFC 9207 issuer override for remote servers whose published OAuth metadata doesn't match the authorization response. Zero runtime dependencies. One file.
stdio (your MCP client) ⇄ outsystems-mcp-relay ⇄ remote MCP server (Streamable HTTP)Why this exists
Some remote MCP deployments are a reverse proxy in front of Keycloak (the
OutSystems Developer Cloud MCP gateway is one). They publish OAuth metadata
whose issuer is the proxy URL (e.g. https://<tenant>/mcp), but the
authorization server stamps its real issuer in the authorization-response
iss parameter (e.g. https://<tenant>/auth/realms/<realm>).
RFC 9207-compliant clients must reject that mismatch, so OAuth login fails
on every harness — Claude Code, pi, Cursor, Codex, you name it. This relay lets
you validate iss against the true backend issuer while keeping every other
OAuth check strict. For normal servers it behaves like a plain relay.
Related MCP server: mcp-auth-proxy
When to use this
Try the official direct connection first — point your harness straight at the remote MCP URL, no relay in between. Only reach for this relay if that fails with the RFC 9207 issuer-mismatch error above.
This exists solely to work around that one server-side bug. It doesn't do anything better than the official path once the bug isn't there — so if OutSystems fixes it tenant-wide, or your tenant never hit it in the first place, drop the relay and connect directly. The relay tells you when that's the case: on a successful login it checks whether any issuer correction was actually needed, and if not, prints a note to stderr saying so. Don't wait for a "does it still need it" review — if you see that note, switch back to the official direct connection right away.
Install
Requires Node.js ≥ 20. No dependencies — just the file.
npm install -g outsystems-mcp-relay # recommended
# or, without a global install:
npx outsystems-mcp-relay <remote-url> ...You do not need to clone this repo to use the relay. Install from npm (or
use npx) and you're done. Clone it only to audit the source (a single
~500-line file) or contribute.
Usage
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 helpGeneric example (normal remote server)
// mcp.json
{
"mcpServers": {
"my-remote": {
"command": "outsystems-mcp-relay",
"args": ["https://api.example.com/mcp"]
}
}
}OutSystems example (issuer mismatch)
{
"mcpServers": {
"outsystems": {
"command": "outsystems-mcp-relay",
"args": ["https://<tenant>.outsystems.dev/mcp"]
}
}
}No --expected-issuer needed — the relay auto-detects the real
authorization-server issuer from the authorize redirect (Keycloak realm
setups). Only add
--expected-issuer https://<tenant>.outsystems.dev/auth/realms/<realm-id> if
auto-detection fails (a non-Keycloak server): the OAuth error message prints
the realm — its received value is the value to use. Auto-detection only
adopts a cross-origin candidate when its issuer is confirmed by the realm's
own metadata (reachable through the origin allowlist); for a genuinely
separate IdP host, pass --expected-issuer (or --as-metadata-url to
pre-allowlist it).
On the first call the relay opens a browser for sign-in (or prints the URL with
--no-open). Tokens are cached and refreshed automatically.
Install via an AI assistant (paste this)
Paste into Claude Code, pi, Cursor, or any AI harness:
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 quickstart (OutSystems issuer mismatch)
The error you're seeing looks like this:
Issuer mismatch in authorization response (RFC 9207):
expected "https://<tenant>.outsystems.dev/mcp",
received "https://<tenant>.outsystems.dev/auth/realms/<realm-id>"In a terminal (not inside 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/mcpThen restart Claude Code. On the first OutSystems tool call the relay opens
a browser for sign-in (add --no-open if you'd rather paste the URL). Tokens
are cached, so later sessions skip sign-in. Verify with /mcp (server should be
connected) and a simple "list my environments".
You don't need to hunt for the realm issuer. The relay auto-detects it from the authorize redirect. If auto-detection can't (a non-Keycloak server), the error message prints it: the received value in the error IS the
--expected-issuervalue.
How it works
Protocol-agnostic passthrough: reads newline-delimited JSON-RPC from stdin, POSTs each frame verbatim to the remote server, writes the JSON-RPC response back to stdout. No tool semantics live here — works for tools, resources, prompts, anything.
Handles Streamable HTTP details:
Mcp-Session-Idecho, direct-JSON responses, and202/text/event-streamresponses (SSE reassembly).OAuth: discovers the authorization-server metadata, dynamically registers a public client (PKCE S256), opens the browser, validates
stateandiss, exchanges the code, refreshes tokens on 401.--expected-issuersets the issuerissis validated against — the fix for proxy/Keycloak mismatches.Requests are serialized (no interleaved responses on stdout).
Security
RFC 9207 enforced:
issis validated only when the authorization server actually sends it (absent = the AS doesn't implement RFC 9207, no check; present = strict string match against the expected issuer).--expected-issueropts into a different expected value — it never disables validation.Origin allowlist: the relay only contacts the configured remote origin (and an explicitly provided
--as-metadata-url). Redirects are walked manually and every hop is allowlisted (307/308 preserve the request body; 301/302/303 downgrade to GET per HTTP semantics), andAuthorization/Cookieare stripped when a redirect changes origin (matching native fetch). No SSRF.PKCE S256 + random
state(validated) + localhost-only callback server on an ephemeral port.Never logs secrets: tokens and authorization codes never appear in output (all diagnostics go to stderr; stdout carries protocol messages only).
Tokens are stored at
~/.mcp-auth/outsystems-mcp-relay-<sha1(url)>.jsonwith0600permissions — the ecosystem convention (same store shape asmcp-remote). OS-keychain storage is a planned enhancement; see Non-goals.
Testing
npm test # mock-server protocol test (passthrough, session-id, SSE, 401)
npm run test:e2e -- <remote-url> --expected-issuer <issuer> # real-tenant round tripTroubleshooting
Symptom | Fix |
| Normally auto-detection handles this with zero flags. If it can't, pass the received URL as |
| The cached token expired and refresh failed. Re-run with |
Browser never opens | Add |
Dynamic client registration fails | The server's registration endpoint is restricted (e.g. Keycloak's Trusted-Hosts policy). If it's the OutSystems proxy this shouldn't happen; otherwise register a client yourself and pass |
Something else | Open an issue with the full error text (all diagnostics go to stderr — redact any tokens) |
Non-goals (v1)
OS-keychain token storage (file with 0600 perms for now)
Multi-server aggregation / management (use a gateway for that)
Server-initiated notification streaming beyond passthrough
Custom CA flags
License
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