こんにちは、ネクストモード株式会社テクニカルサポート担当です。
前回は Slack MCP を STS(Brokered Consent)で扱いました。今回はその続きとして、ID-JAG を受け取れる Notion MCP を Cross App Access(XAA) で呼び出します。
なお、Notion MCP の Enterprise-managed connections は Enterprise プラン前提の機能として案内されています。
AgentCore Runtime 上のエージェントには常設の Notion トークンを置かず、XAA でその都度発行される access token だけで remote Notion MCP を呼び、情報が取得できることを検証しました。併せて、Okta Admin Console で Notion の接続を切ることでエージェントが Notion から情報が取得できなくなることも検証できました。Notion 側の OAuth クライアントと、Okta 側の Resource server / Resource connections もセットです。前回の Slack では初回に同意画面がありましたが、今回は出ていません。
この記事では AWS の ECR や CloudWatch の画面にはあまり立ち入らず、次の 3 点に絞っています。
いちばん最初からうまくいったわけではなく、Resource Indicator の扱い違いや、SSO・Enterprise-managed connections まわりの寄り道もありました。本筋のあとに、その話も書きます。
※本記事は執筆時点の情報に基づきます。Early Access や仕様変更により、画面や挙動が変わる場合があります。最新情報は公式ドキュメントをご確認ください。
「呼べた/呼べない」だけだと味気ないので、読めた中身が本物の Notion であることと、接続を外すと止まることを同じ検証のなかで揃える、というのが今回のゴールです。
構成は remote Notion MCP + Okta Cross App Access(XAA) です。エージェントは https://mcp.notion.com/mcp を、XAA で受け取った Notion access token だけで呼びます。常設の Notion トークンは置きません。トークンの最終発行は Notion 側の認可サーバです。
環境は、AgentCore Runtime(東京)、Okta for AI Agents に取り込み済みの agentcore_demo、検証用 Notion ワークスペース、remote MCP です。前回と同じ Okta Org / エージェントです。同じ Runtime には Slack STS も載せていますが、今回の検証では Notion の Resource connection だけを活用しています。エージェントに Management API 用のトークンは持たせていません。応答の画面は、同じエージェントをローカルのチャットから叩いた結果です。
今回の Notion 側の前提は、次の 3 つです。Notion MCP 用の OAuth クライアントを用意すること、Okta と同じユーザーで SSO できる状態にすること、Enterprise-managed connections を有効にすることです。
XAA で仲介するにしても、Notion 側にはエージェント用の OAuth クライアントが必要です。今回は Notion MCP の Dynamic Client Registration(https://mcp.notion.com/register)で作り、返ってきた Client ID を Okta の Resource connection に載せました。Client secret は Runtime の環境変数に置きますが、Notion の access token を常設する構成ではありません。値は公開していません。
あわせて、Okta を Notion の IdP にしました。SAML SSO を有効にし、Okta と同じメールのユーザーがワークスペースのメンバーとして入れることが必要です。
また、以下の手順で Notion 側の Enterprise-managed connections を有効にする必要があります。
ここからが今回の検証の本編です。Okta Admin Console で、Notion 向けの Resource server(XAA)と、エージェントの Resource connections を設定します。
補足:2026.08.0 から画面構成が変わり、Resource server / MCP Servers は Applications and Resources 配下にあります。AI Agents は従来どおり Directory 配下です。
設定の流れは次のとおりです。
今回の Resource server では XAA を Enable します。執筆時点の OIN Notion には Cross App Access があり、Brokered Consent(STS)の項目自体は出ませんでした。実行時に効いたスイッチは AI Agent の Notion Resource connection でした。
https://mcp.notion.com を設定し、Save します。Audience は空のままで問題ありません。続いて、前回までの記事で取り込み済みの AI Agent(検証では agentcore_demo)に、Notion を接続先として追加します。ここで許可したアプリに対してだけ、エージェントが XAA を進められることを確認します。
invalid_client になります。動きとしては、次の順です。
id_token を付けてエージェントを呼ぶid_token → ID-JAG(aud は https://mcp.notion.com)に換えるつまり、Okta は Notion に渡すための ID-JAG を発行し、最終的な Notion access token は Notion 側が発行します。
つまり、Runtime が長期保持する Notion トークンで直接読むのではなく、Okta と Notion のトークン交換で都度 Notion access token を取得して読む構成です。
常設の Notion トークンは Runtime の環境変数に置きません。止める/通すは Okta Admin の Notion Resource connection です。AWS はエージェントが動く場所、という位置づけで、今回の主題は Okta で行う接続制御のほうです。同意画面は出ていません。
MCP が「呼べた」だけだと、中身が本物かどうか分かりません。そこでエージェントを呼び出し、応答に Notion の実データが乗っているかを見ました。対象は検証用ワークスペースです。プロンプトでは 1 件検索してタイトルだけ報告させ、作成・更新・削除は禁止しました。
応答にはタイトルの「🤖 プロジェクト&タスク」とURLが出力されました。
常設トークンを置かなくても、エージェントの応答に Notion のタイトルが載る、というのがここで見たかったポイントです。
同じ構成のまま、Admin の Notion Resource connection だけを切り替えました。Authorization server の行や、Slack の Resource connection は触っていません。INACTIVE にすると、読取は Notion に届く前に止まります。チャットには、管理者によって許可されていない、と返ります。
| Notion Resource connection | エージェントの応答 |
|---|---|
| ACTIVE | タイトル「🤖 プロジェクト&タスク」が返る |
| INACTIVE | 接続は管理者によって許可されていない、と返る |
| 再 ACTIVE | 再び同じタイトルを読める |
やったことは次のとおりです。
なお、エージェント側には常設の Notion トークンは設定しておらず、XAA 経由で取得した access token だけで Notion MCP を呼び出しています。
ここからは、検証中につまずいたポイントを整理します。特に Resource Indicator、OAuth クライアント ID、SSO、Enterprise-managed connections は、設定ミスに気づきにくい箇所でした。
今回の Notion XAA では、Okta で id_token から ID-JAG を取得するときに ORN を resource として渡さず、audience=https://mcp.notion.com だけを指定するのがポイントでした。
前回 Slack では、接続先として MCP URL をそのまま渡すと invalid_target になり、Admin の接続詳細にある ORN を STS の resource に載せて通しました。今回も最初は同じつもりで、Okta で ID-JAG を取得するときに ORN を付けました。
ORN を付けると、Okta がそれを ID-JAG の resource クレームに載せます。Notion の token エンドポイントはそれを受けず、invalid_target / Invalid resource になりました。今回は、Okta で ID-JAG を取得するときに audience=https://mcp.notion.com だけを指定し、resource は送っていません。画面に ORN が出ること自体は問題ではなく、ID-JAG 取得時にそれを送らないのが今回の違いでした。
INACTIVE のときは、ORN を付けずに ID-JAG を取得する流れでも止まりました。トークン交換単体では HTTP 400 invalid_target です。接続のスイッチは ORN を送らなくても効いています。
Resource connection の AI agent's client ID registered in this app は、Okta に取り込み済みの agentcore_demo の Client ID かと最初は思っていました。しかし反映すべきは、接続先の認可サーバに登録した、エージェント用 OAuth クライアントです。前回 Slack では api.slack.com のアプリ Client ID が同じ役割でした。
今回は https://mcp.notion.com/register の Dynamic Client Registration で作り、返ってきた client_id を Okta の欄へ、client_secret を Runtime へ置いています。secret なしで token を叩くと invalid_client になるので、クライアント自体は Notion に認識されていました。
XAA では、Okta の id_token のユーザーと Notion のユーザーが対応している必要がありました。
検証当初は Okta と Notion それぞれの検証環境でメールドメインが異なることによりうまく進めることができずハマりました。通常の環境であれば問題ないかと思いますが念のため記載しておきます。
SSO まで通っても、Notion 側の Enterprise-managed connections がオフだと、ID-JAG を Notion の token エンドポイントに渡す段階で落ちました。https://mcp.notion.com/token へ jwt-bearer したところ、invalid_grant / Invalid assertion となりました。これは Okta は ID-JAG を出せていても、Notion がそれを受け取っていない状態です。
Enterprise-managed connections をオンにし進めることが必要な点も注意が必要です。
前の記事で予告していた Notion MCP × XAA の検証です。
Slack MCP では、先に XAA で通せないかを見ました。OIN に Cross App Access が出ていても、接続先 MCP の認可サーバが ID-JAG を受け取るとは限りません。確認したのは認可サーバの .well-known/oauth-authorization-server です。jwt-bearer と id-jag が grant_types / authorization_grant_profiles に載っているかが目安でした。
Slack 側(metadata)には authorization_code と refresh_token だけで、jwt-bearer はありませんでした。そのため Slack MCP では STS になりました。
Notion 側(metadata)は次のとおりです。判断に使ったキーだけ抜粋します。
jwt-bearer と id-jag が載っています。Okta OIN の Notion にも Cross App Access があり、Brokered Consent はありません。カタログと接続先の metadata が揃っていたので、今回は XAA で進めています。
OIN にそう書いてあっても、接続先が実際に受け取る grant と同じとは限らない、というのが前回からの続きでした。接続先が本当に ID-JAG を受け取るかは、その認可サーバの metadata を当たると迷いにくかったです。
今回の検証では、Notion MCP を Okta の XAA 経由で呼び出し、Resource connection の切り替えがエージェントの応答に反映されるところまで確認できました。
今回は Notion MCP を XAA で呼び出し、Resource connection による接続制御を確認するところに絞りました。次の内容は扱っていません。
前回の Slack MCP × STS に続き、今回は Notion MCP を Cross App Access(XAA)で呼び出し、Okta for AI Agents の 「What can they connect to?(何に接続できるか)」 をもう一歩進めて確認しました。
常設の Notion トークンを置かずに Notion の情報を読めること、そして Notion Resource connection を切ると読めなくなり、戻すと再び読めることを、エージェントの応答として確認できたのは大きなポイントです。接続先が変わると、STS なのか XAA なのか、Resource Indicator をどう扱うのかも変わります。ここは、実際に手を動かしてみて特に差を感じられました。
Slack と Notion で経路は違いましたが、どちらも最終的には「エージェントが何に接続できるか」を管理者側で制御できる、という同じテーマにつながります。ネクストモードとしては、AI エージェントの活用を進めるうえで、常設トークンに頼らず、必要な接続だけを管理者が制御できる設計が重要だと考えています。利便性だけでなく、こうした接続制御まで含めて整えていくことが、これからの AI エージェント活用には欠かせないポイントになりそうです。
AI エージェントのアイデンティティ管理やセキュリティ統制に関するご相談は、ネクストモードまでお気軽にお問い合わせください。