MCP Gateway
MCP Gateway — フェーズ 1(KLIP、読み取り専用)
認可されたEnergi-Upスタッフが、アプリケーションを開かずにClaudeを通じて自然言語でKLIPに問い合わせできるようにする、単一のセキュアなサービス。厳密に読み取り専用。
デプロイ先(PRD Q3、現在はクローズ済み): <gateway-hostname> -> <gateway-public-ip>
(ECS-MCP、ap-southeast-5)。ホスト名はmcp-gwであり、v0.9ドキュメントが想定していたmcp.example.comではないことに注意。PRD/TSDはこれに合わせて更新すべきである。
ドキュメント: PRD v0.9 · TSD v0.9 · 実装ガイド · 設計レビュー · デプロイランブック
1. 固定バージョン(T-1)
MCP仕様リビジョンとSDKバージョンはここで固定する。SDK自身のドキュメントが設計ドキュメントと矛盾する場合、SDKが優先される — SDKが正確なAPIを定義するからである。
コンポーネント | 固定バージョン | 備考 |
| 1.30.0(完全一致、キャレットなし) | 2026年7月27日公開。OAuth AS、Streamable HTTPトランスポート、 |
MCPプロトコルリビジョン | 2025-11-25を実装。ワイヤー形状は | リビジョン |
Node.js | 22 LTS( | |
TypeScript | 5.9.3、 | |
express | 5.2.1 | TSDの4.xから引き上げ: SDKは |
zod | 4.4.3 | TSDの3.xから引き上げ: SDKの型定義はzod 4を対象としている。 |
jose | 6.2.9 | RS256ゲートウェイトークン。 |
| 2.1.0 |
|
axios | 1.19.0 | KLIPクライアント。メソッドガードの背後にある。 |
pg | 8.23.0 | |
PostgreSQL | 16(コンテナ) | |
nginx | nginx.org mainline | 設定は |
Related MCP server: Snowflake MCP Server
2. レイアウト
src/
core/ config, logger, db, audit, cache, rateLimit, semaphore, migrate, errors
adapters/klip/ routes(APPENDIX A) · fields(APPENDIX A) · client(guard) · session · paginate · normalize
tools/klip/ 9 tool definitions + shared parameter plumbing
mcp/ server, envelope, runner
auth/ keys, hub(OIDC RP), users, clients, tokens, provider, loginPage
http/ app, consent(Hub + break-glass), health, origin, clientIp
migrations/ idempotent SQL (001 schema, 002 Hub OIDC)
deploy/ nginx config, backup sidecar
test/ 120 tests + mock KLIP and mock Hub fixturesレイヤリングルール(T-3): tools → adapters → core。エントリポイント以外でhttp/をインポートするものはない。すべてのビジネス正規化はadapters/klip/normalize.tsにあり、これは何もインポートしないため、単体でユニットテスト可能である。
3. 認証 — 下流Hub OIDC
パイロットユーザーはDownstream Hub(OIDC)でサインインする。ゲートウェイはClaudeが通信する認可サーバーのままであり、Hubはその独自の/authorizeフロー内の1ステップである。
SDKのProxyOAuthServerProviderは意図的に使用しない。プロキシすると、ClaudeにHubトークンが渡され、RFC 8707のオーディエンスバインディングが壊れ、Claudeにklip:readより広いHubスコープが付与され、トークン発行が当社の管理外に移るため、S8キルスイッチがライブセッションを無効化できなくなる。
Claude ──/authorize──▶ gateway ──302──▶ Downstream Hub ──302──▶ /authorize/hub/callback
│ │
│ validate id_token (sig/iss/aud/nonce) │
│ check the pilot ALLOWLIST │
◀──────────────────────────────────────────────┘
└──302 code──▶ Claude ──/token──▶ gateway token (klip:read)認証は認可ではない。 Hubは誰であるかを証明し、usersテーブルがコネクタを使用できるかどうかを決定する。フェーズ1では共有のKLIPサービスアカウントを1つ使用するため、承認されたすべてのユーザーはMCP_READONLYが読み取れるすべてを読み取れる(レビューH8)— パイロットメンバーシップがデータアクセス制御である。リストにないHubアカウントは403を受け取り、<= 15の上限はuser:addによって強制される。
フローでは2つのPKCE交換が実行される。混同しないこと。Claude自身のcode_challengeはClaude→ゲートウェイ区間を保護し(SDKが処理)、ゲートウェイがサーバー側で保持する別のベリファイアがゲートウェイ→Hub区間を保護する。
どのHubクライアントか? ゲートウェイ自身のもの — KLIPのものではない
MCP Gateway用に新しいOIDCクライアントを登録すること。KLIPのHub登録を再利用しないこと。KLIPがテスト用DWS Hubにすでに登録されている場合でも同様である。
Hubは2つの信頼境界のうち1つにのみ関与する:
境界 | 資格情報 | Hub関与? |
Claude → ゲートウェイ(どの人間が質問しているか) | ゲートウェイ自身のHubクライアント + パイロット許可リスト | あり |
ゲートウェイ → KLIP(データの読み取り) | KLIPの | なし — PRD §7が明示的に除外している |
KLIPのクライアントを再利用すると、最初の境界が具体的な形で壊れる。ゲートウェイはIDトークンのaudを自身のHUB_CLIENT_IDに対して検証する。KLIPのクライアントIDを共有すると、KLIPログイン中に発行されたIDトークンがゲートウェイに受け入れられることになり、これは混乱した代理人(confused deputy)の形である。クライアントを分離することで、2つの証明書利用者(relying party)が区別可能になる。また、リダイレクトURI許可リスト、クライアントシークレット、ローテーションスケジュール、Hub SSO監査エントリ、無効化スイッチも独立して維持される — コネクタのHubクライアントをオフにしてもKLIPログインを停止させてはならない。
これにはKLIP側の変更は一切不要である。K1〜K4は影響を受けない。
2つのHubインスタンス、2つの登録
ゲートウェイを各Hubに個別に登録し、対応するKLIPとペアリングする:
ステージ | KLIP_ENV | HUB_ISSUER | クライアント |
4〜6(ビルド、ステージングUAT) |
| テスト用DWS Hub | テスト用Hubのゲートウェイクライアント |
7以降(本番カットオーバー) |
| 本番Hub | 本番Hubの別のゲートウェイクライアント |
ペアリングは起動時に強制される。間違った方向で設定すると、単なる不手際ではなく危険だからである:
KLIP_ENV=production+ テスト用HUB_ISSUER→ ゲートウェイは起動を拒否する。 テストHubアカウントを作成できる者は誰でも、実際の商用データに到達できてしまう。KLIP_ENV=staging+ 本番HUB_ISSUER→ 警告して続行する。
hub:checkは検出したペアリングを出力するため、カットオーバーは検証可能である:
pairing: KLIP staging <-> Hub testingDWS Hubが要求するもの(バニラOIDCではない)
Docs/SSO-TARGET-APP-INTEGRATION.mdによる。これらのうち4つはOIDCクライアントライブラリが想定するデフォルトと異なり、3つは完全に失敗する:
DWS Hub | |
クライアントタイプ | パブリック、PKCE S256 — |
ディスカバリ |
|
トークンボディ | JSON。フォームエンコードは |
スコープ |
|
| トークンリクエストで必須であり、バイト単位で完全一致である |
したがって、HUB_DISCOVERY_URLは明示的に設定され、HUB_CLIENT_SECRETはオプションであり、HUB_TOKEN_BODYはデフォルトでjsonとなり、unsupported_grant_typeの場合にフォームへのワンショットフォールバックがある(どちらが機能したかをログに記録し、固定できるようにする)。
セットアップ手順
リダイレクトURI
<PUBLIC_URL>/authorize/hub/callbackでゲートウェイをHubのOIDCクライアントとして登録する。これはパブリッククライアントである — シークレットを要求しないこと。HUB_ISSUER、HUB_DISCOVERY_URL、HUB_CLIENT_IDを/opt/mcp/.envに配置する。パイロットユーザーが試す前に検証する:
docker compose exec -T gateway node dist/cli.js hub:checkこれにより、登録するリダイレクトURIが出力され、ディスカバリが実行され、HubがS256 PKCEを宣伝していない場合に警告する。ゲートウェイは起動時にもディスカバリをプローブし、
/healthzでhub_oidcとして報告する。パイロットユーザーを追加する(パスワードなし — Hubが認証する):
docker compose exec -T gateway node dist/cli.js user:add someone@example.com "Their Name"
非常用(ブレークグラス)アカウント
Hubがダウンしているか誤設定されている場合に使用するため、ローカルパスワードアカウントは正確に1つだけ許可される:
docker compose exec -T gateway node dist/cli.js user:add-break-glass it-emergency@example.comこれはログインページの開示の背後に隠されており、初回使用時にパスワード変更を強制し、それを通じたすべてのサインインは高重大度でbreak_glass: trueとして監査される。Hub認証ユーザーはパスワードパスをまったく使用できないため、Hubをオフにしても、誰も設定していないパスワードにフォールバックする方法にはならない。
Hub パスが本番で実証されたら、BREAK_GLASS_ENABLED=false に設定して、パスワードの攻撃面を完全に削除してください。
オプションのグループゲート — DWS Hub では利用不可
HUB_REQUIRED_GROUP は、groups クレームに対する2番目のチェックを追加します。DWS Hub は groups クレームを発行しません(openid profile email のみをアドバタイズします)。そのため、これを設定するとすべてのユーザーを拒否することになります。設定した場合、hub:check が警告します。users テーブルのパイロット許可リストが、引き続き認可の制御となります。
IdP 開始ログイン
Hub はダッシュボードのタイルからユーザーをコールバックに直接送り込むことができます。これはコネクタでは機能しません。コールバックは Claude が開始した認可リクエストを完了させるために存在するため、リクエストなしでコールバックに到達しても、コードを発行する対象が何もありません。ゲートウェイはこれを検出し、「サインイン期限切れ」として失敗する代わりに「Claude から開始してください」と表示します。
4. クイックスタート(ローカル)
npm ci
docker run -d --name mcpgw-devdb -e POSTGRES_DB=gateway -e POSTGRES_USER=gateway \
-e POSTGRES_PASSWORD=devpassword -p 127.0.0.1:55432:5432 postgres:16-alpine
cp .env.example .env.dev # then edit: PUBLIC_URL=http://localhost:8787, DATABASE_URL=...55432...
npx tsx test/fixtures/mockKlip.ts 5099 & # mock KLIP, behaves like the real one
set -a; . ./.env.dev; set +a
npm run migrate
npx tsx src/index.tsパイロットユーザーを作成します(TTY またはパイプ入力を使用可能):
printf 'a-strong-password\na-strong-password\n' | npx tsx src/cli.ts user:add you@example.com "Your Name"5. テスト
npm testスイート | 内容 |
| インコターム × ステータス × null のマトリクス、kg→MT、丸め順序、マイナスの未達、WIB タイムスタンプ |
| T-6 の網羅的なメソッド/パステーブル、トラバーサルとオリジンエスケープ |
| T-5 エンベロープ、 |
| 境界付きフェッチは |
| モック KLIP に対する全9ツール、非 GET が KLIP に到達することは決してありません、401 再ログイン、 |
| RFC 8707 オーディエンスバインディング:このサーバーの正規リソースのみが受け入れられます |
| S5 リダクション — 文字列には積極的、数値には作用しません |
| モックプロバイダーに対する Hub OIDC:ディスカバリーの発行者不一致、外部署名キー、誤った issuer/audience、期限切れトークン、nonce の欠落とリプレイ、email クレームなし |
|
|
| テスト用 Hub の背後にある本番 KLIP は起動を拒否します。通常のペアリングは起動を拒否しません |
| ディスカバリーから選択されるトークンエンドポイントの認証方式(post-only およびパブリッククライアントの Hub を含む) |
| DWS Hub を正確にモデル化: |
モック Hub は、実際のディスカバリードキュメント、実際の JWKS、実際の RS256 ID トークン、認可コードに対する PKCE 検証を備えた動作するミニ OIDC プロバイダーであり、不正なトークンを偽造するために必要なあらゆる設定項目を備えています。ネガティブケースこそが重要なのです。
モック KLIP フィクスチャは、実システムの癖を意図的に再現しています:MT とラベル付けされたキログラム、複数言語のステータス、標準の4つ以外のインコターム、null 数量、過剰納品された契約、暗黙に 100 にクランプされる limit、そしてプロンプトインジェクションペイロードを含む契約備考です。
6. デプロイ
実際の IP、ホスト名、セキュリティグループの表を含む、ホスト固有の完全な手順:deploy/RUNBOOK.md。
# on ECS-MCP
cd /opt/mcp && git pull
docker compose build gateway && docker compose up -d
curl -fsS http://127.0.0.1:8787/healthz管理 CLI — これはコンテナ内で実行されることに注意してください。ホストには Docker のみがインストールされ、Node.js はありません:
docker compose exec -T gateway node dist/cli.js user:list
docker compose exec -T gateway node dist/cli.js audit:summary --days 7
docker compose exec -T gateway node dist/cli.js audit:export --from 2026-08-01 --to 2026-09-01 --out /tmp/audit.csv
docker compose exec -T gateway node dist/cli.js routes:verify # probes KLIP, reports Appendix A gapsキルスイッチ(S8) — 目標は5分未満:
docker compose exec -T gateway node dist/cli.js tokens:revoke-all --reason "incident 2026-xx"
docker compose stop gatewayアプリコンテナが異常な場合のブレークグラス:
docker compose exec -T db psql -U gateway -d gateway -c "UPDATE oauth_tokens SET revoked_at=now() WHERE revoked_at IS NULL;"7. 付録Aはハードゲートです
src/adapters/klip/routes.ts と src/adapters/klip/fields.ts には、アダプターが依存するすべての KLIP パス、クエリパラメータ名、ページサイズ上限、レスポンスフィールド名、enum 値が保持されています。現在、すべてのエントリは未検証です。
このゲートは事務的なものではなく、実行時に強制されます。KLIP_ENV=production の場合、いずれかのルートが未検証の間、プロセスは起動を拒否します。ステージングに対して routes:verify を実行し、結果を記録し、ルートごとに verified: true を設定し、enums.verified = true を設定します。
他のどのフィールドよりも重要な2つのフィールド:
maxLimit— KLIP が実際に受け入れる最大のlimit。暗黙に 100 にクランプされる場合、KLIP_PAGE_SIZEが 1000 だと1ページが10ページになり、レイテンシ目標を破ります。enums.*— 正規のステータス値とインコターム値。マッピングされていないものは、デフォルト値にされることはなく、データ品質メモ付きで合計から除外されます。
8. TSD v0.9 からの逸脱
それぞれは設計レビューに由来し、その呼び出し箇所でコメントされています。
# | 変更内容 | 理由 |
B3 | Origin は存在するが無効な場合のみ拒否 | 仕様では、存在するが無効な Origin に対してのみ 403 が要求される。Claude はコネクタをサーバー間で呼び出し、Origin を送信しない場合がある。存在しない場合を拒否すると、すべてのツール呼び出しが 403 になる。 |
B4 |
| RFC 8707 のオーディエンスバインディング。PRM ドキュメントに |
B5 | ステートレスなトランスポート。ID はリクエストごとにトークンから取得 | リビジョン 2026-07-28 でプロトコルセッションが削除された。T-4 は構造上満たされる。乗っ取るセッションが存在しないため。 |
B6 | キルスイッチは | ホストに Node.js がないため、 |
B7 | nginx が不正利用対策の最低限の防御。OAuth の | すべてのトラフィックは Anthropic の共有 egress レンジから到着するため、IP をキーにした制限ではパイロット全体が 1 つのバケットに入ってしまう。 |
H1 | SDK の | SDK には AS(認可サーバー)が同梱されており、失効とデフォルトのレート制限も含まれる。ストレージとユーザー認証のみが当社の実装である。 |
H2 | 下流の Hub OIDC がログインパスであり、緊急用のローカルアカウントが 1 つある | Phase 2 から前倒しされた。Hub が認証を行い、users テーブルはパイロットの許可リストのままである。 |
H3 | Anthropic の | Anthropic は安定した egress レンジを公開し、許可リスト化を推奨している。 |
H4 | 切り詰められた結果は | 自信を持って誤った数値に至る 4 つの異なる経路。 |
H5 | 短い TTL のキャッシュ。2..N ページ目は並行して取得。ページサイズは | 10 回のシーケンシャルなラウンドトリップでは P95 ≤ 5 秒を満たせない。 |
H6 | 9 番目のツール | これがないと、誤入力されたプラント名が空のセットを返し、「outstanding は何もない」と読めてしまう。 |
H7 |
| 指定されたハードコードの「KLIP production」文字列では、ステージングの UAT のすべての応答が本番であると主張することになっただろう。 |
H9 |
| パーティション削除による保持管理は、追記専用トリガーが許可する唯一の方法である。U5 のエクスポートには実装がなかった。クライアント IP はすべて 127.0.0.1 として記録されていただろう。 |
H10 | バックアップサイドカー、コンテナのヘルスチェック、 | TSD では指定されていたがガイドでは実装されておらず、本番稼働時には存在しなかっただろう。 |
— | 未知のツールパラメータは | PRD 8.1 は拒否を要求している。通常の |
— | ツールは | 散文に埋め込まれた JSON ではなく型付きデータ。転記エラーが減り、それが M1 が測定するものである。 |
9. 未解決事項
付録 A の整合性確認(P1)— 本番稼働をブロックし、起動時に強制される。
KLIP 側の K1–K4 —
MCP_READONLYロール、svc-mcpアカウント、セキュリティグループルール。ホスト外へのバックアップ同期とテスト済みのリストア — サイドカーはローカルのみに書き込む。
deploy/nginx/mcp.confの実際の企業 egress CIDR。その後、コメントアウトされた 2 つのreturn 403行を有効にする。30 同時ユーザーのキャパシティ NFR での負荷テスト。
Hub クライアント登録 — ゲートウェイ自身のものを、まずテスト用 DWS Hub に登録:
HUB_ISSUER、クライアント ID とシークレット、リダイレクト URI<PUBLIC_URL>/authorize/hub/callbackを Hub 側に登録する。Hub の email と groups クレーム名を確認してからhub:checkを実行する。Stage 7 では、本番 Hub への 2 つ目の個別登録が必要である。HUB_REQUIRED_GROUPを設定するかどうか、および Hub パスが本番で実証された後にBREAK_GLASS_ENABLED=falseにするかどうかを決定する。
This server cannot be deployed
Maintenance
Related MCP Connectors
Query your org's data in natural language — read-only MCP access to SQL, NoSQL, files & warehouses.
Query your warehouse or a CSV with Claude/ChatGPT over MCP, governed by table-level ACL + audit.
Query 40 databases from Claude, ChatGPT, or Cursor — on any device. Read-only, encrypted, audited.
Give Claude only the Google Drive files you choose. Every action logged.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables read-only querying of the gong-nl-db Postgres database through natural language via Claude Desktop.9Academic Free v1.1
- AlicenseNot gradedqualityDmaintenanceEnables natural language queries against Snowflake Gold-layer tables through Claude Desktop, allowing users to ask business questions in plain English without SQL knowledge.MIT
- FlicenseNot gradedqualityCmaintenanceEnables natural language interaction with Kintone data via Claude, allowing listing apps, field definitions, querying and modifying records.-
- FlicenseAqualityCmaintenanceEnables querying AgroClimate company data via natural language through ChatGPT or Claude.7-