【Oktane26】Okta for AI AgentsのAgent Gatewayを現地で検証してみた
はじめに
こんにちは、飛行機が遅延して焦りまくったネクストモードのSaaSおじさん久住です。
Oktane 2026では、AIエージェントの保護とガバナンスが大きなテーマの一つです。その中でも個人的に注目していたのが、Okta for AI AgentsのAgent Gatewayです。
Oktane前はリサーチリリースだったのが、なんと一般公開(GA)が発表されました!

せっかく現地で触れられるようになったので、さっそく試してみます。本記事では、自作のAIエージェントからSlack公式のリモートMCPサーバーへ接続する構成を作り、その通信をAgent Gatewayでどこまで統制できるか検証します。
Agent Gatewayについてのセッションレポートもありますのであわせてご覧ください。
Agent Gatewayを利用するメリット
一言でいうと、AIエージェントの便利さはそのままに、アクセスを見える・絞れる・止められるようにできるのが嬉しいポイントです。
- 見える:どのエージェントが、誰の代理で、どのツールを呼んだかを追跡できる
- 絞れる:エージェントに必要なツールだけを許可できる
- 止められる:問題のある接続をGateway側で無効化できる(キルスイッチ)
とくに自作エージェントの場合、これまではSlackのトークンを設定ファイルや環境変数に直接持たせることが多く、常時有効な権限がコード側に残りがちでした。Agent Gatewayを使えば、エージェントに渡すのはOktaのトークンだけで済みます。
Agent Gatewayとは
Agent Gatewayは、AIエージェントとリモートMCPサーバーの間に入るプロキシです。複数のツールをOktaで保護された1つの仮想MCPサーバー(vMCP)にまとめ、ツール呼び出し時に接続先のアクセストークンを取得してリクエストへ挿入します。

| 比較項目 | 直接接続 | Agent Gateway経由 |
|---|---|---|
| 接続先 | 個別に設定 | vMCPへ集約 |
| 権限 | 接続先側で管理 | 公開ツールをOktaで選択 |
| 資格情報 | エージェントが保持 | Gatewayが注入 |
| 監査・遮断 | 接続先ごと | Oktaで集約 |
構成概要
自作のエージェント(MCPクライアント)から、Slackが公式提供するリモートMCPサーバーへ接続します。
接続先はAgent GatewayのvMCPエンドポイントだけにして、Slackのトークンはエージェント側に一切持たせません。

確認するポイントは以下の5点です。
- Agent GatewayへSlackのリモートMCPサーバーを登録し、OAuth認可を完了できるか
- vMCPで公開するツールを絞れるか(例:検索・閲覧のみ許可し、投稿は公開しない)
- 自作エージェントにSlackトークンを持たせずに、Gatewayのトークン注入だけでツール呼び出しが成功するか
- Okta側でエージェントまたはGatewayを無効化したとき、Slack操作を遮断できるか
- ツールコールがOkta System Logへ記録されるか。記録内容をSlack監査ログとどこまで突合できるか
💡 今回の自作エージェントは、Node.js(TypeScript)とMCP公式SDKで作った小さなMCPクライアントです。上の5点はOkta・Gateway・Slackの間で起きることなので、LLMは使わずにツールを直接呼び出して検証しました(LLMをつなげば、同じ仕組みの上でAIがツールを選んで実行します)。
前提条件
- Okta for AI Agentsを利用できるOkta環境(今回はPreview Sandbox)
- Agent Gatewayを利用できること
- Slack公式のリモートMCPサーバーを利用できるSlackワークスペース(今回はEnterprise Grid配下のワークスペース)
- Slack MCPサーバー向けのSlackアプリと、利用するツールに対応したOAuthスコープ
- 検証用のSlackパブリックチャンネル
- OAuth 2.0(Authorization Code + PKCE)でログインできるMCPクライアント(自作エージェント)
💡 Slackは公式のリモートMCPサーバーをOAuth認可で提供しており、Agent Gatewayの前提(リモートMCPサーバー+OAuth 2.0 Bearer認証)に合うため、今回の検証対象に選びました。
設定の全体像
設定は次の順番で進めます。Agent Gatewayの作成画面では「登録済みのMCPサーバー」と「登録済みのAIエージェント」から選ぶ形になっているため、MCPサーバーとAIエージェントを先に登録しておくのがポイントです。
- Slackアプリを準備する
- OktaにSlack MCPサーバーを登録する
- OktaにAIエージェントを登録する
- Agent Gatewayを作成し、エージェント・MCPサーバー・公開ツールを紐づける
- 自作エージェントをvMCPへ接続する
設定してみた
Step 1:Slackアプリを準備する
Agent GatewayがSlack MCPにOAuthでログインするための「OAuthクライアント」として、Slackアプリを作ります。Slackのドキュメントによると、MCPを使えるのはMarketplace公開アプリか社内アプリだけです。今回は検証用の社内アプリとして作りました。

1-1. アプリを作成する
api.slack.com/apps で Create New App → Blank app を選び、アプリ名(今回は「Okta Agent Gateway test」)と検証用ワークスペースを指定します。
1-2. スコープを追加する
OAuth & Permissions → User Token Scopes に、使うツールに必要なスコープを追加します。Slack MCPはユーザートークンで動くので、Bot Token Scopesではありません。

| スコープ | 用途 |
|---|---|
search:read.public |
公開チャンネルのメッセージ検索 |
channels:read / channels:history |
チャンネル情報・履歴の閲覧 |
users:read |
ユーザー名の解決 |
chat:write |
投稿(Step 8で使う) |
1-3. リダイレクトURLを追加する
同じ画面の Redirect URLs に、Oktaのコールバック https://{Oktaドメイン}/oauth2/v1/sts/callback を追加し、「URLを保存する」まで押します(追加しただけでは保存されません。私はここを忘れて redirect_uri did not match any configured URIs になりました)。
1-4. Slack MCP Serverをオンにする
Agents 画面で 「Slack Model Context Protocol (MCP) Server」をオンにします。

⚠️ 【よくある躓きポイント】
このスイッチがオフのままだと、Slack MCPは App is not enabled for Slack MCP server access で接続を拒否します。ところがOktaの画面には「ツールを検出できません」としか出ないので、原因がまったく分かりません(詳しくはStep 2)。
なお、左メニューの[MCP Servers]や、[Agents]画面上部の「Agent experience」は今回は不要です。
1-5. インストールしてチャンネルを作る
アプリをワークスペースにインストールし、検証用のパブリックチャンネル(今回は #test-agent-gateway)を作ります。ユーザートークンで動くため、アプリをチャンネルへ招待する必要はありません。
1-6. Client ID / Client Secretを控える
Basic Information の Client ID / Client Secret を控えます。Manage Distribution の「Public Distribution」は有効化しないでください(非公開の配布アプリ扱いになり、MCPを使えなくなります)。
Step 2:OktaにSlack MCPサーバーを登録する
Okta管理コンソールの アプリケーションとリソース → MCPサーバー → カスタムMCPを追加 から登録します。

2-1. 名前とURL
名前(今回は slack mcp)と、リソース識別子に https://mcp.slack.com/mcp を入れます。リソース識別子は後から変更できません。

2-2. 認可サーバー
Slack MCPのメタデータから、認可サーバーが自動で入力されます。

| 項目 | 値 |
|---|---|
| 発行者 | https://mcp.slack.com |
| 認可エンドポイント | https://slack.com/oauth/v2_user/authorize |
| トークンエンドポイント | https://slack.com/api/oauth.v2.user.access |
2-3. クライアント資格情報
クライアント登録タイプは「静的資格情報」を選び、Step 1で控えたSlackアプリのClient ID / Client Secretを入れます。OAuthスコープは「スコープをカスタマイズ」で、Slackアプリに付けた5つを選びます。


2-4. 資格情報をテストしてツールを検出
ボタンを押すとSlackの同意画面がポップアップで開きます。「許可する」を押すと、Slack MCPのツールが7個検出されました。

検出されたツールは次のとおりです。
読み取り系:slack_search_public/slack_search_channels/slack_read_channel/slack_read_thread書き込み系:slack_send_message/slack_schedule_message/slack_send_message_draft
🔍 「ツールを検出できません」の原因調査
最初は、Slackの同意まで進んだのに下の画面で止まりました。System LogではSlackトークンの取得(oauth_sts)は成功していたため、同じトークンでSlack MCPへ直接つなぐスクリプトを書いて確認したところ、Slackが App is not enabled for Slack MCP server access を返していました。Step 1の[Agents]のスイッチをオンにしたら、すぐに検出できました。

Step 3:OktaにAIエージェントを登録する
ディレクトリ → AIエージェント → AIエージェントを登録 → 手動で登録 から登録します。

3-1. プロファイル
名前を入れて次へ進みます。

⚠️ エージェント名に日本語を使うと、次の手順で自動作成されるOIDCアプリの名前が、Unicodeのエスケープ表記(AgentGateway検証…)のまま表示されました。エージェント側の名前を変えるとアプリ名も追従します。今回は AgentGateway Test Agent に変更しました。最初から英数字の名前にしておくのが無難です。
3-2. ユーザーアクセスと認証
「ユーザーがこのエージェントにアクセスできるようにする」にチェックを入れ、「このAIエージェントにリンクされる新しいOIDCアプリを作成する」を選びます。これがAgent Gatewayへの接続機能のスイッチで、ユーザーの代理でエージェントが動く今回の構成では必須です。

一度紐づけたOIDCアプリは変更できず、変えるにはエージェントの削除が必要です。既存アプリを流用せず、専用のアプリを作るのが安全です。
3-3. 所有者を追加
ガバナンスとライフサイクル管理のための所有者を指定します(推奨は2人以上)。

3-4. クライアント登録(エージェントの認証方式)
エージェント画面の[クライアント登録]で、Oktaで生成されたクライアントID → クライアントシークレット → 構成 を選びます。

シークレットを生成し、表示されたシークレットとクライアントIDを控えて、[アクティブ化]します。

3-5. ユーザーの割り当て
[ユーザーアクセス]を見ると「割り当てなし」になっています。リンクされたアプリに、エージェントを使うユーザーを割り当てます。

アプリを有効化しないと割り当てができなかったので、先にアプリを有効化しました。

📌 リンクされたOIDCアプリについて(今回の環境で確認したもの)
・Client IDはAIエージェント(ワークロードプリンシパル)自身のID(wlp…)
・付与タイプの「認証コード」「トークンの交換」はグレーアウトで固定(「リフレッシュトークン」は既定でオフ)
・サインインリダイレクトURIには、既定で http://localhost:8080/authorization-code/callback が登録済み(今回はアプリ側は変えず、自作エージェントをこのURIに合わせました)
Step 4:Agent Gatewayを作成する
セキュリティ → エージェントゲートウェイ → エージェントゲートウェイを作成 から作成します。

4-1. プロファイル
名前(今回は「Slack MCP」)を入れて作成します。ゲートウェイURLは https://{Oktaのサブドメイン}.gateway.oktapreview.com/mcp/servers/slack-mcp の形で、保存後は変更できません。作成直後は非アクティブです。

4-2. AIエージェント
Gatewayを呼び出せるエージェントとして、Step 3の AgentGateway Test Agent を選んで保存します。

4-3. リソース接続
[接続の追加]から、Step 2で登録した slack mcp を選んで保存します。


4-4. ツールのカスタマイズ
追加直後は7個すべてが「未接続」です。[ツールを管理する]から公開するツールを選びます。

4-5. 有効化
ツールを選んで保存すると「ゲートウェイをアクティブ化する準備ができました」と表示されるので、[直ちにアクティブ化]を押します。

まずは読み取り系の4つだけを公開し、投稿・予約投稿・下書きは未接続のままにしました。ゲートウェイの設定は以上なので終了を押します。

一覧に戻り、ゲートウェイがアクティブになっていることを確認できました。

Step 5:自作エージェントをvMCPへ接続する
自作エージェントの設定は、ゲートウェイURLと、Step 3のClient ID / シークレットだけです。Slackのトークンはどこにも書きません。
GATEWAY_URL=https://{Oktaのサブドメイン}.gateway.oktapreview.com/mcp/servers/slack-mcp
OKTA_CLIENT_ID=wlp…(AIエージェントのクライアントID)
OKTA_CLIENT_SECRET=…(AIエージェントのクライアントシークレット)
OKTA_SCOPES=openid REDIRECT_URI=http://localhost:8080/authorization-code/callback
起動すると、エージェントは次の流れでOktaにログインし、vMCPへ接続します。
- 認証なしでゲートウェイURLにアクセスすると 401 が返り、
WWW-Authenticateヘッダーでメタデータの場所(/.well-known/oauth-protected-resource/mcp/servers/slack-mcp)が案内される - メタデータから、Gateway専用のOktaカスタム認可サーバー(
https://{Oktaドメイン}/oauth2/aus…)が分かる - Authorization Code + PKCEでブラウザからサインインし、アクセストークンを取得する
- そのトークンをBearerにして、vMCPへ
tools/list/tools/callを送る
接続部分のコードは、MCP公式SDKの標準的な書き方そのままです。
const transport = new StreamableHTTPClientTransport(new URL(GATEWAY_URL), {
requestInit: { headers: { Authorization: `Bearer ${accessToken}` } }, // Oktaのトークンだけ
});
await client.connect(transport);
const { tools } = await client.listTools();
await client.callTool({ name: "slackmcp_slack_read_channel", arguments: { channel_id: "C0XXXXXXXXX" } });
接続すると、公開した4つのツールだけが見えました。ツール名には、Gatewayが接続先ごとの接頭辞 slackmcp_ を付けています。

エージェントが持つアクセストークンも、iss がGateway専用のOktaカスタム認可サーバー、aud がゲートウェイURL、sub がサインインしたユーザーです。Oktaが「このGateway専用・このユーザー用」に発行したトークンだけで、Slackのトークンではありません。
💡 メタデータが案内するスコープは openid offline_access ですが、リンクされたアプリでリフレッシュトークンを有効にしていないため、openid だけで接続しました。アクセストークンの期限が切れたら再ログインが必要です。
検証してみた
ここからは、Step 5までで作った環境を使って、確認ポイント②〜⑤を順に確かめます。
Step 6:Slackトークンなしでツールを実行する
slackmcp_slack_read_channel を実行すると、初回だけ次のエラーが返りました。

Step 2の同意は「管理者がツール一覧を取得するため」のもので、ここでは「エージェントがあなたの代理でSlackを操作するため」の同意が、ユーザーごとに1回必要です。URLを開くとSlackの同意画面が出るので、「許可する」を押します。Slackのトークンは、このときOkta側に保管されます。エージェントには渡りません。

同意後にもう一度実行すると、チャンネルのメッセージを取得できました。

Step 7:公開していないツールを呼んでみる
公開していない slackmcp_slack_send_message を、ツール名を直接指定して呼び出しました。結果は MCP error -32602: invalid params です。存在しないツール名を呼んだときとまったく同じ応答なので、エージェントからは非公開ツールの存在も分かりません。Slackにも投稿されていませんでした。

一方、Okta System Logには tool "slackmcp_slack_send_message" not found と本当の理由が記録されていました。エージェントには伏せ、管理者は追える作りです。
Step 8:投稿ツールを追加公開する
Okta側で slack_send_message を追加公開します。

エージェントでツール一覧を再取得すると5件になりました。
.png?width=800&height=543&name=s27-ui-tools-5.webp%20(1).png)
Step 7で invalid params になったのとまったく同じ引数で呼び出すと、今度は成功しました。

Slackにはログインユーザー本人の名義で、「Okta Agent Gateway test を使用して送信されました」と投稿されています。エージェントのコードも設定も変えずに、Okta側の設定だけで権限が変わりました。

Step 9:Okta側から止める
Okta側で止めたとき、エージェントからの呼び出しがどうなるかを確かめました。時刻はOkta System Logのイベント時刻です。
9-1. GatewayのAIエージェントからエージェントを外す
Gatewayの[AIエージェント]からエージェントを外して保存しました(System Logでは workload_principal.delegation_link.delete)。ここでは手動で呼び出しています。

| 経過 | 結果 |
|---|---|
| 0分 | 委任リンクを削除 |
| 約50秒〜1分25秒 | GatewayによるSlackトークンの交換(oauth_sts)が3回とも成功。削除はまだ反映されていない |
| 〜約3分 | 呼び出しは成功し続ける。この間トークン交換は発生せず、キャッシュ済みのトークンが使われた |
| 約3分45秒 | 再ログインは拒否(access_denied: Policy evaluation failed/System Logは no_matching_policy) |
| 約4分15秒 | エージェントを戻す(delegation_link.create) |
| 約4分40秒 | 再ログインに成功し、新しいセッションを確立 |
| 約4分50秒〜 | 呼び出しが MCP error -32001: authorization failed で失敗(System Logは token exchange failed) |
| 約7分35秒 | トークン交換が成功し、呼び出しも復帰 |

わかったこと:
- 委任リンクが判定されるのは、GatewayがSlackのトークンを取りに行く(トークン交換)ときだけでした。キャッシュ済みのトークンがある間は、実行中のセッションがそのまま動き続けます。
- 止まったのは、再ログインで新しいセッションになってからです。エージェントを戻した後だったので、削除の反映が遅れて効いた形です(戻してから復帰まで約3分20秒)。
- 削除直後の約1分半は、トークン交換自体も成功していました。再ログインせずに呼び続けた場合にいつ止まるかは未確認です。
9-2. Gatewayを無効化する
次に、5秒間隔で slackmcp_slack_read_channel を呼び続けながら、Gateway自体を無効化しました(workload_principal.deactivate)。

| 操作 | 切り替わり始め | 完全に反映 |
|---|---|---|
| Gatewayの無効化 | 約2分後(HTTP 401が出始める) | 約4分半後 |
| Gatewayの再有効化 | 約1分後(成功が出始める) | 約3分半後 |
どちらも、切り替わりの途中は成功と拒否が混在しました。Slackトークンの取得元(Gateway側)のIPが3つあったので、Gatewayの複数のサーバーがそれぞれキャッシュを持ち、少しずつ反映されていくためと推測しています。
9-1と9-2の違い
| エージェントを外す(委任リンク削除) | Gatewayを無効化 | |
|---|---|---|
| 判定のタイミング | Slackトークンの交換時だけ | 呼び出しのたび(リクエスト検証) |
| 実行中のセッション | キャッシュが効いている間は動き続ける | 再ログインしなくてもHTTP 401で止まる |
| 止まるまで | 新しいセッションになるか、キャッシュが切れるまで(今回は再ログイン後に停止) | 約2分で拒否が始まり、約4分半で完全遮断 |
| 向いている用途 | 特定のエージェントの権限を外す | すぐに止めたい(緊急停止) |
📢 現時点では仕様どおり。拡張版は今後提供予定
Oktane 2026のプレスリリースでは、現在のキルスイッチは「エージェントを無効化すると新しいセッションをブロックする」ものとされており、9-1の挙動はこの説明どおりです。あわせて、キルスイッチをAgent Gatewayに拡張し、発行済みトークンの失効と実行中セッションの停止まで行える拡張版が、Q4にGA予定と発表されています(予定のため変更の可能性あり)。
Step 10:ログで追跡する
Gatewayの[最近のアクティビティ]
Gatewayの詳細画面には[最近のアクティビティ]タブがあり、過去30日間のツール呼び出しとGatewayの操作を確認できます。どのユーザーの代理で、どのAIエージェントが、どのMCPサーバーのツールを呼び、成功したかが一覧で分かるので、まずはここを見れば十分です。トークン交換や認証のイベントまで追うときは、System Logを見ます。

Okta System Log
ツール呼び出しは1回ごとに記録され、エージェント側のログと約1秒差で1対1に突き合わせられました。
| イベント | 内容 |
|---|---|
agent_gateway.mcp.session.establish |
エージェントがGatewayに接続した |
agent_gateway.mcp.tools.list |
ツール一覧を取得した |
agent_gateway.mcp.tool.call |
ツール呼び出し1回ごと。アクター=AIエージェント、代理元ユーザー、接続先MCPサーバー、成功/失敗と失敗理由 |
agent_gateway.request.validate |
認証ヘッダーなしのアクセスを拒否した |
app.oauth2.token.grant.oauth_sts |
GatewayがSlackのトークンを取得した(STSトークン交換) |
- Slackのトークン取得(
oauth_sts)は、ツール呼び出し約70回に対して10回だけでした。Gatewayは下流のトークンをキャッシュして使い回しています。 - Gatewayの無効化で401になった呼び出しは、
tool.callとしては記録されませんでした。 - エージェントを外していた間の
tool.callは、アクター名が空欄でした。
Slack監査ログ
Enterprise Gridの監査ログ(組織の管理画面からCSVでエクスポート)にも、MCPのツール呼び出しが mcp_slack_read_channel_tool_called などとして1回ごとに記録されていました。件数はエージェント側の成功件数(98件)と一致し、Okta側のイベントとも時刻差1秒以内で突き合わせられました。
- Slack側の操作者はログインユーザー本人、操作したアプリはOkta Agent Gateway test(Oktaに登録したSlackアプリ)として記録されます。どのAIエージェントが呼んだかはSlack側からは分からず、Okta System Logと突き合わせて初めて「誰の代理で、どのエージェントが、Slackで何をしたか」がつながります。
- Oktaでは成功なのにSlackに記録がない呼び出しが2件ありました(初回の同意待ちと
channel_not_found)。Oktaの「成功」は「Gatewayが処理した」という意味で、Slack側の成功までは保証しません。 - CSVエクスポートには、読んだチャンネルや接続元IPは含まれませんでした。
検証結果まとめ
| 確認項目 | 結果 |
|---|---|
| ① Slack MCPの登録とOAuth認可 | ✅ 成功。Slackアプリの[Agents]で「Slack MCP Server」を有効にする必要あり |
| ② 公開ツールの絞り込み | ✅ 7ツール中4つだけ公開できた。非公開ツールは存在しないツールと同じ応答。Okta側で公開すると、コード変更なしで同じ呼び出しが成功 |
| ③ Slackトークンなしでのツール実行 | ✅ 成功。エージェントの資格情報はGateway向けのOktaトークンだけ。初回のみユーザーごとにSlackへの同意が必要 |
| ④ Okta側からの遮断 | ⚠️ 止められるが即時ではない。Gateway無効化は約2分で拒否が始まり、約4分半で完全遮断。エージェントを外しても、実行中のセッションは新しいセッションになるまで動き続けた(現時点の仕様どおりで、Q4予定の拡張版で対応見込み) |
| ⑤ Okta System Log/Slack監査ログでの追跡 | ✅ 両方に1回ごとに記録され、約1秒差で突き合わせ可能。エージェントの特定はOkta側、Slackでの操作内容はSlack側で見る |
キルスイッチは現時点では即時ではないので、緊急時はGatewayの無効化に加えて、Slack側でのトークン失効やアプリの無効化も組み合わせるのが安全です。
さいごに
今回はOktaneが開催されたラスベガス現地から、いち早くAgent Gatewayの機能を試しました。
自作エージェントの準備に少し時間がかかったものの、Agent Gatewayの作成自体はそこまで複雑ではなく、初めての設定が楽しくてのめり込んでしまいました。
現時点では、キルスイッチが即時ではないことや、AIエージェントをOktaに登録する必要があり、登録できるAIエージェントもまだ限られていることなどの制約もあります。それでも、AIエージェントが業務ツールを本格的に操作する時代に、IDを起点とした実行時アクセス制御の重要性を実感できる機能でした!
参考リンク
- Introducing Agent Gateway: Runtime AI agent governance
- Okta Agent Gateway — Developer Documentation
- Configure an Agent Gateway — Developer Documentation
- Configure an AI agent for Agent Gateway — Developer Documentation
- Agent Gateway — Okta Documentation
- Add an Agent Gateway — Okta Documentation
- Okta for AI Agents
- Slack MCP server overview — Slack Developer Docs
- Audit Logs API actions(Slack MCP Server)— Slack Developer Docs
Okta に関するお問い合わせ
ネクストモードでは、AI エージェントのセキュリティ対策を含む Okta の導入から運用までを支援しています。Okta に関するご相談は、ネクストモードまでお気軽にお問い合わせください。