Skip to main content
Glama
izambasiron

outsystems-mcp-relay

by izambasiron

{"type": "text"}# outsystems-mcp-relay

軽量で汎用的な stdio → リモート MCP リレー。OAuth 対応、さらにリモートサーバーの公開 OAuth メタデータが認可応答と一致しない場合の RFC 9207 発行者オーバーライド機能を備えています。ランタイム依存関係ゼロ。単一ファイル。

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

なぜこれが存在するのか

一部のリモート MCP デプロイメントは Keycloak の前段にリバースプロキシを置いています(OutSystems Developer Cloud MCP ゲートウェイもその一つ)。それらは issuer がプロキシ URL(例: https://<tenant>/mcp)である OAuth メタデータを公開しますが、認可サーバーは認可応答の iss パラメータに実際の発行者(例: https://<tenant>/auth/realms/<realm>)をスタンプします。

RFC 9207 準拠のクライアントはその不一致を拒否しなければならないため、Claude Code、pi、Cursor、Codex など、あらゆるハーネスで OAuth ログインが失敗します。このリレーは、他のすべての OAuth チェックを厳格に保ちながら、iss を実際のバックエンド発行者に対して検証できるようにします。通常のサーバーに対しては、単なるリレーとして動作します。

Related MCP server: mcp-auth-proxy

いつこれを使うべきか

まず公式の直接接続を試してください — ハーネスをリモート MCP URL に直接向け、リレーを挟まないでください。上記の RFC 9207 発行者不一致エラーで失敗した場合にのみ、このリレーに手を伸ばしてください。

これは、そのサーバー側のバグを回避するためだけに存在します。バグが存在しない場合、公式パスより優れたことは何もありません。したがって、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 レルム設定)から実際の認可サーバー発行者を自動検出します。自動検出が失敗した場合(Keycloak 以外のサーバー)にのみ、--expected-issuer https://<tenant>.outsystems.dev/auth/realms/<realm-id> を追加してください。OAuth エラーにはレルムが表示されます — その受信値が使用する値です。自動検出は、発行者がレルム自身のメタデータ(オリジン許可リスト経由で到達可能)によって確認された場合にのみ、クロスオリジンの候補を採用します。真に別の 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(サーバーが接続されているはず)と簡単な「環境一覧」で確認してください。

レルム発行者を探す必要はありません。 リレーは認可リダイレクトから自動検出します。自動検出ができない場合(Keycloak 以外のサーバー)、エラーメッセージに表示されます。エラー内の受信値が --expected-issuer の値です。

仕組み

  • プロトコル非依存のパススルー: stdin から改行区切りの JSON-RPC を読み取り、各フレームをそのままリモートサーバーに POST し、JSON-RPC 応答を stdout に書き込みます。ツールのセマンティクスはここにはありません — ツール、リソース、プロンプト、何でも動作します。

  • Streamable HTTP の詳細を処理: Mcp-Session-Id エコー、直接 JSON 応答、202/text/event-stream 応答(SSE 再アセンブリ)。

  • OAuth: 認可サーバーのメタデータを検出し、パブリッククライアント(PKCE S256)を動的登録し、ブラウザを開き、state と iss を検証し、コードを交換し、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 と同じストア形状)。OS キーチェーンストレージは計画中の拡張です。非目標を参照してください。

テスト

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 を渡してください

その他

完全なエラーテキスト(すべての診断は stderr に出力されます — トークンは編集してください)を添えて issue を開いてください

非目標(v1)

  • OS キーチェーントークンストレージ(当面は 0600 パーミッションのファイル)

  • マルチサーバー集約/管理(その場合はゲートウェイを使用)

  • パススルーを超えたサーバー開始通知ストリーミング

  • カスタム CA フラグ

ライセンス

MIT

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Local stdio proxy for Uno MCP Gateway that enables MCP clients without OAuth support to securely connect to authenticated remote servers.
    8
    21 PyPI
    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.
    5 npm
    -
  • A
    license
    Not graded
    quality
    A
    maintenance
    Bridge 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 npm
    54
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables local MCP clients to access tools from a remote FastMCP server over stdio, handling OAuth authentication and Streamable HTTP communication.
    -