
MCP Gatewayとは何か?業務システムのデータをAIに聞く入口としてOSSのContextForgeを触ってみた
AIエージェントから社内の業務システムのデータを参照させたい、という相談が増えてきました。たとえばSalesforceのような顧客管理、ファイル共有、会計、経費精算……と、参照したいデータはあちこちの業務システムに散らばっています。
「それぞれのシステムにAIエージェントを直接つなげばいいのでは?」と考えたくなりますが、対象が増えてくると、だんだん困ることが出てきます。今回は、その困りごとを整理したうえで、解決策として登場した MCP Gateway という概念を紹介し、OSS実装の ContextForge を実際に触ってみます。
MCP Gatewayは、複数のベンダーやOSSがすでに同じような定義で製品を出しているカテゴリで、AIエージェントとMCPサーバー群の間に立って、認証やアクセス制御といった横断的な制御を一手に引き受ける層です。なお本記事は、MCP(Model Context Protocol、AIエージェントと外部ツールをつなぐ標準プロトコル)を触ったことはあるが、それを束ねるGatewayは調べたことがない、という方を想定しています。
MCPそのものについては、弊社ブログでも解説しているのでこちらをご参照ください。
直結すると何が困るのか
まず、AIエージェントを各業務システムに直接つなぐ構成を考えてみます。
一見シンプルですが、システムが増えるにつれて次のような課題が積み上がっていきます。
- 設定が煩雑になる:クライアントやエージェントごとに、接続先を1つずつ登録・管理しなければならない
- 認証がバラバラ:システムごとに認証方式やトークン管理が異なり、それぞれに対応する必要がある
- 監査ログが取れない:誰が・どのシステムのデータに・どれだけアクセスしたのかを、横断的に記録する場所がない
- コストが読めない:API利用が従量課金の場合、エージェントが呼びたい放題になり、コストが青天井になりかねない
- アクセス制御が粗い:「このエージェントはこのデータだけ」といった細かい制御が難しく、全部許可か全部拒否になりがち
さらにやっかいなのが、MCPでAIエージェントとつなぐには、多くの場合 既存のWebAPIをMCPとして喋らせる変換レイヤー(MCPラッパー)がシステムごとに必要になることです。これらを個別に作って運用すると、ラッパーが乱立し、上記の課題がシステムの数だけ分散していきます。
これらを1つずつ解決していくのは、かなり骨が折れます。
これらを解決する「MCP Gateway」
そこで最近登場してきたのが、MCP Gateway という概念です。
MCP Gatewayは、AIエージェントと業務システム群の間に立つ 単一の統制された入口 です。すべてのツール呼び出しがこの「関所」を必ず通るようにすることで、認証・監査・制御を一箇所に集約できます。
先ほど挙げた困りごとと、MCP Gatewayが提供する機能は、きれいに対応します。
| 直結の困りごと | MCP Gatewayでの解決 |
|---|---|
| 設定が煩雑 | 複数のシステムを1つのエンドポイントに集約・ルーティング |
| 認証がバラバラ | 認証・認可を入口で一元化 |
| 監査ログが取れない | すべての呼び出しを一箇所で記録(監査ログ・可観測性) |
| コストが読めない | レート制限・クォータで呼び出し上限を強制、キャッシュで重複呼び出しを削減 |
| アクセス制御が粗い | ツール単位のアクセス制御 |
なお、既存WebAPIをMCPとして見せる部分だけなら、MCPサーバーを自分で書いても実現できます。MCP Gatewayを挟む価値は、その変換を1箇所に集めたうえで、認証・監査・制御をまとめて効かせられる点にあります。
どう実現するか:SaaS / OSS / 自作
MCP Gatewayを実現する手段は、大きく3通りあります。
- SaaS(マネージド):運用をベンダーに任せる。認証・統制・スケールの作り込みが不要で、素早く始められる。たとえばAmazon Bedrock AgentCore Gatewayは、既存のREST API(OpenAPI仕様)やLambda関数をMCP互換ツールに変換して単一エンドポイントから公開でき、クライアント側・ツール側双方の認証も引き受けるフルマネージドサービスです
- OSS(セルフホスト):自前でホストする。カスタマイズは自由だが、運用は自己責任。今回取り上げるContextForgeがこれにあたります
- 自作:すべて自分で作る。要件が特殊なとき以外は選びにくい
この3択は、突き詰めると 「どこまで自分で作り込むか」 のトレードオフです。SaaSは作り込み最小、OSSは運用は自前、自作は全部自作、という並びになります。
統制層をフルスクラッチで作るのは、可用性やMCP仕様の追従まで自分で背負うことになり、かなり重い選択です。現実的にはSaaSかOSSに寄せるのが妥当でしょう。
今回は、自前でホストしつつ、既存WebAPIのMCP変換やプラグインによる拡張もできるOSSとして、ContextForge を取り上げます。
ContextForgeとは
ContextForge(IBM/mcp-context-forge)は、IBMが公開しているOSSのAI Gateway / レジストリ / プロキシです。MCPサーバーだけでなく、A2A(Agent2Agent、AIエージェント同士を連携させるプロトコル)のサーバーやREST/gRPC APIも配下にまとめ、統一されたエンドポイントとして公開できます。
今回の「社内システムの入口」という用途に効いてくるのは、次のような機能です。
- 既存WebAPIのMCP化:REST APIをMCPツールとして登録できる。ツールのパラメータをHTTPヘッダーへ渡すマッピングや、タイムアウト(
timeout_ms、既定20000ミリ秒)をツールごとに設定できる(REST Passthrough) - レート制限:ツール呼び出しの上限を
TOOL_RATE_LIMIT(既定100回/分)で設定できる。ツール単位・クライアント単位でカウントされる(Configuration) - キャッシュ:
Cached Tool Resultプラグインで、冪等なツールの結果をTTL付きでキャッシュできる(cached_tool_result) - プラグイン機構:CPEX(ContextForge Plugin Extensions)というプラグインフレームワークで拡張できる。PIIマスキング、コンテンツモデレーション、サーキットブレーカー、リトライなどが標準で用意されている(Plugins)
- 監査・可観測性:OpenTelemetry(OTLP)でトレースを外部バックエンドに送れる(
OTEL_ENABLE_OBSERVABILITY、既定は無効。Configuration)。認証・認可イベントはSECURITY_LOGGING_ENABLEDでsecurity_eventsテーブルに記録できる(Security Features)
触ってみる:ContextForgeで既存WebAPIをMCP化する
ここからは、実際にContextForgeを立てて、既存のWebAPIをMCPツールとして登録し、MCP Gateway経由で呼び出すところまでを試します。
今回は「社内にある既存のREST API」の代わりに、認証不要で使えるダミーAPI提供サービスの SampleAPIs を題材にします。GET https://api.sampleapis.com/coffee/hot を、社内の業務APIに見立てて進めます。
作っていく構成はこうです。
なお今回は「本番運用をどう組むか」ではなく「このOSSが要件を満たせるか手触りを確かめる」段階なので、コンテナ1個(SQLite)の最小構成 で通します。公式の docker-compose.yml は本番運用を見据えた構成で、リソース要件も設定量も大きく、機能の確認には過剰でした。何を削って最小構成にしたかは、記事の最後に補足としてまとめています。
ContextForgeを起動する
コンテナ1個で起動できますが、その前に押さえておきたい点が2つあります。
注意1:シークレットは強い値にする
v1.0.8は JWT_SECRET_KEY と AUTH_ENCRYPTION_SECRET を起動時に検証し、条件を満たさないとプロセスが起動しません(開発・本番の区別なく)。条件は「32文字以上」「一定以上のエントロピー」「既知の弱い値でない」です。そのため、下のコマンドでは openssl rand -base64 48 で強い値を生成しています。
注意2:Admin UIは明示的に有効化する
MCPGATEWAY_UI_ENABLED と MCPGATEWAY_ADMIN_API_ENABLED は既定で false です。docker run で試すときは、/admin を開くために両方を true にしておきます。
以上を踏まえると、起動コマンドは次のようになります。
$ docker run -d --name mcpgateway-minimal \
-p 4444:4444 -v "$(pwd)/data-minimal:/data" \
-e HOST=0.0.0.0 \
-e DATABASE_URL="sqlite:////data/mcp.db" \
-e JWT_SECRET_KEY="$(openssl rand -base64 48)" \
-e AUTH_ENCRYPTION_SECRET="$(openssl rand -base64 48)" \
-e PLATFORM_ADMIN_EMAIL=admin@example.com \
-e PLATFORM_ADMIN_PASSWORD=changeme \
-e MCPGATEWAY_UI_ENABLED=true \
-e MCPGATEWAY_ADMIN_API_ENABLED=true \
-e GUNICORN_WORKERS=2 \
-e EXPOSE_ERROR_DETAILS=true \
ghcr.io/ibm/mcp-context-forge:v1.0.8
起動できたら、ヘルスチェックで確認します(/health は認証不要)。最小構成のベースURLは http://localhost:4444 です。
$ export BASE_URL="http://localhost:4444"
$ curl -s ${BASE_URL}/health
実行結果
{
"status": "healthy",
"mcp_runtime": {
"mode": "python",
"mounted": "python",
"boot_mode": "off",
"boot_mounted": "python",
"effective_mode": "off",
"override_active": false,
"override_version": 0,
"cluster_propagation": "disabled",
"boot_reconcile_status": "ok",
"pod_id": "86a9db64527a",
"rust_build_included": false,
"rust_runtime_enabled": false,
"session_core_mode": "python",
"event_store_mode": "python",
"resume_core_mode": "python",
"live_stream_core_mode": "python",
"affinity_core_mode": "python",
"session_auth_reuse_mode": "python",
"rust_session_core_enabled": false,
"rust_event_store_enabled": false,
"rust_resume_core_enabled": false,
"rust_live_stream_core_enabled": false,
"rust_affinity_core_enabled": false,
"rust_session_auth_reuse_enabled": false
}
}
Admin UIにログインしてみる
環境ができたので、まずはAdmin UIを開いてみます。ブラウザで http://localhost:4444/admin にアクセスすると、ログイン画面が表示されます。

ここに、起動時に指定した PLATFORM_ADMIN_EMAIL と PLATFORM_ADMIN_PASSWORD の値(admin@example.com / changeme)を入力します。すると初回ログインではそのまま管理画面には入れず、パスワードの変更を求める画面に切り替わります。初期パスワードのまま使い続けられない作りになっているので、ここで新しいパスワードを設定します。
変更が終わると、System Overviewの画面が開きます。

稼働中のバージョン、MCPランタイムの状態、実行回数や成功率といったメトリクスが並びます。左のサイドバーが、これから触っていく登録対象(MCP Servers、Virtual Servers、Tools、Prompts……)の一覧です。今の時点では登録済みのツールも仮想サーバーもすべて0件で、ここに業務APIを1本追加していくことになります。
認証の考え方を押さえる
ツール登録やクライアント接続の前に、ContextForgeの認証がどこにかかるのかを整理しておきます。認証は2つの層に分かれています。
- ① クライアント → MCP Gateway:MCP Gatewayに繋ぐには JWT(Bearerトークン) が必要です。すべてのAPIルートで認証を要求する
AUTH_REQUIREDは既定でtrueのため(Configuration)、起動コマンドで何も指定していない今回の構成でも、認証なしではツールを呼べません。 - ② MCP Gateway → 業務API:各業務APIごとの認証です。今回題材にするSampleAPIsはたまたま認証不要ですが、実運用ではAPIキーやOAuthをMCP Gateway側に持たせて付与します。
「認証を一箇所に集約する」というMCP Gatewayの利点は、この①でクライアントの認証を一元的に受け止め、②で各APIの認証情報をMCP Gatewayが代わりに管理する、という構造から来ています。
以下では、まず①のためのJWTトークンをAdmin UIから発行します。
JWTトークンを発行する
JWTトークンは、Admin UIのトークン管理画面から発行できます。画面から発行したトークンはDBに登録され、あとから一覧・失効ができます。
先ほどログインしたAdmin UIで、サイドバーの「ORGANIZATION」にある「API Tokens」を開きます。

名前と有効期限を指定して「Create Token」を押すと発行できます。

有効期限は任意ではなく必須で、フォームにも「サーバーポリシー(REQUIRE_TOKEN_EXPIRATION=true)により有効期限が必要」と書かれています。期限なしのトークンを作れない作りです。
「Token Scoping」では、このトークンで許す範囲を絞れます。今回は Permissions に tools.read, tools.execute を指定して、ツールの参照と実行だけを許すトークンにしました。ほかに特定の仮想サーバーへの限定(Server ID)や、発信元IPの制限(IP Restrictions)も指定できます。
発行すると、トークン文字列が表示されます。この画面は一度しか表示されないので、ここで控えます。

発行したトークンは一覧に並びます。作成日・有効期限・最終利用日時とスコープが確認でき、「Revoke」で失効、「Usage Stats」で利用状況も見られます。

控えたトークンを環境変数に入れておきます。あとでクライアントから繋ぐときに、認証ヘッダー(Authorization: Bearer <TOKEN>)として使います。
$ export TOKEN="<<YOUR_TOKEN>>"
既存WebAPIをMCPツールとして登録する
いよいよ本題です。SampleAPIsのエンドポイントを、ContextForgeにRESTツールとして登録します。サイドバーの「MCP」にある「Tools」を開くと、一覧の下に「Add New Tool from REST API」というフォームがあります。既存WebAPIをMCP化するための入り口です。

入力したのは次の3つだけです。
- Name:
sample-coffee-hot - URL:
https://api.sampleapis.com/coffee/hot - Description: ツールの説明。LLMがツールを選ぶときに読む文章なので、何ができるツールなのかを書きます
Integration Typeは REST、Request Typeは GET が既定なのでそのままです。url を入れれば、内部で使う base_url と path_template は自動で抽出されます。Headers、Input Schema、Output Schema、Json Path Filterは空のままでも登録できます。認証が必要なAPIなら「Authentication Type」で Basic / Bearer Token / Custom Headers を選び、ここに資格情報を持たせます(今回のSampleAPIsは認証なしなので None のままです)。
フォームの下端でタグと公開範囲を指定して「Add Tool」を押します。Visibilityは Public / Team / Private の3択で、既定はPublicです。

登録されると、ツール一覧に並びます。

Tool IDが振られ、Sourceに登録元のURL、Statusに REST Public Online が並びます。ここに出ている Name(sample-coffee-hot)が、MCPクライアントからツールを呼ぶときの名前になります。
動作確認も画面からできます。一覧の「Actions」から「Test」を選び、「Run Tool」を押すと、MCP Gateway経由でAPIを呼んだ結果がJSON-RPCのレスポンスとして返ってきます。

isError: false で、SampleAPIsのコーヒー一覧(Black Coffee など)が result.content のテキストとして入っています。ただのREST APIだった api.sampleapis.com/coffee/hot が、ContextForge経由でMCPツールとして扱えるようになりました。
仮想サーバーにまとめる
登録したツールは、仮想サーバー(virtual server) としてまとめると、1つのMCPエンドポイントとしてクライアントに公開できます。サイドバーの「Virtual Servers」を開き、一覧の下にある「Add New Server」フォームを使います。
名前と説明を入れて、「Associated Tools」から公開したいツールにチェックを入れます。ここに先ほど登録した sample-coffee-hot が並んでいます。Resources、Promptsも同じように束ねられますが、今回はツールだけです。

Server IDは空にしておくと自動生成されます(既存のIDを引き継ぎたい場合だけ「Custom UUID」に指定します)。「Enable OAuth 2.0 for MCP Client Authentication」を有効にすると、MCPクライアントがブラウザ経由のOAuth/SSOで認証できるようになります。今回はJWTトークンで繋ぐのでオフのままです。
「Add Server」を押すと、一覧に仮想サーバーが追加されます。

「1 tool」と表示され、この仮想サーバーが1本のツールを持っていることが分かります。「Actions」から「View」を開くと、接続に必要な情報が確認できます。

Server IDと、それを含むURLが表示されます。クライアントから繋ぐMCPエンドポイントは、このURLの末尾に /mcp を付けた形です。
http://localhost:4444/servers/<<YOUR_SERVER_UUID>>/mcp
この <<YOUR_SERVER_UUID>> と、先ほどのJWTトークンが、クライアントから繋ぐときの接続情報になります。
Claude Desktopから繋ぐ
作成した仮想サーバーに、実際のAIクライアントとして Claude Desktop から繋いでみます。
ここで一度立ち止まりたいのが「どこから接続しにいくか」です。Claude DesktopにはリモートのMCPサーバーをURLで登録するコネクタ機能がありますが、この接続はAnthropicのクラウド側から発信されるため、localhostで動かしている今回のMCP Gatewayには届きません。社内ネットワークの内側にMCP Gatewayを置く構成でも同じで、インターネットから到達できない場所に立てるならこの経路は使えません。
そこで今回は、設定ファイルに記述する方法を使います。Claude Desktopの設定ファイルに書けるのはstdio形式だけなので、stdioで受けてHTTPに橋渡しする mcp-remote を挟みます。
まず、先ほど TOKEN 環境変数に入れておいたトークンを、ヘッダーファイルに書き出します。
$ echo "Authorization: Bearer ${TOKEN}" > ~/.contextforge-headers.txt
$ chmod 600 ~/.contextforge-headers.txt
次に、設定ファイル claude_desktop_config.json(macOSなら ~/Library/Application Support/Claude/claude_desktop_config.json)に次を追記します。<<YOUR_SERVER_UUID>> は仮想サーバーのIDに、<<YOUR_USERNAME>> はご自身のユーザー名に置き換えてください。
{
"mcpServers": {
"contextforge": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"http://localhost:4444/servers/<<YOUR_SERVER_UUID>>/mcp",
"--allow-http",
"--transport", "http-only",
"--header-file", "/Users/<<YOUR_USERNAME>>/.contextforge-headers.txt"
]
}
}
}
mcp-remote のフラグや認証ヘッダーの渡し方の詳細は、公式のREADMEを参照してください。
Claude Desktopを再起動すると、登録した業務APIのツールがClaudeから使えるようになります。

AIクライアント側から見ると、接続先はContextForgeの1エンドポイントだけです。その裏で複数の業務システムを束ねられ、しかもMCP Gatewayへの接続はJWTで認証されます。これが「統制された入口」の具体的な姿です。
Metrics画面で「何がどれだけ呼ばれたか」を見る
MCP Gatewayを通すもう1つの利点が、呼び出しの記録が1箇所に集まる ことです。直結だと各APIのログを個別に見に行くしかありませんが、ContextForgeはサイドバーの「MONITORING」にある「Metrics」で、MCP Gatewayを通った呼び出しをまとめて見られます。
先ほどのツールを何回か実行した状態で開いてみます。

上段のカードがエンティティ数(ユーザー、チーム、MCPリソース、収集済みメトリクス)、その下が総実行回数・成功率・平均レスポンスタイム・エラー率という実行系の指標です。
さらに「Top Performers」で、よく使われているツール・リソース・プロンプト・仮想サーバーがランキングで並びます。ツールごとに実行回数・平均レスポンスタイム・成功率・最終利用日時が出るので、「どのAPIが使われていて、どれが遅いのか」がここだけで分かります。その下にはTools / Resources / Prompts / Serversそれぞれの内訳(成功・失敗回数、失敗率、平均レスポンスタイム、最終実行時刻)が並びます。
画面上部のタブを切り替えると、別の切り口も見られます。「Activity」タブでは、APIトークンの状態やセッション数、収集されているメトリクスの件数が確認できます。

発行済みトークンのActive / Revoked / Total、MCPセッション数、そして「Token Logs」がトークン利用のログ件数です。誰のトークンがどれだけ使われているかを追えます。
「Security」タブでは、認証イベントと監査ログの件数が見られます。

Auth Eventsはログインなどの認証イベントで、この環境でもログインし直した分がカウントされています。Audit Logsは AUDIT_TRAIL_ENABLED を有効にすると溜まっていくもので、今回は無効なので0件です。
数値そのものは検証環境なので小さいですが、MCP Gatewayを1本通しただけで、ツール単位の利用実績とレスポンスタイムが自動で取れる のはそれだけで価値があります。直結だと、この手の「どのAPIが・どれだけ・どのくらいの速さで呼ばれたか」は各API側のログを突き合わせるしかありません。
補足:画面からでもAPIからでも操作できる
ここまでの操作はすべてAdmin UIから行いましたが、同じことはREST APIからもできます。Admin UI自体がこのAPIを呼んでいるので、画面でできることはAPIでもできる、という関係です。ツールや仮想サーバーの登録をコード管理したい、CI/CDから流し込みたい、といった場合はこちらが向いています。
エンドポイントの一覧は、起動したMCP Gatewayの /docs(Swagger UI)と /redoc でそのまま見られます。Admin UIにログイン済みのブラウザなら、そのまま開けます。
http://localhost:4444/docs
具体的な使い方は、公式ドキュメントのAPI Usage Guideに、エンドポイントごとの例がまとまっています。
補足:最小構成にするために何を削ったか
公式の docker-compose.yml は本番運用を見据えた構成です。プロファイル指定なしでも、Gateway(3レプリカ)・nginx・PostgreSQL・pgbouncer・Redis・DBマイグレーション用のジョブ・サンプルMCPサーバーとその登録ジョブが立ち上がります。さらに monitoring プロファイルを付けるとPrometheus・Grafana・Loki・Tempo・pgAdminなどが、sso プロファイルではKeycloakが加わります。
今回はこれを、次のように置き換えてコンテナ1個にしました。
| フル構成 | 今回の最小構成 |
|---|---|
| PostgreSQL + pgbouncer(接続プール) | SQLite(DATABASE_URL="sqlite:////data/mcp.db") |
Redis(CACHE_TYPE=redis) |
既定の CACHE_TYPE=database のまま。Redisを立てない |
| nginx(TLS終端・キャッシュ、8080で公開) | Gatewayの4444をそのまま公開 |
| マイグレーション用のワンショットジョブ | 起動時にSQLiteのファイルが作られるので不要 |
| サンプルMCPサーバーと自動登録ジョブ | 題材のWebAPIを自分で登録するので不要 |
Gateway 3レプリカ / GUNICORN_WORKERS=24 |
1コンテナ / GUNICORN_WORKERS=2 |
監視スタック(monitoring プロファイル) |
Admin UIのMetrics画面で確認 |
逆に、docker run では既定のままだと足りない部分があるので、そこは明示的に足しています。
MCPGATEWAY_UI_ENABLED/MCPGATEWAY_ADMIN_API_ENABLED:どちらも既定はfalseなので、Admin UIを使うためにtrueにしますJWT_SECRET_KEY/AUTH_ENCRYPTION_SECRET:起動時に強度が検証されるので、生成した値を渡しますEXPOSE_ERROR_DETAILS=true:バリデーションエラーが既定ではマスクされ、{"detail": "An error occurred, please try again."}しか返らないため、検証中は詳細が見えるようにしています(本番では伏せるべき設定です)
削ったことによる制約も、そのぶん出ます。nginxを外してHTTPで直接公開しているので、ログイン画面にはsecure cookieの警告が出ます。SQLiteかつ1コンテナなので、複数インスタンスでの共有やスケールは確認できません。監視スタックがないので、メトリクスはAdmin UIから見える範囲だけです。「機能が要件を満たすか」を確かめる目的には十分でしたが、本番構成の検証としては別途フル構成を組む必要があります。
おわりに
AIエージェントから社内の業務システムを参照する、というテーマを入口に、MCP Gatewayという概念と、そのOSS実装であるContextForgeを触ってみました。
改めて整理すると、WebAPIをMCPに変換する処理はどうやっても必要になりますが、MCP Gatewayの本質は その変換を束ねて、認証・監査・レート制限・キャッシュといった統制を一箇所に集約できる ことにあります。特に、API利用が従量課金になる業務システムでは、レート制限やキャッシュによるコスト統制が効いてきます。実運用では、すべてを一律に統制するのではなく、コストリスクの高いシステムだけをGateway経由にする、といった使い分けも考えられます。
MCPサーバーが増えてきて管理に悩み始めた方は、まずローカルで一度、既存のAPIを1本MCP化して束ねてみると、MCP Gatewayの効きどころが体感できると思います。ぜひ試してみてください。
このブログがどなたかのお役に立てれば幸いです。
参考資料
- ContextForge(IBM/mcp-context-forge)
- ContextForge 公式ドキュメント
- 題材にしたSampleAPIs
- mcp-remote(stdio ⇄ リモートMCPのブリッジ)








