Skip to main content
Glama
izambasiron

outsystems-mcp-relay

by izambasiron

outsystems-mcp-relay

一个轻量级、通用的 stdio → 远程 MCP 中继,支持 OAuth,并带有 RFC 9207 签发者覆盖功能,用于远程服务器的已发布 OAuth 元数据与授权响应不匹配的情况。零运行时依赖。单文件。

stdio (your MCP client)  ⇄  outsystems-mcp-relay  ⇄  remote MCP server (Streamable HTTP)

为什么需要这个

某些远程 MCP 部署是 Keycloak 前面的反向代理(OutSystems Developer Cloud MCP 网关就是其中之一)。它们发布的 OAuth 元数据中 issuer 是代理 URL(例如 https://<tenant>/mcp),但授权服务器在授权响应的 iss 参数中盖的是其真实签发者(例如 https://<tenant>/auth/realms/<realm>)。

符合 RFC 9207 的客户端必须拒绝这种不匹配,因此 OAuth 登录在几乎所有工具链上都会失败——Claude Code、pi、Cursor、Codex,无一例外。这个中继让你可以针对真实后端签发者验证 iss,同时保持所有其他 OAuth 检查严格不变。对于正常服务器,它的行为就像一个普通中继。

Related MCP server: mcp-auth-proxy

何时使用

先尝试官方直连方式——将你的工具链直接指向远程 MCP URL,中间不经过中继。只有当直连因上述 RFC 9207 签发者不匹配错误而失败时,才考虑使用这个中继。

它的存在仅仅是为了绕开那一个服务端 bug。一旦该 bug 不存在,它并不会比官方路径做得更好——所以如果 OutSystems 在租户范围内修复了它,或者你的租户从一开始就没遇到这个问题,就放弃中继,直接连接。中继会告诉你何时属于这种情况:在成功登录时,它会检查是否确实需要签发者修正,如果不需要,会向 stderr 打印一条说明。不要等着做"是否还需要它"的复查——如果你看到那条说明,立即切回官方直连。

安装

需要 Node.js ≥ 20。无依赖——只有这一个文件。

npm install -g outsystems-mcp-relay      # recommended
# or, without a global install:
npx outsystems-mcp-relay <remote-url> ...

使用中继不需要克隆此仓库。 从 npm 安装(或使用 npx)即可。克隆仅用于审计源码(一个约 500 行的单文件)或贡献代码。

用法

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 help

通用示例(普通远程服务器)

// mcp.json
{
  "mcpServers": {
    "my-remote": {
      "command": "outsystems-mcp-relay",
      "args": ["https://api.example.com/mcp"]
    }
  }
}

OutSystems 示例(签发者不匹配)

{
  "mcpServers": {
    "outsystems": {
      "command": "outsystems-mcp-relay",
      "args": ["https://<tenant>.outsystems.dev/mcp"]
    }
  }
}

无需 --expected-issuer——中继会从授权重定向中自动检测真实的授权服务器签发者(Keycloak realm 场景)。只有当自动检测失败时(非 Keycloak 服务器),才添加 --expected-issuer https://<tenant>.outsystems.dev/auth/realms/<realm-id>:OAuth 错误消息会打印 realm——其收到的值就是要使用的值。自动检测只会在跨源候选者的签发者被 realm 自身的元数据(可通过源允许列表访问)确认后才采用;对于真正独立的 IdP 主机,请传入 --expected-issuer(或 --as-metadata-url 以预先加入允许列表)。

首次调用时,中继会打开浏览器进行登录(或使用 --no-open 打印 URL)。令牌会被缓存并自动刷新。

通过 AI 助手安装(粘贴此内容)

粘贴到 Claude Code、pi、Cursor 或任何 AI 工具链中:

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 快速入门(OutSystems 签发者不匹配)

你看到的错误是这样的:

Issuer mismatch in authorization response (RFC 9207):
expected "https://<tenant>.outsystems.dev/mcp",
received "https://<tenant>.outsystems.dev/auth/realms/<realm-id>"

在终端中(不是在 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/mcp

然后重启 Claude Code。在首次调用 OutSystems 工具时,中继会打开浏览器进行登录(如果更愿意粘贴 URL,可添加 --no-open)。令牌会被缓存,因此后续会话会跳过登录。用 /mcp 验证(服务器应显示已连接),并执行一个简单的"列出我的环境"。

你不需要去寻找 realm 签发者。 中继会从授权重定向中自动检测它。如果自动检测无法完成(非 Keycloak 服务器),错误消息会打印出来:错误中的收到的值就是 --expected-issuer 的值。

工作原理

  • 协议无关的透传:从 stdin 读取换行分隔的 JSON-RPC,将每个帧原样 POST 到远程服务器,将 JSON-RPC 响应写回 stdout。这里不包含任何工具语义——适用于工具、资源、提示词等一切内容。

  • 处理 Streamable HTTP 细节:Mcp-Session-Id 回显、直接 JSON 响应,以及 202/text/event-stream 响应(SSE 重组)。

  • OAuth:发现授权服务器元数据,动态注册公共客户端(PKCE S256),打开浏览器,验证 stateiss,交换授权码,在 401 时刷新令牌。--expected-issuer 设置 iss 的验证目标——这是针对代理/Keycloak 不匹配的修复方案。

  • 请求被串行化(stdout 上不会出现交错响应)。

安全性

  • 强制执行 RFC 9207:仅当授权服务器实际发送 iss 时才进行验证(缺失 = AS 未实现 RFC 9207,不检查;存在 = 与预期签发者进行严格字符串匹配)。 --expected-issuer 选择不同的预期值——它绝不会禁用验证。

  • 源允许列表:中继只联系配置的远程源(以及显式提供的 --as-metadata-url)。重定向被手动遍历,每一跳都在允许列表中(307/308 保留请求体;301/302/303 按 HTTP 语义降级为 GET),并且当重定向改变源时,Authorization/Cookie 会被剥离(与原生 fetch 一致)。无 SSRF。

  • PKCE S256 + 随机 state(已验证)+ 仅限 localhost 的回调服务器,使用临时端口。

  • 绝不记录机密:令牌和授权码永远不会出现在输出中(所有诊断信息都发送到 stderr;stdout 只承载协议消息)。

  • 令牌存储在 ~/.mcp-auth/outsystems-mcp-relay-<sha1(url)>.json,权限为 0600—— 这是生态系统的惯例(与 mcp-remote 的存储格式相同)。操作系统钥匙串存储是计划中的增强功能;参见非目标。

测试

npm test                # mock-server protocol test (passthrough, session-id, SSE, 401)
npm run test:e2e -- <remote-url> --expected-issuer <issuer>   # real-tenant round trip

故障排查

症状

修复

Issuer mismatch ... expected "…/mcp", received "…/auth/realms/…"

通常自动检测无需任何标志即可处理。如果无法处理,请将收到的 URL 作为 --expected-issuer 传入——错误消息会为你打印出来

长时间空闲后 authentication failed

缓存的令牌已过期且刷新失败。使用 --force 重新运行(或删除 ~/.mcp-auth/ 中中继的文件)以重新认证

浏览器从未打开

添加 --no-open——中继会打印授权 URL,供你粘贴到浏览器中

动态客户端注册失败

服务器的注册端点受限(例如 Keycloak 的 Trusted-Hosts 策略)。如果是 OutSystems 代理,这不应发生;否则请自行注册客户端并传入 --client-id

其他问题

提交 issue,附上完整错误文本(所有诊断信息都发送到 stderr——请对任何令牌进行脱敏)

非目标(v1)

  • 操作系统钥匙串令牌存储(目前使用 0600 权限的文件)

  • 多服务器聚合/管理(请使用网关)

  • 超出透传范围的服务器发起通知流

  • 自定义 CA 标志

许可证

MIT

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

  • A
    license
    Not graded
    quality
    D
    maintenance
    Local stdio proxy for Uno MCP Gateway that enables MCP clients without OAuth support to securely connect to authenticated remote servers.
    1
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Bridges stdio-based LLM harnesses to OAuth-protected remote MCP servers via Streamable HTTP, handling PKCE browser login and token refresh automatically.
    9
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI clients like Claude to interact with Cartena tools via MCP, supporting remote OAuth or local stdio authentication.

View all related MCP servers

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.

View all MCP Connectors

Latest Blog Posts

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