Agent Registry を使用してプライベート カスタム MCP サーバーにエグレスする Agent Gateway を使用した Gemini Enterprise

1. はじめに

この Codelab では、agent-to-anywhere(下り)モードで Agent Gateway を使用して、Gemini Enterprise のプライベートで管理された下り(外向き)接続について説明します。Gemini Enterprise アプリを構成して、Private Service Connect(PSC)インターフェースを使用して Agent Gateway を介してトラフィックをルーティングし、Cloud Run でホストされているカスタム Model Context Protocol(MCP)サーバーを安全に呼び出します。これにより、VPC ネットワーク内の Google API の PSC エンドポイントに接続します。

エンタープライズ環境で自律型エージェントにネットワークへの直接アクセスを許可すると、データ漏洩や未審査のツールの実行のリスクが生じます。Agent Gateway は、ストリーミング可能な HTTP MCP ツールのペイロードを動的に検査する、一元化されたプラットフォーム レベルのゼロトラスト適用ポイントを提供します。アウトバウンド リクエストは、暗号で検証可能なAgent Identity で認証され、Common Expression Language(CEL)ルールを含む IAM 統合アクセス ポリシー(UAP)を使用して Identity-Aware Proxy(IAP)で認可されます。これにより、バックエンド ワークロードを公共のインターネットに公開することなく、特定の MCP ツールとメソッドに対するきめ細かいアクセス制御が可能になります。

構築内容

  • Agent Registry エンドポイント検証を使用した外向き(エージェントから任意の宛先へ)モードで動作する Agent Gateway
  • Agent Registry にツール仕様が登録されているプライベート ストリーミング HTTP MCP サーバー(--ingress=internal)をホストする Cloud Run サービス
  • Agent Gateway の Identity-Aware Proxy(IAP)認可拡張機能
  • MCP ツールの認可のための CEL 条件を含む IAM 統合アクセス ポリシー(UAP)
  • Agent Gateway にバインドされ、Agent Registry からインポートされたカスタム MCP サーバー データストアに接続された Gemini Enterprise アプリ
  • VPC ネットワーク リソース、Cloud DNS ゾーン、Google API 用 PSC エンドポイント
  • Agent Gateway プライベート VPC 下り(外向き)用の PSC ネットワーク アタッチメント
  • VPC トラフィックを保護する Cloud Next Generation Firewall(NGFW)ポリシー ルール

figure1

図 1. Codelab アーキテクチャ

学習内容

  • Cloud Run でソースからプライベート ストリーミング HTTP MCP サーバーをデプロイし、そのエンドポイントとツール スキーマを Agent Registry に登録する方法
  • 準拠したレジストリ エントリで Agent Gateway を構成し、Gemini Enterprise app のツール呼び出しをゲートウェイ経由でルーティングする方法
  • PSC ネットワーク アタッチメントとインターフェースを使用してプライベート VPC 下り(外向き)を確立する方法
  • Agent Gateway の認可を Identity-Aware Proxy(IAP)に委任する方法
  • destination.agent_registry.* と destination.is_registered の CEL 属性を使用して IAM 統合アクセス ポリシー(UAP)を作成してバインドし、MCP ツールの実行を制限する方法
  • Cloud Logging を使用してポリシーの適用とネットワーク下り(外向き)を検証する方法

必要なもの

  • 課金を有効にした Google Cloud プロジェクト
  • 有効な Gemini Enterprise ライセンスまたは30 日間のトライアル
  • ネットワーキング サービス、Gemini Enterprise、Agent Platform リソースをプロビジョニングするための IAM 権限
  • Google Cloud CLI(gcloud)、curl、jq がインストールされた POSIX 互換シェル(bash または zsh)

これで概要の説明は終わりです。次はコンセプトのセクションに進みます。

2. コンセプト

デプロイ シーケンス

この Codelab では、まずインフラストラクチャをデプロイして、MCP ツールを Gemini Enterprise に登録して接続する前に、プライベート ネットワーク パスとガバナンス制御が動作するようにします。

  1. ネットワーク インフラストラクチャ: VPC サブネット、PSC エンドポイント、PSC ネットワーク アタッチメント、Cloud NGFW ポリシー ルール、プライベート Cloud DNS ゾーンをプロビジョニングします。
  2. Agent Gateway: Agent Registry 統合(registries)とプライベート VPC 下り(外向き)(networkAttachment)を使用して、下り(外向き)モードで Agent Gateway をデプロイします。
  3. 認可ポリシー: destination.is_registered と destination.agent_registry.* の CEL 条件を使用して、IAP 認可拡張機能、Gateway Authz ポリシー、IAM 統合アクセス ポリシー(UAP)を構成します。
  4. MCP サーバーをデプロイして登録する: ソースから Cloud Run(--ingress=internal)に math MCP サーバーをデプロイし、Agent Registry にサービスとツールの仕様(add と subtract)を登録します。
  5. Gemini Enterprise アプリ: Gemini Enterprise アプリ(Engine)を作成し、ID とオブザーバビリティの設定を構成して、アウトバウンド下り(外向き)をエージェント ゲートウェイ(agentGatewaySetting)にバインドします。
  6. カスタム MCP データコネクタをインポートする: 登録済みの MCP サーバーのバッキング データストアを Gemini Enterprise アプリにリンクする REGISTRY_MCP データコネクタ(:setUpDataConnector)を作成して有効にします。
  7. 検証: チャットで許可されたツールと拒否されたツールの実行をテストし、Agent Gateway、DNS、ファイアウォール、Cloud Run のログ全体でポリシーの適用を確認します。

Gemini Enterprise の下り(外向き)

Gemini Enterprise は、Engine の agentGatewaySetting と DataConnector の use_agent_gateway_egress: true の両方が構成されている場合、カスタム MCP サーバー ツール リクエストを Agent Gateway に転送します。

figure2

図 2. Gemini Enterprise の下り(外向き)アーキテクチャ

Gemini Enterprise app は、ツールルーティングを次の 4 つの主要分野に整理します。

  1. ウィジェット(default_search_widget_config):
    • ウェブ クライアント インターフェースを提供します。ウィジェットはユーザーからプロンプトを受け取り、基盤となるエンジンとのチャット セッションを開始します。
  2. コア アシスタント(assistants/default_assistant/agents/default/core_assistant):
    • エンジン内のルート会話型推論エージェント。ユーザー クエリを評価する際、コア アシスタントは算術計算が必要かどうかを判断し、利用可能なツールを検査して、実行を合成された Agent Gateway サブエージェントに委任します。
  3. データストアとデータコネクタ:
    • DataStore: :setUpDataConnector の実行時に専用の Collection 内でプロビジョニングされ、インポートされた Agent Registry ツール スキーマ(add、subtract)、引数の型、エージェントの手順を Gemini Enterprise Engine にリンク(dataStoreIds)します。
    • DataConnector: リモート MCP サーバー(instance_uri)への REGISTRY_MCP アクション接続(createBapConnection: true)を管理し、Agent Registry MCP サーバー リソース(registry_mcp_server_name)を解決して、Agent Gateway 下り(外向き)(use_agent_gateway_egress: true)を有効にします。
  4. Agent Identity、Agent Registry、Agent Gateway:
    • データ コネクタがアウトバウンド ツール呼び出しをディスパッチすると、agentGatewaySetting で指定されたゲートウェイにトラフィックが転送されます。Core Assistant は、自身の ID をアサートする SPIFFE ID トークン principal://agents.global.org-.../agents/default/core_assistant を生成します。
    • Agent Gateway は、registries フィールドを使用して Agent Registry と統合し、宛先エンドポイントと登録済みツールスキーマを動的に解決します。destination.is_registered 属性と destination.agent_registry.* 属性を設定し、VPC ネットワークへの転送を許可する前に、IAM 統合アクセス ポリシー(UAP)CEL ルールに対して評価するために、IAP v2 に渡します。

ゲートウェイ VPC の接続

Agent Gateway は、次の 2 つの YAML フィールドを使用して、プライベート VPC ネットワーク接続を有効にします。

  • networkConfig.egress.networkAttachment: PSC ネットワーク アタッチメントを介して VPC ネットワークにルーティングされるようにプライベート IP トラフィックを転送します。
  • dnsPeeringConfig.domains: VPC ネットワークの Cloud DNS ゾーンで DNS の解決をピアリングします。これにより、ターゲット ホスト名(*.run.app)が VPC ネットワークで定義された限定公開 PSC エンドポイントの IP アドレスに解決されます。

制限事項と要件

  • StreamableHTTP のみ: 以前のサーバー送信イベント(SSE)転送はサポートされていません。MCP サーバーは StreamableHTTP を使用する必要があります。
  • Public CA TLS が必要: MCP エンドポイントは、PSC 経由で非公開でアクセスする場合でも、Public CA によって署名された TLS 証明書を使用する必要があります。
  • 組織のポリシーのオーバーライド: データストアを登録する前に、カスタム MCP データストアの組織のポリシーを明示的にオーバーライドする必要があります。

これでコンセプトの説明は終わりです。次は セットアップ セクションに進みます。

3. セットアップ

必要な IAM のロール

Codelab を完了するには、次のロールが必要です。

ドメイン

必要な IAM のロール

プロジェクトと IAM

roles/orgpolicy.policyAdmin
roles/resourcemanager.projectIamAdmin
roles/iam.accessPolicyAdmin
roles/serviceusage.serviceUsageAdmin
roles/iam.serviceAccountUser

ネットワーキングとゲートウェイ

roles/networkservices.admin
roles/networksecurity.admin
roles/serviceextensions.admin
roles/compute.networkAdmin
roles/dns.admin

Gemini Enterprise と Registry

roles/discoveryengine.admin
roles/agentregistry.admin(または roles/apphub.admin)

ワークロードとビルド

roles/run.admin
roles/cloudbuild.builds.editor
roles/artifactregistry.writer
roles/storage.admin

オブザーバビリティ

roles/logging.viewer
roles/logging.logWriter

または、roles/owner などの広範な基本ロールを roles/orgpolicy.policyAdmin と組み合わせて使用します(roles/owner 単独では組織ポリシーを変更できないため)。

プロジェクトにアクセスする

この Codelab では、1 つの Google Cloud プロジェクトを使用します。構成手順では、gcloud CLI と Linux シェルコマンドを使用します。

まず、Google Cloud プロジェクトのコマンドラインにアクセスします。

プロジェクト ID を設定する

gcloud config set project SET_YOUR_PROJECT_ID_HERE

セッションを認証する

# login to gcloud cli
gcloud auth login
# login for gcloud api
gcloud auth application-default login

シェル環境変数を設定する

# set custom var for slug (eg, "foo") and region preference
export SLUG="foo"
export REGION="us-central1"

echo ${SLUG}
echo ${REGION}
# create project vars (automatic)
export PROJ_ID=$(gcloud config list --format="value(core.project)")
export PROJ_NO=$(gcloud projects describe ${PROJ_ID} --format="value(projectNumber)")
export ORG_ID=$(gcloud projects get-ancestors ${PROJ_ID} --format="value(id)" | tail -n 1)
export USER_IDENTITY=$(gcloud config get-value account)

echo ${PROJ_ID}
echo ${PROJ_NO}
echo ${ORG_ID}
echo ${USER_IDENTITY}
# create resource vars for agent platform (automatic)
export AGW_NAME="agw-${SLUG}-${REGION}-ata"
export AGW_URI="projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
export UAP_POLICY_NAME="uap-policy-${SLUG}"
export UAP_BINDING_NAME="uap-binding-${SLUG}"
export MCP_NAME="math-wizard"
export MCP_URL="https://${MCP_NAME}-${PROJ_NO}.${REGION}.run.app/mcp"

echo ${AGW_NAME}
echo ${AGW_URI}
echo ${UAP_POLICY_NAME}
echo ${UAP_BINDING_NAME}
echo ${MCP_NAME}
echo ${MCP_URL}
# create resource vars for gemini enterprise (automatic)
export GE_APP_DISPLAY_NAME="Codelab app"
export GE_APP_ORG_NAME="${SLUG}, Inc."
export GE_LOCATION="global"
export GE_APP_NAME="app-${SLUG}-${GE_LOCATION}"
export GE_APP_INIT="${GE_APP_NAME}_$(date +%s)"

echo ${GE_APP_DISPLAY_NAME}
echo ${GE_APP_ORG_NAME}
echo ${GE_LOCATION}
echo ${GE_APP_NAME}
echo ${GE_APP_INIT}

エージェント ID の信頼できるドメインを設定する

if-then-else ステートメントは、プリンシパル エージェント ID の正しい信頼ドメインを設定するために、プロジェクトが組織に属しているかどうかを確認します。

# set var for trust domain
if [[ -n "${ORG_ID}" ]]; then
  export TRUST_DOMAIN="agents.global.org-${ORG_ID}.system.id.goog"
else
  export TRUST_DOMAIN="agents.global.proj-${PROJ_NO}.system.id.goog"
fi

echo "trust domain: ${TRUST_DOMAIN}"

請求先プロジェクトと割り当てプロジェクトを設定する

# set cli quota project
gcloud config set billing/quota_project ${PROJ_ID}
# set api quota project
gcloud auth application-default set-quota-project ${PROJ_ID}

構成ファイル用のローカル ディレクトリを作成する

# create config folder
mkdir -p cfg

Google Cloud SDK のセルフマネージド インストール(Cloud Shell の外部など)を実行している場合は、コンポーネントを最新バージョンに更新します。

# update gcloud cli
gcloud components update

API サービスを有効にする

# enable google apis (part 1)
gcloud services enable \
  agentregistry.googleapis.com \
  agentidentity.googleapis.com \
  aiplatform.googleapis.com \
  apphub.googleapis.com \
  apptopology.googleapis.com \
  cloudapiregistry.googleapis.com \
  cloudtrace.googleapis.com \
  compute.googleapis.com \
  dataform.googleapis.com \
  iam.googleapis.com \
  iap.googleapis.com \
  logging.googleapis.com \
  modelarmor.googleapis.com \
  monitoring.googleapis.com \
  networksecurity.googleapis.com \
  networkservices.googleapis.com \
  notebooks.googleapis.com \
  observability.googleapis.com
# enable google apis (part 2)
gcloud services enable \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com \
  discoveryengine.googleapis.com \
  dns.googleapis.com \
  orgpolicy.googleapis.com \
  run.googleapis.com \
  saasservicemgmt.googleapis.com \
  securitycenter.googleapis.com \
  storage.googleapis.com \
  telemetry.googleapis.com \
  texttospeech.googleapis.com

組織のポリシー

デフォルトの Google Cloud のマネージド組織のポリシーの制約により、この Codelab で使用される機能が制限されます。

  • discoveryengine.managed.disableCustomMcpServerConnector:
    • カスタム MCP サーバー(custom_mcp)をデータソースとして使用するデータコネクタの作成を制限します(デフォルトで適用されます)。
  • iam.managed.disableAccessPolicyBinding:
    • IAM v3 アクセス ポリシー バインディングをリソースに制限します(デフォルトで適用されます)。
  • discoveryengine.managed.allowedEgressFqdns:
    • VPC Service Controls(VPC-SC)が有効になっている場合、またはプロジェクトが組織の enforcedProjects パラメータに登録されている場合に、データコネクタのアウトバウンド下り(外向き)ドメイン(instance_uri FQDN)を制限します。
  • discoveryengine.managed.allowedDataSources:
    • VPC-SC が有効になっている場合、またはプロジェクトが組織の enforcedProjects パラメータにリストされている場合に、許可されるデータコネクタ タイプ(dataSource)を制限します。

enforce: false を明示的に設定して、プロジェクト レベルで継承された組織のポリシーの制限をオーバーライドします。

カスタム MCP 制約を無効にする

# disable data connector constraint (allow custom mcp servers)
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJ_NO}/policies/discoveryengine.managed.disableCustomMcpServerConnector
spec:
  rules:
  - enforce: false
EOF
# verify org policy constraint on project
gcloud org-policies describe discoveryengine.managed.disableCustomMcpServerConnector \
  --project=${PROJ_ID} --effective

アクセス ポリシーの制約を無効にする

# disable iam v3 constraint (allow v3 access policies)
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJ_NO}/policies/iam.managed.disableAccessPolicyBinding
spec:
  rules:
  - enforce: false
EOF
# verify org policy constraint on project
gcloud org-policies describe iam.managed.disableAccessPolicyBinding \
  --project=${PROJ_ID} --effective

条件付きデータ コネクタの制約を確認して無効にする

デフォルトでは、discoveryengine.managed.allowedEgressFqdns と discoveryengine.managed.allowedDataSources は、プロジェクトが VPC Service Controls(VPC SC)境界内にある場合、または組織の管理者がプロジェクトを enforcedProjects に追加した場合にのみ、コネクタの作成をブロックします。

まず、プロジェクトで有効なポリシーを確認します。

# check effective egress fqdn constraint on project
gcloud org-policies describe discoveryengine.managed.allowedEgressFqdns \
  --project=${PROJ_ID} --effective
# check effective data source constraint on project
gcloud org-policies describe discoveryengine.managed.allowedDataSources \
  --project=${PROJ_ID} --effective

~~IF~~ これらの制約が適用されている場合、VPC SC またはポリシーで制限された組織で custom_mcp コネクタの設定がブロックされないようにするには、プロジェクトの両方のポリシーで enforce: false を設定します。

# disable egress fqdn constraint on project
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJ_NO}/policies/discoveryengine.managed.allowedEgressFqdns
spec:
  rules:
  - enforce: false
EOF
# disable allowed data sources constraint on project
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJ_NO}/policies/discoveryengine.managed.allowedDataSources
spec:
  rules:
  - enforce: false
EOF
# verify both constraints are disabled on project
gcloud org-policies describe discoveryengine.managed.allowedEgressFqdns \
  --project=${PROJ_ID} --effective

gcloud org-policies describe discoveryengine.managed.allowedDataSources \
  --project=${PROJ_ID} --effective

IAM の権限

必要な IAM ロールを、ユーザー アカウントと Cloud Build で使用される Compute Engine のデフォルト サービス アカウントに付与します。

  • ユーザー アカウント(${USER_IDENTITY}):
    • Cloud Run サービスのデプロイと呼び出し(roles/run.admin、roles/run.invoker、roles/iam.serviceAccountUser)、コンテナ イメージのビルド(roles/cloudbuild.builds.editor)、Gemini Enterprise の管理(roles/discoveryengine.admin)、統合アクセス ポリシーの作成(roles/iam.accessPolicyAdmin)を行う権限が必要です。
  • Compute Engine のデフォルトのサービス アカウント(${PROJ_NO}-compute@developer.gserviceaccount.com):
    • Cloud Build が Cloud Storage でソースコードをステージング(roles/storage.admin)、Artifact Registry にイメージを push(roles/artifactregistry.writer)、ビルドログを書き込み(roles/logging.logWriter)するために使用されます。

次のコマンドを実行して、ロール バインディングを割り当てます。

# grant roles to user account
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/run.admin"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/iam.serviceAccountUser"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/run.invoker"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/discoveryengine.admin"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/iam.accessPolicyAdmin"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/cloudbuild.builds.editor"
# grant roles to default compute (cloud build) service account
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --role="roles/storage.admin"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --role="roles/artifactregistry.writer"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --role="roles/logging.logWriter"

IAM 権限を確認する

ユーザー アカウントに 6 つの(6)ロール バインディングがあるかどうかを確認します。

# show iam policy on project for user account
gcloud projects get-iam-policy ${PROJ_ID} \
  --flatten="bindings[].members" \
  --filter="bindings.members:${USER_IDENTITY}" \
  --format="table(bindings.role:label=ROLE, bindings.members:label=PRINCIPAL_IDENTITY)"

デフォルトのコンピューティング サービス アカウントに 3 つの(3)ロール バインディングがあることを確認します。

# show iam policy on project for default compute service account
gcloud projects get-iam-policy ${PROJ_ID} \
  --flatten="bindings[].members" \
  --filter="bindings.members:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --format="table(bindings.role:label=ROLE, bindings.members:label=PRINCIPAL_IDENTITY)"

サービス エージェントのバインディングを確認する(予防措置)

新しいプロジェクトでは、networkservices.googleapis.com が最初に有効になったときに、Google Cloud が Agent Gateway サービス エージェントを自動的にプロビジョニングし、roles/agentgateway.serviceAgent を付与します。以前のクリーンアップでデフォルトのサービス エージェント バインディングが削除されている可能性がある既存のプロジェクトを再利用する場合は、次のコマンドをフェイルセーフとして実行し、ID とロール バインディングがそのまま残っていることを確認します。

# ensure network services service account has been created
gcloud beta services identity create \
  --service=networkservices.googleapis.com \
  --project="${PROJ_ID}"

# ensure network services service account has service agent roles applied
gcloud projects add-iam-policy-binding "${PROJ_ID}" \
  --member="serviceAccount:service-${PROJ_NO}@gcp-sa-agentgateway.iam.gserviceaccount.com" \
  --role="roles/agentgateway.serviceAgent"

これでセットアップは完了です。次は [ネットワーク] セクションに進みます。

4. ネットワーク

このセクションでは、専用の /28 サブネット(192.168.10.0/28)を使用して カスタムモードで VPC ネットワークをデプロイします。このサブネットは、VPC ネットワークへの Agent Gateway ネットワーク下り(内向き)の PSC ネットワーク アタッチメントをサポートしています。

Google API の PSC エンドポイントは、単一の /32グローバル内部 IPv4 アドレス(172.16.20.20)を使用してデプロイされ、Google API とサービスへのプライベート内部アクセスをサポートします。この Codelab では、Agent Gateway は Cloud DNS ピアリングで run.app. ドメインを解決し、PSC エンドポイントを使用して Cloud Run をターゲットにします。

ネットワークを作成する

グローバル VPC ネットワークを作成します。

# create vpc network
gcloud compute networks create vnet-${SLUG} --subnet-mode=custom

Agent Gateway PSC ネットワーク アタッチメントのサブネットを作成します。

# create subnet for agent gateway psc na
gcloud compute networks subnets create subnet-${REGION}-agw \
  --network=vnet-${SLUG} \
  --range=192.168.10.0/28 \
  --region=${REGION} \
  --enable-private-ip-google-access

ファイアウォール ルールの作成

ロギングが有効になっているすべての下り(外向き)トラフィックを許可するファイアウォール ポリシーを作成します。これは、Agent Gateway から VPC ネットワークに送信されるトラフィックをモニタリングするために使用されます。Cloud NGFW は、ネットワーク セキュリティとトラフィック モニタリングの両方でエッセンシャル ティアとスタンダード ティアをサポートしています。

# create fw policy
gcloud compute network-firewall-policies create fw-policy-${SLUG} --global
# create fw policy rule
gcloud compute network-firewall-policies rules create 1001 \
  --description="allow all out and log" \
  --firewall-policy=fw-policy-${SLUG} \
  --global-firewall-policy \
  --action=allow \
  --direction=EGRESS \
  --layer4-configs=all \
  --dest-ip-ranges=0.0.0.0/0 \
  --enable-logging
# bind fw policy to network
gcloud compute network-firewall-policies associations create \
  --name=fw-policy-bind-${SLUG} \
  --firewall-policy=fw-policy-${SLUG} \
  --network=vnet-${SLUG} \
  --global-firewall-policy

PSC ネットワーク アタッチメントを作成する

Agent Gateway からの接続を自動的に受け入れるように構成された Private Service Connect(PSC)ネットワーク アタッチメントを作成します。ネットワーク アタッチメントは、アウトバウンド下り(外向き)トラフィック用に、Agent Gateway のプロデューサー側と安全にリンクする接続のコンシューマー VPC ネットワーク側を確立します。サブネットの要件と IP 範囲の仕様の詳細については、VPC 接続を構成するをご覧ください。

# create psc network attachment
gcloud compute network-attachments create psc-na-${REGION}-agw \
  --region=${REGION} \
  --subnets=subnet-${REGION}-agw \
  --connection-preference=ACCEPT_AUTOMATIC

PSC ネットワーク アタッチメントを確認する

# show psc network attachment details
gcloud compute network-attachments describe psc-na-${REGION}-agw --region=${REGION}

PSC ネットワーク アタッチメントのリソース URI を取得し、PSC_NA_URI 環境変数に保存します。この URI は、Agent Gateway 構成(networkConfig.egress.networkAttachment)で参照され、VPC ネットワークへのネットワーク下り(外向き)用の PSC インターフェースをプロビジョニングします。

# fetch psc network attachment uri
export PSC_NA_URI=$(gcloud compute network-attachments describe psc-na-${REGION}-agw \
  --region=${REGION} \
  --format="value(selfLink.scope(v1))")
echo ${PSC_NA_URI}

PSC エンドポイントを作成する

Google API 用の Private Service Connect(PSC)エンドポイントは、Agent Gateway で使用され、トラフィックをパブリック インターネットに公開することなく、内部ネットワーク パスを介して Cloud Run MCP サーバーへのプライベート接続を確立します。Agent Gateway から VPC ネットワークに送信されるアウトバウンド ツール呼び出しは、ターゲット Cloud Run サービス URL(*.run.app)をこのプライベート エンドポイントの IP アドレスに解決します。

PSC エンドポイントにグローバル内部 IPv4 アドレスを予約します。選択する IP アドレスは、VPC ネットワーク内の既存のサブネットと重複しない /32 アドレスである必要があります。

# set env var for psc ep ip address
export PSC_EP_IP="172.16.20.20"
echo ${PSC_EP_IP}
# reserve internal global ipv4 address
gcloud compute addresses create ip-psc2gapis \
  --global \
  --purpose=PRIVATE_SERVICE_CONNECT \
  --addresses=${PSC_EP_IP} \
  --network=vnet-${SLUG}

all-apis バンドルを使用して、Google API の PSC エンドポイントを作成します。このバンドルには Cloud Run が含まれています(run.app)。

# create psc endpoint for google apis
gcloud compute forwarding-rules create psc2gapis \
  --global \
  --network=vnet-${SLUG} \
  --address=ip-psc2gapis \
  --target-google-apis-bundle=all-apis

PSC エンドポイントを確認する

# show psc endpoint details
gcloud compute forwarding-rules describe psc2gapis --global

DNS ゾーンとレコードを作成する

Cloud DNS は、Agent Gateway が Cloud Run でホストされている MCP サーバーとプライベートに通信できるようにするために使用されます。Agent Gateway が Cloud Run をターゲットとするアウトバウンド ツール リクエストを評価するときに、DNS ピアリング(dnsPeeringConfig.domains)を使用して、VPC ネットワークに関連付けられたプライベート Cloud DNS ゾーンを使用して *.run.app の DNS クエリを解決します。プライベート DNS レコードは、内部 PSC エンドポイント IP アドレス(172.16.20.20)でクエリを返します。これにより、MCP ツールのリクエストをプライベート ネットワーク パス経由でルーティングできます。

run.app. ドメインの限定公開 Cloud DNS マネージド ゾーンを作成します。

# create private dns zone
gcloud dns managed-zones create priv-zone-run \
  --description="private zone for run.app" \
  --dns-name="run.app." \
  --visibility=private \
  --networks=vnet-${SLUG}

PSC エンドポイントの IP アドレスを指す *.run.app. のワイルドカード DNS A レコードを作成します。

# create dns record
gcloud dns record-sets create "*.run.app." \
  --zone=priv-zone-run \
  --type=A \
  --ttl=300 \
  --rrdatas=${PSC_EP_IP}

DNS クエリロギングを有効にする Cloud DNS ポリシーを作成します。DNS ロギングは、VPC ネットワーク内の Agent Gateway から発信されたドメイン解決リクエストをキャプチャし、監査可能性を提供します。また、*.run.app ツールのリクエストが内部 PSC エンドポイントに正しく解決されることを確認できます。

# create dns policy (logging)
gcloud dns policies create dns-policy-${SLUG} \
  --description="dns logging for vnet-${SLUG}" \
  --networks=vnet-${SLUG} \
  --enable-logging

ネットワークに関する説明は以上です。次は Agent Gateway セクションに進みます。

5. Agent Gateway

Agent Gateway は、限定公開 VPC 接続の PSC ネットワーク アタッチメントと DNS ピアリング設定を構成する networkConfig フィールドとともに、Agent Registry インスタンスの registries を指定します。

  • registries: ゲートウェイを最大 2 つの Agent Registry インスタンス(1 つはリージョン(../locations/${REGION})、1 つはグローバル(../locations/global))に関連付けます。これにより、Agent Gateway が Agent Registry と統合され、きめ細かい IAP v2 ポリシーの適用のため、リージョン デプロイ(${REGION} の Cloud Run MCP サーバーなど)とグローバル リソース(Gemini Enterprise エージェントやグローバル エンドポイントなど)の両方が解決されます。宛先 URL を解決する際、地域エントリはグローバル エントリよりも優先されます。
  • networkAttachment: PSC ネットワーク アタッチメント(psc-na-${REGION}-agw)を指し、プライベート エグレス用に Agent Gateway を VPC ネットワークに接続します。
  • dnsPeeringConfig.domains: Cloud Run サービスの Agent Gateway から発信された DNS クエリが DNS ピアリングを使用して、Cloud DNS プライベート ゾーンで構成されたプライベート Google API PSC エンドポイント IP アドレス(172.16.20.20)にホスト名を解決するように run.app. を構成します。

Agent Gateway をデプロイする

Agent Gateway 構成ファイルを作成してインポートします。

# create agent gateway config file
cat > cfg/${AGW_NAME}-networkConfig.yaml << EOF
name: ${AGW_NAME}
protocols:
  - MCP
googleManaged:
  governedAccessPath: AGENT_TO_ANYWHERE
registries:
  - "//agentregistry.googleapis.com/projects/${PROJ_ID}/locations/${REGION}"
networkConfig:
  egress:
    networkAttachment: ${PSC_NA_URI}
  dnsPeeringConfig:
    domains:
      - run.app.
    targetProject: ${PROJ_ID}
    targetNetwork: projects/${PROJ_ID}/global/networks/vnet-${SLUG}
EOF
# import agent gateway config file (create gateway)
gcloud network-services agent-gateways import ${AGW_NAME} \
  --source="cfg/${AGW_NAME}-networkConfig.yaml" \
  --location=${REGION}

Agent Gateway のデプロイを確認する

エージェント レジストリとネットワーク構成を確認します。

# show agent gateway registries and network config
gcloud network-services agent-gateways describe ${AGW_NAME} \
  --location=${REGION} \
  --format="yaml(registries,networkConfig)"

想定される出力:

networkConfig:
  dnsPeeringConfig:
    domains:
    - run.app.
    targetNetwork: projects/${PROJ_ID}/global/networks/vnet-${SLUG}
    targetProject: ${PROJ_ID}
  egress:
    networkAttachment: projects/${PROJ_ID}/regions/${REGION}/networkAttachments/psc-na-${REGION}-agw
registries:
- //agentregistry.googleapis.com/projects/${PROJ_ID}/locations/${REGION}

出力に必要な構成の詳細が表示されていることを確認します。

  • registries: ゲートウェイに関連付けられているリージョン(${REGION})Agent Registry URI を一覧表示します。
  • egress.networkAttachment: VPC 下り(外向き)の PSC ネットワーク アタッチメント URI を指定します。
  • dnsPeeringConfig.domains: プライベート ドメイン解決用の targetNetwork を指す run.app. が含まれます。

PSC ネットワーク アタッチメントを調べて、ゲートウェイ接続を確認します。

# show psc network attachment details
gcloud compute network-attachments describe psc-na-${REGION}-agw \
  --region=${REGION} \
  --format="yaml(connectionEndpoints)"

承認済みの接続エンドポイントがあることを確認します。

connectionEndpoints:
- ipAddress: 192.168.10.2
  projectIdOrNum: '<AGW_TENANT_PROJ_NO>'
  status: ACCEPTED
  subnetwork: https://www.googleapis.com/compute/v1/projects/${PROJ_ID}/regions/${REGION}/subnetworks/subnet-${REGION}-agw

認可を委任する

Agent Gateway は、Identity-Aware Proxy(IAP)統合アクセス ポリシー(UAP)と統合された認可ポリシー(networksecurity.authzPolicies)を使用して、アウトバウンド ツール トラフィックを保護し、管理します。

Agent Gateway は基本的なインライン ALLOW ルールと DENY ルールをサポートしていますが、エンタープライズ環境では一元化された ID 中心のガバナンスが必要です。IAM 統合アクセス ポリシー(またはアクセス ポリシー)を使用すると、標準の IAM v3 アクセス ポリシーを使用して下り(外向き)アクセスルールを管理できます。

figure3

図 3. 認可アーキテクチャ

認可フローは次の 3 つのコンポーネントを接続します。

  1. Gateway 認可ポリシー(authzPolicy):
    • Agent Gateway をターゲットとするリージョン リソース。
    • policyProfile: REQUEST_AUTHZ と action: CUSTOM で構成され、すべての送信承認チェックを IAP Authz 拡張機能に転送します。
  2. IAP サービス拡張機能(authzExtension):
    • リクエストの認可を Identity-Aware Proxy(iap.googleapis.com)に委任するリージョン リソース。
    • ポリシー バージョン V2 を使用して ENFORCE モードでポリシーを評価します。
  3. IAM 統合アクセス ポリシーとバインディング(accessPolicy と policyBinding):
    • きめ細かいアクセスルールを含むグローバル IAM v3 リソース。
    • 呼び出し元エージェントの SPIFFE プリンシパル ID を認証し、ユニバーサル iap.googleapis.com/resources.egressViaIAP 権限を確認し、宛先属性に対して Common Expression Language(CEL)条件を評価します。

認可拡張機能をデプロイする

認可の判断を IAP サービスに委任する service-extensions 認可拡張機能の構成を作成します。

# create authz extension config file
cat > cfg/${AGW_NAME}-svc-ext-authz-iap.yaml << EOF
name: ${AGW_NAME}-svc-ext-authz-iap
service: iap.googleapis.com
failOpen: false
timeout: 1s
metadata:
  iapPolicyVersion: "V2"
EOF
# import iap authz extension (create authz extension)
gcloud service-extensions authz-extensions import ${AGW_NAME}-svc-ext-authz-iap \
  --source=cfg/${AGW_NAME}-svc-ext-authz-iap.yaml \
  --location=${REGION}

認可拡張機能を確認する

認可拡張機能が有効になっていることを確認します。

# list authz extensions
gcloud service-extensions authz-extensions list \
  --location=${REGION} \
  --format="table(
    name.basename():label=NAME,
    createTime.date(tz=LOCAL):label=CREATED,
    updateTime.date(tz=LOCAL):label=MODIFIED,
    service:label=SERVICE,
    metadata:label=METADATA,
    timeout:label=TIMEOUT
  )"

認可ポリシーをデプロイする

Agent Gateway をターゲットとし、リクエストの検証を IAP の認可拡張機能に委任する network-security 認可ポリシー構成を作成します。

# create authz policy config file
cat > cfg/${AGW_NAME}-authz-policy-iap.yaml << EOF
name: ${AGW_NAME}-authz-policy-iap
target:
  resources:
    - "projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
policyProfile: REQUEST_AUTHZ
action: CUSTOM
customProvider:
  authzExtension:
    resources:
      - "projects/${PROJ_ID}/locations/${REGION}/authzExtensions/${AGW_NAME}-svc-ext-authz-iap"
EOF
# import authz policy config file (create authz policy)
gcloud network-security authz-policies import ${AGW_NAME}-authz-policy-iap \
  --source=cfg/${AGW_NAME}-authz-policy-iap.yaml \
  --location=${REGION}

認可ポリシーを確認する

認可ポリシーが有効になっていることを確認します。

# list authz policies
gcloud network-security authz-policies list \
  --location=${REGION} \
  --format="table(
    name.basename():label=NAME,
    action:label=ACTION,
    customProvider.list().sub('\W.*', ''):label=CUSTOM_PROVIDER_TYPE,
    policyProfile:label=POLICY_PROFILE,
    customProvider.authzExtension.resources[0].basename():label=CUSTOM_PROVIDER_RESOURCE
  )"

IAM アクセス ポリシーを作成する

Agent Gateway は、認可チェックを IAP に委任し、Agent Registry から宛先メタデータを解決するようになりました。次に、アウトバウンド ツールの実行を制御する IAM 統合アクセス ポリシー ルールを定義します。

IAP は、次の Agent Registry の宛先属性に対して CEL 属性式を評価します。

  • 登録ステータス(destination.is_registered):
    • 宛先が Agent Registry にカタログ登録されているかどうかを示すブール値(true/false)。
  • MCP サーバー名(destination.agent_registry.mcp_server.name):
    • Agent Registry に登録されている正規の MCP サーバー リソース名。
  • MCP メソッド(destination.agent_registry.mcp_server.method):
    • 呼び出される MCP メソッド(tools/call、tools/list、initialize など)。
  • ツール名(destination.agent_registry.mcp_server.tool.name):
    • 呼び出された特定のツール名(subtract や add など)。登録された MCP サーバーで、ツールレベルのきめ細かい認可を有効にします。

IAM アクセス ポリシー ルールを定義する

IAM ポリシー ルール マニフェストでは、次の項目を指定します。

  • プリンシパル: Gemini Enterprise コア アシスタント エージェントを表す SPIFFE プリンシパル ID。
  • 権限: すべての IAP 管理下の下り(外向き)トラフィックに必要なユニバーサル iap.googleapis.com/resources.egressViaIAP 権限。
  • 条件: エージェントが Agent Registry にカタログ登録されているエンドポイントのみを呼び出すことができるようにする CEL 式(destination.is_registered == true)。

ポリシー ルール マニフェスト ファイルを作成します。

# create access policy rule file
cat > cfg/${UAP_POLICY_NAME}-rules.json << EOF
[
  {
    "description": "allow ge assistant to any registered service",
    "effect": "ALLOW",
    "principals": [
      "principal://${TRUST_DOMAIN}/resources/discoveryengine/projects/${PROJ_NO}/locations/global/engines/${GE_APP_INIT}/assistants/default_assistant/agents/default/core_assistant"
    ],
    "operation": {
      "permissions": [
        "iap.googleapis.com/resources.egressViaIAP"
      ]
    },
    "conditions": {
      "iap.googleapis.com": {
        "expression": \
        "destination.is_registered == true"
      }
    }
  }
]
EOF

IAM アクセス ポリシーをデプロイする

マニフェスト ファイルで定義されたルールを使用して、グローバル IAM アクセス ポリシーを作成します。

# create iam access policy
gcloud iam access-policies create ${UAP_POLICY_NAME} \
  --details-rules=cfg/${UAP_POLICY_NAME}-rules.json \
  --project=${PROJ_ID} \
  --location=global

IAM アクセス ポリシーを確認する

IAM アクセス ポリシーが正常に作成されたことを確認し、ルールの詳細を調べます。

# show iam access policy details
gcloud iam access-policies describe ${UAP_POLICY_NAME} \
  --project=${PROJ_ID} \
  --location=global

想定される出力:

details:
  rules:
  - conditions:
      iap.googleapis.com:
        expression: destination.is_registered == true
    description: allow ge assistant to any registered service
    effect: ALLOW
    operation:
      permissions:
      - iap.googleapis.com/resources.egressViaIAP
    principals:
    - principal://agents.global.org-${ORG_ID}.system.id.goog/resources/discoveryengine/projects/${PROJ_NO}/locations/global/engines/${GE_APP_INIT}/assistants/default_assistant/agents/default/core_assistant
name: projects/${PROJ_ID}/locations/global/accessPolicies/${UAP_POLICY_NAME}

IAM アクセス ポリシーをプロジェクトにバインドする

プロジェクト内のすべてのエージェント ゲートウェイで適用を有効にするには、IAM アクセス ポリシーをプロジェクト リソースに関連付けるポリシー バインディングを作成します。

# bind iam access policy to project resource
gcloud iam policy-bindings create ${UAP_BINDING_NAME} \
  --policy="projects/${PROJ_ID}/locations/global/accessPolicies/${UAP_POLICY_NAME}" \
  --target-resource="//cloudresourcemanager.googleapis.com/projects/${PROJ_ID}" \
  --project=${PROJ_ID} \
  --location=global

IAM アクセス ポリシー バインディングを確認する

アクティブなポリシー バインディングが正しいポリシーとターゲットを指していることを確認します。

# show policy binding details
gcloud iam policy-bindings describe ${UAP_BINDING_NAME} \
  --project=${PROJ_ID} \
  --location=global

想定される出力:

name: projects/${PROJ_ID}/locations/global/policyBindings/${UAP_BINDING_NAME}
policy: projects/${PROJ_ID}/locations/global/accessPolicies/${UAP_POLICY_NAME}
policyKind: ACCESS
target:
  resource: //cloudresourcemanager.googleapis.com/projects/${PROJ_ID}

これでエージェント ゲートウェイの説明は終わりです。次は MCP サーバーのセクションに進みます。

6. MCP サーバー

このセクションでは、add ツールと subtract ツールを公開するカスタム FastMCP サーバーを作成し、ソースから Cloud Run に直接デプロイします。ソースのデプロイ(--source)中に、Cloud Build は、含まれている Dockerfile と uv を使用してコンテナ イメージをパッケージ化します(pyproject.toml で定義された依存関係をインストールし、server.py を起動します)。

Cloud Run サービスがデプロイされたら、MCP サーバーをツール仕様(toolspec.json)とともに Agent Registry に登録します。これにより、Gemini Enterprise はツールを検出して呼び出すことができます。

MCP サーバー アプリケーションを作成する

アプリケーション コード用の math-wizard プロジェクト ディレクトリを作成します。

# create directory for code
mkdir -p math-wizard

Python プロジェクト マニフェスト ファイルを記述します。

# create python project manifest file
cat > math-wizard/pyproject.toml << 'EOF'
[project]
name = "math-wizard"
version = "0.1.0"
description = "math wizard mcp server"
requires-python = ">=3.12"
dependencies = [
    "fastmcp==2.13.1",
]
EOF

Cloud Logging と Cloud Trace の検証のために、受信 HTTP ヘッダー(mcp-session-id、x-forwarded-for、user-agent、x-cloud-trace-context)をキャプチャする追加のインストルメンテーション関数がコードに含まれています。

アプリケーション コード ファイルを作成します。

# create mcp server application code
cat > math-wizard/server.py << 'EOF'
import asyncio
import json
import logging
import os
from fastmcp import FastMCP
from fastmcp.server.dependencies import get_http_headers
from mcp.types import ToolAnnotations

logger = logging.getLogger(__name__)
logging.basicConfig(format="[%(levelname)s]: %(message)s", level=logging.INFO)

mcp = FastMCP("math wizard mcp server")

def log_network_context(tool_name: str, a: int, b: int) -> None:
    headers = get_http_headers()
    print(json.dumps({
        "severity": "INFO",
        "message": f">>> 🛠️ Tool: '{tool_name}' called with numbers '{a}' and '{b}'",
        "tool": tool_name,
        "mcp_session_id": headers.get("mcp-session-id"),
        "x_forwarded_for": headers.get("x-forwarded-for"),
        "user_agent": headers.get("user-agent"),
        "trace_header": headers.get("x-cloud-trace-context"),
    }), flush=True)

@mcp.tool(
    annotations=ToolAnnotations(
        readOnlyHint=True,
    )
)
def add(a: int, b: int) -> int:
    """Use this to add two numbers together.

    Args:
        a: The first number.
        b: The second number.

    Returns:
        The sum of the two numbers.
    """
    logger.info(f">>> 🛠️ Tool: 'add' called with numbers '{a}' and '{b}'")
    log_network_context("add", a, b)
    return a + b

@mcp.tool(
    annotations=ToolAnnotations(
        readOnlyHint=True,
    )
)
def subtract(a: int, b: int) -> int:
    """Use this to subtract two numbers.

    Args:
        a: The first number.
        b: The second number.

    Returns:
        The difference of the two numbers.
    """
    logger.info(f">>> 🛠️ Tool: 'subtract' called with numbers '{a}' and '{b}'")
    log_network_context("subtract", a, b)
    return a - b

if __name__ == "__main__":
    logger.info(f"🚀 MCP server started on port {os.getenv('PORT', 8080)}")
    asyncio.run(
        mcp.run_async(
            transport="streamable-http",
            host="0.0.0.0",
            port=int(os.getenv("PORT", 8080)),
        )
    )
EOF

Dockerfile を作成して、コンテナ イメージのビルド手順と起動コマンドを定義します。

# create dockerfile
cat > math-wizard/Dockerfile << 'EOF'
# use official python 3.12 image
FROM python:3.12-slim

# install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

# install the project into /app
COPY . /app
WORKDIR /app

# allow statements and log messages to immediately appear in the logs
ENV PYTHONUNBUFFERED=1

# install dependencies
RUN uv sync

EXPOSE 8080

# run the mcp server
CMD ["uv", "run", "server.py"]
EOF

Cloud Run にサービスをデプロイする

Cloud Build(プロジェクトのデフォルトのコンピューティング サービス アカウント ${PROJ_NO}-compute@developer.gserviceaccount.com を使用)を使用して、ソースから MCP サーバーをデプロイします。

# deploy cloud run service
gcloud run deploy ${MCP_NAME} \
  --source math-wizard \
  --region=${REGION} \
  --no-invoker-iam-check \
  --ingress=internal \
  --quiet

Cloud Run のデプロイを確認する

Cloud Run サービスの詳細を確認して、アクティブな構成を確認します。

# show cloud run service details
gcloud run services describe ${MCP_NAME} --region=${REGION}

想定される出力:

<snip>
✔ Service math-wizard in region ${REGION}

URL:     https://math-wizard-${PROJ_NO}.${REGION}.run.app
Ingress: internal
Traffic:
  100% LATEST (currently math-wizard-00001-<id>)
</snip>

Agent Registry に MCP サーバーを登録する

Gemini Enterprise が MCP サーバーで使用可能なツールを正確に検出できるようにするには、登録時に Agent Registry にツール仕様ファイル(toolspec.json)を指定する必要があります。

MCP ツールの仕様を作成する

# create tool spec file
cat > cfg/toolspec.json << 'EOF'
{
  "tools": [
    {
      "name": "add",
      "description": "Use this to add two numbers together.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "a": { "type": "integer", "description": "The first number." },
          "b": { "type": "integer", "description": "The second number." }
        },
        "required": ["a", "b"]
      },
      "isReadOnly": true,
      "isDestructive": false,
      "isIdempotent": true,
      "isOpenWorld": false
    },
    {
      "name": "subtract",
      "description": "Use this to subtract two numbers.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "a": { "type": "integer", "description": "The first number." },
          "b": { "type": "integer", "description": "The second number." }
        },
        "required": ["a", "b"]
      },
      "isReadOnly": true,
      "isDestructive": false,
      "isIdempotent": true,
      "isOpenWorld": false
    }
  ]
}
EOF

Agent Registry に MCP サーバーを登録する

# register mcp server in agent registry
gcloud agent-registry services create ${MCP_NAME} \
  --project=${PROJ_ID} \
  --location=${REGION} \
  --display-name="${MCP_NAME}-${PROJ_NO}.${REGION}.run.app" \
  --description="MANDATORY MATH & ARITHMETIC AGENT: You MUST ALWAYS invoke \
this tool for ANY mathematical calculation, addition (+), subtraction (-), \
sum, difference, or arithmetic question (including simple questions like \
'what is 67 + 345?'). NEVER compute arithmetic yourself and NEVER transfer \
math queries to file_and_coding_agent / code interpreter. Always delegate \
every math question to this tool." \
  --mcp-server-spec-type=tool-spec \
  --mcp-server-spec-content=cfg/toolspec.json \
  --interfaces=protocolBinding=JSONRPC,url="${MCP_URL}"

Agent Registry で MCP サーバーを確認する

デプロイされた Cloud Run サービスが、エンドポイント URL と使用可能なツールとともに、リージョンに登録された MCP サーバーとしてリストされていることを確認します。

# list registered mcp servers in agent registry
gcloud agent-registry mcp-servers list \
  --location=${REGION} \
  --project=${PROJ_ID} \
  --format="table(
    name.basename():label=REGISTRY_ID,
    displayName:label=DISPLAY_NAME,
    interfaces[0].url:label=ENDPOINT_URL,
    tools[].name.list():label=TOOLS
  )"

想定される出力:

REGISTRY_ID                                         DISPLAY_NAME                                  ENDPOINT_URL                                              TOOLS
agentregistry-00000000-0000-0000-0012-3456789abcde  math-wizard-${PROJ_NO}.${REGION}.run.app      https://math-wizard-${PROJ_NO}.${REGION}.run.app/mcp      add,subtract

サービス構成仕様を表示して、各ツールの正確なツール定義、入力スキーマ、動作アノテーションが登録されていることを確認します。

# describe mcp server tool specs
gcloud agent-registry services describe ${MCP_NAME} \
  --location=${REGION} \
  --project=${PROJ_ID} \
  --format="yaml(mcpServerSpec.content.tools)"

これで MCP サーバーの説明は終わりです。次は Gemini Enterprise のセクションに進みます。

7. Gemini Enterprise

このセクションでは、Gemini Enterprise アプリと、リンクされたカスタム MCP サーバー データストア リソースを作成して構成します。

ディスカバリー エンジン リソースモデル

Gemini Enterprise app(Discovery Engine API の Engine リソースとして表されます)は、エンドユーザー向けの中央オーケストレーション レイヤと会話インターフェースです。ユーザーのチャット セッションを管理し、生成モデルを企業データに基づいてグラウンディングし、動的ツールの実行を調整します。

Gemini Enterprise アプリは、データストアを介してデータとシステムを操作します。

  • ナレッジ データストア: 検索拡張生成(RAG)用に静的コンテンツ(Cloud Storage、Google ドライブ、BigQuery など)を取り込んでインデックス登録します。
  • データコネクタ(アクション プロバイダ): 動的なサードパーティ製 API またはカスタム API に接続します。カスタム MCP サーバー データストアは、Model Context Protocol(MCP)で定義されたツールを公開し、モデルが会話中に外部関数を動的に呼び出すことを可能にします。

Agent Gateway 経由の下り(外向き)ルーティング

デフォルトでは、Gemini Enterprise はコネクタとツールの実行トラフィックをパブリック ネットワーク経由で転送します。ただし、プライベート VPC ワークロードとゼロトラスト ガバナンスの場合、エンジンは下り(外向き)を Agent Gateway 経由でルーティングするように構成できます。

  • このラボで後ほどカスタム MCP サーバー データストアを作成するときに、データストアの設定で [Route egress through Agent Gateway] を有効にします。
  • これにより、エンジンのアウトバウンド ツール呼び出しがリージョン Agent Gateway にバインドされ、すべての MCP リクエストがアプリの Agent Identity を持ち、IAP と IAM 統合アクセス ポリシー(UAP)を使用してランタイム承認を受け、PSC ネットワーク アタッチメントを介してプライベート VPC に移動します。

Gemini Enterprise アプリを作成する

次のメソッドは、discoveryengine.googleapis.com API を使用して Gemini Enterprise アプリのリソースと構成を作成します。Google Cloud コンソール UI を使用して構成するには、アプリを作成するの手順をご覧ください。

# create engine (ge app)
curl -s -X POST "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines?engineId=${GE_APP_INIT}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "displayName": "${GE_APP_DISPLAY_NAME}",
  "dataStoreIds": [],
  "solutionType": "SOLUTION_TYPE_SEARCH",
  "industryVertical": "GENERIC",
  "appType": "APP_TYPE_INTRANET",
  "searchEngineConfig": {
    "searchTier": "SEARCH_TIER_ENTERPRISE",
    "searchAddOns": [
      "SEARCH_ADD_ON_LLM"
    ]
  },
  "commonConfig": {
    "companyName": "${GE_APP_ORG_NAME}"
  }
}
EOF

アプリの作成を確認する

# fetch engine (ge app) id
export GE_APP_ID=$(curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq -r --arg name "${GE_APP_DISPLAY_NAME}" '.engines[] | select(.displayName==$name) | .name | split("/") | last')

echo "engine (ge app) id: ${GE_APP_ID}"

エンジン詳細を表示して、作成された構成を確認します。

# get engine (ge app) details
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

JSON レスポンスでサーバーによって入力される次のプロパティに注意してください。

  • name: 正規リソースパス(projects/${PROJ_NO}/locations/global/collections/default_collection/engines/${GE_APP_ID})。
  • sessionConfig.sessionManagementPolicy: デフォルトは "VERTEX_AI_MANAGED" です。これにより、マルチターン チャットとツール呼び出しの状態が Agent Platform(旧称 Vertex AI)に保持されます。
  • observabilityConfig.observabilityEnabled: ベースライン指標のデフォルトは true です(詳細なプロンプトとツール ペイロードのロギングは後のステップで有効になります)。

ID プロバイダを有効にする

Gemini Enterprise アプリでエンドユーザー認証の ID プロバイダとして Google Identity を有効にします。

次の方法では、discoveryengine.googleapis.com API を使用して Gemini Enterprise アプリの ID プロバイダを構成します。Google Cloud コンソール UI を使用して構成するには、ID プロバイダを構成するの手順をご覧ください。

# set identity provider
curl -s -X PATCH "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/aclConfig" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "idpConfig": {
    "idpType": "GSUITE"
  }
}
EOF

ID プロバイダを確認する

# show identity provider
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/aclConfig" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

出力 "idpType": "GSUITE" は、Google Identity プロバイダに対応しています。

(省略可)Gemini Enterprise のトライアル ライセンスを有効にする

Gemini Enterprise ライセンスが割り当てられているプロジェクトを使用している場合は、この手順をスキップできます。ライセンスのない新しいプロジェクトを使用している場合は、次の手順に進みます。

ライセンス構成リソースを作成して、Gemini Enterprise ユーザーシートを 30 日間利用できるようにします。これにより、デフォルトのライセンスが新しいトライアルに設定され、ログインしたユーザーに自動的にシートが付与されます。

# configure free trial subscription
curl -s -X POST "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/licenseConfigs?licenseConfigId=free_trial_gemini" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "subscriptionTier": "SUBSCRIPTION_TIER_SEARCH_AND_ASSISTANT",
  "freeTrial": true
}
EOF

ライセンスが適用されたことを確認する

# show license config
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/licenseConfigs/free_trial_gemini" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

"subscriptionTerm": "SUBSCRIPTION_TERM_ONE_MONTH" と "freeTrial": true を確認します。

# verify auto-registration enabled on default user store
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/userStores/default_user_store" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

../free_trial_gemini" と "enableLicenseAutoRegister": true を確認します。

オブザーバビリティ設定を有効にする

Gemini Enterprise アプリ(エンジン)レベルでオブザーバビリティを有効にすると、Metrics Explorer でコア アシスタントと指標データのインタラクションを表示し、Cloud Trace でエンドツーエンドのトレースを関連付けることができます。

# set observability on engine (ge app)
curl -s -X PATCH "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}?updateMask=observabilityConfig" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "observabilityConfig": {
    "observabilityEnabled": true,
    "sensitiveLoggingEnabled": true
  }
}
EOF

オブザーバビリティの設定を確認する

# verify observability is enabled on engine (ge app)
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq '{observabilityConfig: .observabilityConfig}'

"sensitiveLoggingEnabled": true を確認します。

Agent Gateway にバインドする

Gemini Enterprise からのアウトバウンド トラフィックを Agent Gateway 経由でルーティングすると、すべての AI エージェント ツール呼び出しに対して一元化されたゼロトラスト ガバナンスとセキュリティ適用境界が確立されます。

  • 一元化されたポリシー適用: Agent Gateway は、トラフィックがエージェント環境から離れる前に、認可ポリシーとガバナンス制御に対してアウトバウンド ツール リクエストを評価するインライン プロキシとして機能します。
  • プライベート ネットワークの下り(外向き): Gemini Enterprise を Agent Gateway にバインドすると、Cloud Run のプライベート MCP サーバーをターゲットとするツール呼び出しが、パブリック インターネットをバイパスして Private Service Connect(PSC)経由で安全にルーティングされます。
  • 統合された監査機能: 接続されているすべての MCP サーバーと外部ツールで、一元化されたリクエスト ロギング、テレメトリー、監査証跡を提供します。

Gemini Enterprise アプリで agentGatewaySetting を構成すると、エンドユーザーのクエリによって開始されたアウトバウンド ツールとエージェントの呼び出し(Agent Registry からインポートされたカスタム MCP サーバーと A2A エージェントの呼び出しなど)が Agent Gateway を介して自動的にルーティングされます。

エンジン agentGatewaySetting にパッチを適用して有効にします。

# bind engine (ge app) to agent gateway
curl -s -X PATCH "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}?updateMask=agentGatewaySetting.defaultEgressAgentGateway.name" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "agentGatewaySetting": {
    "defaultEgressAgentGateway": {
      "name": "projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
    }
  }
}
EOF

Agent Gateway のバインディングを確認する

アプリの構成を取得して、agentGatewaySetting バインディングを確認します。

# verify engine (ge app) agent gateway configuration
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq '{name: .name, displayName: .displayName, agentGatewaySetting: .agentGatewaySetting}'

想定される出力:

{
  "name": "projects/${PROJ_NO}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}",
  "displayName": "${GE_APP_DISPLAY_NAME}",
  "agentGatewaySetting": {
    "defaultEgressAgentGateway": {
      "name": "projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
    }
  }
}

カスタム MCP サーバーのデータストアを作成する

このセクションでは、カスタム MCP データストアを作成して、MCP サーバーを Gemini Enterprise に接続します。

Discovery Engine API を使用する場合、これは 2 段階のプロセスです。

  1. 作成(:setUpDataConnector): 専用の Collection リソース(${MCP_NAME}-%timestamp-collection)を作成し、DataConnector(custom_mcp)をアタッチして、バッキング DataStore(..._mcp_data)をプロビジョニングします。
  2. 有効化(PATCH .../dataConnector?updateMask=actionConfig): Agent Registry ツールの仕様を使用してコネクタのアクション ランタイム(actionState: "ACTIVE")を有効にし、DataStore(dataStoreIds)を Gemini Enterprise Engine にバインドします。
# fetch mcp server agent registry resource name
export MCP_REGISTRY_URI=$(gcloud agent-registry mcp-servers list \
  --location=${REGION} \
  --project=${PROJ_ID} \
  --filter="displayName:${MCP_NAME}" \
  --format="value(name)")

echo "mcp registry name: ${MCP_REGISTRY_URI}"
echo "mcp url: ${MCP_URL}"

データコネクタを作成する

# create custom mcp data connector from agent registry and link to engine
curl -s -X POST "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}:setUpDataConnector" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "collectionId": "${MCP_NAME}-$(date +%s)-collection",
  "collectionDisplayName": "${MCP_NAME}-collection",
  "dataConnector": {
    "dataSource": "custom_mcp",
    "dataSourceVersion": 1,
    "params": {
      "oauth_access_token": "unused"
    },
    "refreshInterval": "86400s",
    "entities": [
      {
        "entityName": "mcp_data"
      }
    ],
    "connectorModes": [
      "FEDERATED"
    ],
    "actionConfig": {
      "isActionConfigured": true,
      "createBapConnection": true,
      "actionParams": {
        "auth_type": "NO_AUTH",
        "instance_uri": "${MCP_URL}",
        "mcp_server_source": "REGISTRY_MCP",
        "registry_mcp_server_name": "${MCP_REGISTRY_URI}",
        "mcp_agent_instructions": "MANDATORY MATH & ARITHMETIC AGENT: Always invoke this tool for any mathematical calculation, addition (+), subtraction (-), sum, or difference.",
        "use_agent_gateway_egress": true,
        "agent_gateway_engine": "projects/${PROJ_ID}/locations/global/collections/default_collection/engines/${GE_APP_ID}"
      }
    }
  }
}
EOF

データ コネクタの作成を確認する

# fetch collection id
export GE_COLLECTION_ID=$(curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq -r --arg dname "${MCP_NAME}-collection" '.collections[] | select(.displayName == $dname) | .name | split("/") | last' | head -n 1)

echo "ge collection id: ${GE_COLLECTION_ID}"

"registry_mcp_server_name" フィールドに MCP サーバーの Agent Registry UUID が入力されていることを確認します。

# show data connector details
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/${GE_COLLECTION_ID}/dataConnector" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq '{name, state, actionState, connectorModes, bapConfig, registry_mcp_server_name: .actionConfig.actionParams.registry_mcp_server_name}'

Google Cloud コンソール UI で MCP サーバー レジストリ エントリを表示します。

echo "mcp server registry page url: https://console.cloud.google.com/agent-platform/agent-registry/mcp-servers/${REGION}/${MCP_REGISTRY_URI##*/}/overview?project=${PROJ_ID}"

データ コネクタを有効にする

# activate and bind data connector
curl -s -X PATCH "https://discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/global/collections/${GE_COLLECTION_ID}/dataConnector?updateMask=actionConfig" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "name": "projects/${PROJ_ID}/locations/global/collections/${GE_COLLECTION_ID}/dataConnector",
  "actionConfig": {
    "isActionConfigured": true,
    "createBapConnection": true,
    "actionParams": {
      "auth_type": "NO_AUTH",
      "instance_uri": "${MCP_URL}",
      "mcp_server_source": "REGISTRY_MCP",
      "registry_mcp_server_name": "${MCP_REGISTRY_URI}",
      "mcp_agent_instructions": "MANDATORY MATH & ARITHMETIC AGENT: Always invoke this tool for any mathematical calculation, addition (+), subtraction (-), sum, or difference.",
      "use_agent_gateway_egress": true,
      "agent_gateway_engine": "projects/${PROJ_ID}/locations/global/collections/default_collection/engines/${GE_APP_ID}"
    }
  }
}
EOF

カスタム MCP サーバーのリンクを確認する

# show engine (ge app) details
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq '{name: .name, dataStoreIds: .dataStoreIds, agentGatewaySetting: .agentGatewaySetting}'

リンクされたデータストア "dataStoreIds": "collection-math-wizard-_mcp_data" を確認します。

# show collection details
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq --arg app "${GE_APP_ID}" '.collections[] | select(.dataConnector.actionConfig.actionParams.agent_gateway_engine // "" | endswith($app)) | .dataConnector | {name: .name, state: .state, actionState: .actionState, connectorModes: .connectorModes, actionParams: .actionConfig.actionParams}'

すべてのパラメータが入力された "state": "ACTIVE" を確認します。

ツールのアクション

Gemini Enterprise ダッシュボードで math-wizard-collection データストアを検査すると、[アクション] タブが使用されておらず、[↻ カスタム アクションを再読み込み] ボタンが無効になっていることがわかります。これは想定された動作です。

Google Cloud コンソール UI でデータストアの詳細ページを表示します。

echo "data store details page url: https://console.cloud.google.com/gemini-enterprise/locations/${GE_LOCATION}/collections/${GE_COLLECTION_ID}/connector/details?project=${PROJ_ID}"

カスタム MCP サーバーを Gemini Enterprise に接続する方法に応じて、ツールの検出とガバナンスは次の 2 つの方法のいずれかで処理されます。

  • 直接カスタム MCP(BYO_MCP ワークフロー): Agent Registry を使用せずに Gemini Enterprise 内でカスタム MCP サーバーを直接構成すると、データストア自体がツール カタログ(connectorModes: ["FEDERATED", "ACTIONS"])を管理します。[アクション] タブを開き、[↻ カスタム アクションを再読み込み] をクリックして tools/list スキーマを取得し、UI で個々のツール(add と subtract)を手動でオンまたはオフに切り替える必要があります。
  • Agent Registry のインポート(この Codelab で使用される REGISTRY_MCP ワークフロー): Agent Registry から MCP サーバーをインポートすると、Agent Registry は MCP エンドポイント、そのインターフェース メタデータ、ツール カタログ(connectorModes: ["FEDERATED"])の信頼できる唯一の情報源として機能します。Gemini Enterprise は、データストア UI で手動で再読み込みや切り替えを行うことなく、エンジンの Agent Gateway を介して、登録された MCP ツールをランタイム時に自動的に有効にします。

これで Gemini Enterprise app の部分は終了です。次は「検証」セクションに進みます。

8. 検証

このセクションでは、Gemini Enterprise ウェブアプリからライブ MCP ツール呼び出しをトリガーし、Agent Gateway、Cloud DNS、VPC ファイアウォール、Cloud Run ログ全体でリクエスト フローをトレースします。次に、IAM 統合アクセス ポリシーを強化して subtract を許可し、add をブロックして、ゲートウェイでゼロトラストの適用を確認します。

ユーザー アクセス

Gemini Enterprise ウェブアプリの URL を作成します。

# fetch app user url
export GE_WIDGET_ID=$(curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}/widgetConfigs/default_search_widget_config" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  -H "Content-Type: application/json" \
  | jq -r '.configId')

export GE_APP_USER_URL="https://vertexaisearch.cloud.google.com/home/cid/${GE_WIDGET_ID}"

echo "app user url: ${GE_APP_USER_URL}"

リンクをクリックして、ブラウザで Gemini Enterprise ウェブアプリのチャット インターフェースを開き、[使ってみる] をクリックします。

チャットでエージェント クエリをテストする

チャット UI で、チャット ボックスの下部にある [コネクタ] のパズル アイコンをクリックして、math-wizard-collection データコネクタが有効になっていることを確認します。切り替えボタンがオン(色付き)で表示されます。

次のテストクエリを試してください。

what is 2342345 - 98234798324?
what is 72347234 + 234234?

アシスタントが正しい回答を返し、各回答の下にインタラクティブなアクション引用バッジ(Math Calculation (8s) 🤖 Agentgateway Agent など)が表示され、ツールが実行されたことを確認します。

Cloud Logging でログを検査する

Cloud Logging のログを調べて、Gemini Enterprise が Agent Gateway とプライベート VPC ネットワークを介してツール呼び出しをルーティングしたことを確認します。

1. Agent Gateway と IAP の認可を確認する

Agent Gateway がリクエストをインターセプトし、Agent Registry でターゲットを解決し、IAP に認可を委任し、ツール呼び出しを許可したことを確認します。

# show agent gateway logs
gcloud logging read 'resource.type="networkservices.googleapis.com/Gateway"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="table( \
    timestamp.date(tz=LOCAL):label=TIMESTAMP, \
    httpRequest.status:label=STATUS, \
    httpRequest.serverIp:label=SERVER_IP, \
    jsonPayload.agentGatewayInfo.mcpInfo.method:label=MCP_METHOD, \
    jsonPayload.agentGatewayInfo.mcpInfo.parameter:label=TOOL, \
    jsonPayload.authzPolicyInfo.result:label=AUTHZ, \
    jsonPayload.agentGatewayInfo.agentRegistryResource.basename():label=REGISTRY_MCP
  )"

出力に次の内容が含まれていることを確認します。

  • STATUS: 200(実行成功)と 202(notifications/initialized ハンドシェイク)。
  • SERVER_IP: Google API PSC エンドポイント IP(172.16.20.20:443)。
  • MCP_METHOD と TOOL: MCP プロトコル シーケンス(notifications/initialized、tools/list、tools/call と add または subtract)。
  • AUTHZ: ALLOWED(IAP 認可による下り(外向き)を許可)。
  • REGISTRY_MCP: 解決された Agent Registry リソース ID(agentregistry-...)。

2. DNS とファイアウォールの転送を確認する

Cloud DNS がホスト名を PSC エンドポイントに解決し、ファイアウォールが Agent Gateway インターフェースからのトラフィックを許可したことを確認します。

# show dns logs
gcloud logging read 'resource.type="dns_query"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="table( \
    timestamp.date(tz=LOCAL):label=TIMESTAMP, \
    jsonPayload.queryName:label=QUERY_NAME, \
    jsonPayload.queryType:label=TYPE, \
    jsonPayload.responseCode:label=RCODE, \
    jsonPayload.rdata:label=RDATA
  )"
# show firewall logs
gcloud logging read 'logName:"compute.googleapis.com%2Ffirewall"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="table( \
    timestamp.date(tz=LOCAL):label=TIMESTAMP, \
    jsonPayload.connection.src_ip:label=SRC_IP, \
    jsonPayload.connection.dest_ip:label=DEST_IP, \
    jsonPayload.connection.dest_port:label=PORT, \
    jsonPayload.rule_details.reference.basename():label=RULE, \
    jsonPayload.disposition:label=DISPOSITION
  )"

次の値を確認します。

  • DNS QUERY_NAME & RDATA: math-wizard-...run.app.(A レコード、NOERROR)を 172.16.20.20 に解決します。
  • ファイアウォール SRC_IP & DEST_IP: 192.168.10.2(Agent Gateway PSC インターフェース IP)から 172.16.20.20:443。
  • ファイアウォール RULE & DISPOSITION: firewallPolicy:fw-policy-... と ALLOWED が一致しました。

3. Cloud Run ツールの実行を検証する

Cloud Run コンテナがツール呼び出しを受信して処理したことを確認します。

# show cloud run logs
gcloud logging read 'resource.type="cloud_run_revision"
  AND textPayload:"Tool:"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="value(timestamp.date(tz=LOCAL), textPayload)"

textPayload にツール実行エントリ(>>> 🛠️ Tool: 'subtract' called with numbers '[x]' and '[y]' など)が表示されることを確認します。

最小権限ポリシーの適用をテストする

最初の IAM アクセス ポリシーでは、宛先が登録されていれば(destination.is_registered == true)、どのメソッドまたはツールも許可されていました。このステップでは、subtract ツールのみを許可し、add をブロックすることで、最小権限を適用するようにポリシーを更新します。

IAM アクセス ポリシーを更新する

MCP ツールの実行を制限する場合は、2 つのルールパターンを使用します。

  1. ルール 1(MCP の検出とハンドシェイク): ツール呼び出し以外の MCP ライフサイクル メソッド(destination.is_registered == true と destination.agent_registry.mcp_server.method != 'tools/call')を許可します。Gemini Enterprise は、ツールを呼び出す前にストリームの設定と検出(initialize、notifications/initialized、tools/list)をネゴシエートし、destination.agent_registry.mcp_server.tool.name は tools/call の間のみ入力されるため、セッションの初期化とカタログの検出を機能させるにはルール 1 が必要です。
  2. ルール 2(ツールレベルの制限): tools/call の実行を制限し、subtract ツールのみを許可します(destination.is_registered == true、destination.agent_registry.mcp_server.method == 'tools/call'、destination.agent_registry.mcp_server.tool.name == 'subtract')。

両方のルールを使用してアクセス ポリシー ルール マニフェスト ファイルを更新します。

# create access policy rule file (update: allow subtract only)
cat > cfg/${UAP_POLICY_NAME}-rule-update.json << EOF
[
  {
    "description": "allow ge assistant to any registered endpoint to perform mcp discovery and handshake",
    "effect": "ALLOW",
    "principals": [
      "principal://${TRUST_DOMAIN}/resources/discoveryengine/projects/${PROJ_NO}/locations/global/engines/${GE_APP_ID}/assistants/default_assistant/agents/default/core_assistant"
    ],
    "operation": {
      "permissions": [
        "iap.googleapis.com/resources.egressViaIAP"
      ]
    },
    "conditions": {
      "iap.googleapis.com": {
        "expression": \
        "destination.is_registered == true && \
         destination.agent_registry.mcp_server.method != 'tools/call'"
      }
    }
  },
  {
    "description": "allow ge assistant to any registered mcp server with tool call subtract",
    "effect": "ALLOW",
    "principals": [
      "principal://${TRUST_DOMAIN}/resources/discoveryengine/projects/${PROJ_NO}/locations/global/engines/${GE_APP_ID}/assistants/default_assistant/agents/default/core_assistant"
    ],
    "operation": {
      "permissions": [
        "iap.googleapis.com/resources.egressViaIAP"
      ]
    },
    "conditions": {
      "iap.googleapis.com": {
        "expression": \
        "destination.is_registered == true && \
         destination.agent_registry.mcp_server.method == 'tools/call' && \
         destination.agent_registry.mcp_server.tool.name == 'subtract'"
      }
    }
  }
]
EOF

更新されたルールを IAM アクセス ポリシーに適用します。

# update iam access policy
gcloud iam access-policies update ${UAP_POLICY_NAME} \
  --details-rules=cfg/${UAP_POLICY_NAME}-rule-update.json \
  --project=${PROJ_ID} \
  --location=global

IAM アクセス ポリシーを確認する

新しい IAM アクセス ポリシーが適用され、減算ツールのみが許可されていることを確認します。

# show iam access policy details
gcloud iam access-policies describe ${UAP_POLICY_NAME} \
  --project=${PROJ_ID} \
  --location=global \
  --flatten="details.rules[]" \
  --format="table( \
    details.rules.principals[0].scope(engines).sub('assistants/default_assistant/agents/default', '...'):label=PRINCIPAL, \
    details.rules.effect:label=EFFECT, \
    details.rules.conditions.'iap.googleapis.com'.expression.sub('\s*&&\s*', '\n&& ').sub('\s*\|\|\s*', '\n|| '):label=EXPRESSION
  )"

禁止されているツール呼び出しをテストする

Gemini Enterprise ウェブアプリのチャット UI に戻り、別のテストクエリを試します。

what is 100 plus 20?

アシスタントは add の呼び出しを試みますが、Agent Gateway と IAP は IAM ポリシー条件を false と評価し、HTTP 403 Forbidden で下り(外向き)リクエストを拒否します。チャット UI で、アシスタントがブロックされたツール呼び出しを再試行する際に Calculate Sum を表示し、🤖 Agentgateway Agent ... Working on it. で回転していることがわかります。これは想定された動作です。これにより、Agent Gateway と IAP がネットワーク レベルで許可されていないツールの実行を積極的にインターセプトして拒否していることが確認できます。

Cloud Logging でログを再検査する

Agent Gateway のログエントリを表示し、許可されていない add ツール呼び出しに対応する新しい 403 エントリを確認します。

# show agent gateway logs
gcloud logging read 'resource.type="networkservices.googleapis.com/Gateway"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="table( \
    timestamp.date(tz=LOCAL):label=TIMESTAMP, \
    httpRequest.status:label=STATUS, \
    httpRequest.serverIp:label=SERVER_IP, \
    jsonPayload.agentGatewayInfo.mcpInfo.method:label=MCP_METHOD, \
    jsonPayload.agentGatewayInfo.mcpInfo.parameter:label=TOOL, \
    jsonPayload.authzPolicyInfo.result:label=AUTHZ, \
    jsonPayload.agentGatewayInfo.agentRegistryResource.basename():label=REGISTRY_MCP
  )"

想定される出力:

TIMESTAMP            STATUS  SERVER_IP         MCP_METHOD                 TOOL  AUTHZ    REGISTRY_MCP
YYYY-MM-DDTHH:MM:SS  403                       tools/call                 add   DENIED   agentregistry-00000000-0000-0000-0012-3456789abcde
YYYY-MM-DDTHH:MM:SS  403
YYYY-MM-DDTHH:MM:SS  202     172.16.20.20:443  notifications/initialized        ALLOWED  agentregistry-00000000-0000-0000-0012-3456789abcde
YYYY-MM-DDTHH:MM:SS          172.16.20.20:443                                   ALLOWED  agentregistry-00000000-0000-0000-0012-3456789abcde
YYYY-MM-DDTHH:MM:SS  200     172.16.20.20:443  initialize                       ALLOWED  agentregistry-00000000-0000-0000-0012-3456789abcde

追加のリクエストが Cloud Run バックエンドに到達していないことを確認します。

# show cloud run logs
gcloud logging read 'resource.type="cloud_run_revision"
  AND textPayload:"Tool:"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="value(timestamp.date(tz=LOCAL), textPayload)"

このコマンドは新しいエントリを返しません。これは、Agent Gateway が IAM アクセス ポリシーを正常に適用したことを示しています。

これで検証部分は完了です。次は、クリーンアップ セクションに進みます。

9. クリーンアップ

このラボで作成したリソースと構成を削除する手順は次のとおりです。

Gemini Enterprise コンポーネントを削除する

# delete gemini enterprise engine (app)
curl -s -X DELETE "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

# delete custom mcp collection, data connector, and backing data store
curl -s -X DELETE "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/${GE_COLLECTION_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}"

# reset identity provider configuration
curl -s -X PATCH "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/aclConfig" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  -H "Content-Type: application/json" \
  -d '{"idpConfig":{"idpType":"IDP_TYPE_UNSPECIFIED"}}'

MCP サーバー コンポーネントを削除する

# delete agent registry service
gcloud -q agent-registry services delete ${MCP_NAME} \
  --location=${REGION} \
  --project=${PROJ_ID}

# delete cloud run service, source-deploy artifact registry repo, and staging bucket
gcloud -q run services delete ${MCP_NAME} \
  --region=${REGION} \
  --project=${PROJ_ID}

gcloud -q artifacts repositories delete cloud-run-source-deploy \
  --location=${REGION} \
  --project=${PROJ_ID}

gcloud -q storage rm --recursive gs://run-sources-${PROJ_ID}-${REGION} \
  --project=${PROJ_ID}

Agent Gateway と IAM アクセス ポリシーを削除する

# delete gateway authorization policy, iap extension, and agent gateway
gcloud -q network-security authz-policies delete ${AGW_NAME}-authz-policy-iap \
  --location=${REGION} \
  --project=${PROJ_ID}

gcloud -q service-extensions authz-extensions delete ${AGW_NAME}-svc-ext-authz-iap \
  --location=${REGION} \
  --project=${PROJ_ID}

gcloud -q network-services agent-gateways delete ${AGW_NAME} \
  --location=${REGION} \
  --project=${PROJ_ID}
# delete iam policy binding and access policy
gcloud -q iam policy-bindings delete ${UAP_BINDING_NAME} \
  --location=global \
  --project=${PROJ_ID}

gcloud -q iam access-policies delete ${UAP_POLICY_NAME} \
  --location=global \
  --project=${PROJ_ID}

DNS コンポーネントとファイアウォール コンポーネントを削除する

# delete dns record set, managed zone, and policy
gcloud -q dns record-sets delete "*.run.app." \
  --type=A \
  --zone=priv-zone-run \
  --project=${PROJ_ID}

gcloud -q dns managed-zones delete priv-zone-run \
  --project=${PROJ_ID}

gcloud -q dns policies update dns-policy-${SLUG} \
  --networks="" \
  --project=${PROJ_ID}

gcloud -q dns policies delete dns-policy-${SLUG} \
  --project=${PROJ_ID}
# delete firewall policy association, rule, and policy
gcloud -q compute network-firewall-policies associations delete \
  --name=fw-policy-bind-${SLUG} \
  --firewall-policy=fw-policy-${SLUG} \
  --global-firewall-policy \
  --project=${PROJ_ID}

gcloud -q compute network-firewall-policies rules delete 1001 \
  --firewall-policy=fw-policy-${SLUG} \
  --global-firewall-policy \
  --project=${PROJ_ID}

gcloud -q compute network-firewall-policies delete fw-policy-${SLUG} \
  --global \
  --project=${PROJ_ID}

PSC と VPC ネットワーク コンポーネントを削除する

# delete psc forwarding rule and internal ip address
gcloud -q compute forwarding-rules delete psc2gapis \
  --global \
  --project=${PROJ_ID}

gcloud -q compute addresses delete ip-psc2gapis \
  --global \
  --project=${PROJ_ID}
# delete psc network attachment, subnet, and vpc network
gcloud -q compute network-attachments delete psc-na-${REGION}-agw \
  --region=${REGION} \
  --project=${PROJ_ID}

gcloud -q compute networks subnets delete subnet-${REGION}-agw \
  --region=${REGION} \
  --project=${PROJ_ID}

gcloud -q compute networks delete vnet-${SLUG} \
  --project=${PROJ_ID}

組織のポリシーのオーバーライドとローカル ファイルを削除する

# delete project-level organization policy overrides
gcloud -q org-policies delete discoveryengine.managed.disableCustomMcpServerConnector --project=${PROJ_ID}
gcloud -q org-policies delete iam.managed.disableAccessPolicyBinding --project=${PROJ_ID}
# remove local project files
rm -rf cfg math-wizard

これでクリーンアップ作業は終了です。次はまとめに進みます。

10. まとめ

おめでとうございます!Gemini Enterprise アプリが非公開のカスタム MCP サーバー上のツールを安全に検出して呼び出すことができるエンドツーエンドのアーキテクチャを構築しました。

  • カスタム MCP サーバーと Agent Registry: Cloud Run(--ingress=internal)に非公開の FastMCP サービスをデプロイし、そのエンドポイントとツール スキーマ(add と subtract)を Agent Registry に登録しました。
  • Gemini Enterprise の統合: Gemini Enterprise アプリをプロビジョニングし、アウトバウンド ツール トラフィックを Agent Gateway にバインドし、登録済みの MCP サーバーを REGISTRY_MCP データコネクタとしてアタッチしました。
  • プライベート VPC 下り(外向き)とゼロトラスト ガバナンス: PSC(172.16.20.20)を介してツール実行をプライベートにルーティングし、IAP と IAM 統合アクセス ポリシー(destination.agent_registry.*)を使用してツールレベルの最小権限を適用します。

cosmopup

Cosmpup は Codelab が最高だと思っています。

次のステップ

ご意見、ご質問、修正事項がございましたら、こちらのフィードバック フォームからお送りください。

ありがとうございました