Gemini Enterprise mit Agent Gateway-Ausgang zu privatem benutzerdefinierten MCP-Server über Agent Registry

1. Einführung

In diesem Codelab wird die private, verwaltete Egress-Konnektivität für Gemini Enterprise mit dem KI-Agenten-Gateway im agent-to-anywhere-Modus (Egress) untersucht. Sie konfigurieren eine Gemini Enterprise-App, um einen benutzerdefinierten Model Context Protocol (MCP)-Server, der in Cloud Run gehostet wird, sicher aufzurufen. Dazu leiten Sie Traffic über Agent Gateway mithilfe von Private Service Connect (PSC)-Schnittstellen weiter, um eine Verbindung zu einem PSC-Endpunkt für Google APIs in einem VPC-Netzwerk herzustellen.

In Unternehmensumgebungen birgt die Gewährung von direktem Netzwerkzugriff für autonome Agents das Risiko von Daten-Exfiltration und der Ausführung nicht geprüfter Tools. Agent Gateway bietet einen zentralen Zero-Trust-Durchsetzungspunkt auf Plattformebene, der streamfähige HTTP-MCP-Tool-Nutzlasten dynamisch prüft. Ausgehende Anfragen werden mit einer kryptografisch überprüfbaren Agent Identity authentifiziert und über Identity-Aware Proxy (IAP) mithilfe von IAM Unified Access Policies (UAP) mit CEL-Regeln (Common Expression Language) autorisiert. So lässt sich die Zugriffssteuerung auf bestimmte MCP-Tools und -Methoden detailliert steuern, ohne Backend-Arbeitslasten im öffentlichen Internet offenzulegen.

Was Sie erstellen

  • Agent Gateway im Modus „Ausgehender Traffic“ (Agent zu beliebigem Ziel) mit Endpunktprüfung der Agent Registry
  • Cloud Run-Dienst, der einen privaten streamfähigen HTTP-MCP-Server (--ingress=internal) hostet, der mit seinen Tool-Spezifikationen in Agent Registry registriert ist
  • IAP-Autorisierungserweiterung (Identity-Aware Proxy) für Agent Gateway
  • IAM Unified Access Policies (UAP) mit CEL-Bedingungen für die Autorisierung von MCP-Tools
  • Gemini Enterprise-App, die an das Agent Gateway gebunden und mit einem benutzerdefinierten MCP-Server-Datenspeicher verbunden ist, der aus der Agent Registry importiert wurde
  • VPC-Netzwerkressourcen, Cloud DNS-Zone und PSC-Endpunkt für Google APIs
  • PSC-Netzwerk-Anhang für ausgehenden privaten VPC-Traffic des Agent Gateway
  • Cloud Next Generation Firewall (NGFW)-Richtlinienregeln zum Sichern des VPC-Traffics

figure1

Abbildung 1. Codelab-Architektur

Lerninhalte

  • So stellen Sie einen privaten streamfähigen HTTP-MCP-Server aus dem Quellcode in Cloud Run bereit und registrieren seinen Endpunkt und sein Tool-Schema in Agent Registry
  • Agent Gateway mit konformen Registrierungseinträgen konfigurieren und Tool-Aufrufe der Gemini Enterprise App über das Gateway weiterleiten
  • Privaten VPC-Ausgang mit PSC-Netzwerk-Attachments und ‑Schnittstellen einrichten
  • Agent Gateway-Autorisierung an Identity-Aware Proxy (IAP) delegieren
  • IAM Unified Access Policies (UAP) mit destination.agent_registry.*- und destination.is_registered-CEL-Attributen erstellen und binden, um die Ausführung von MCP-Tools einzuschränken
  • Richtliniendurchsetzung und Netzwerk-Egress mit Cloud Logging validieren

Voraussetzungen

  • Ein Google Cloud-Projekt mit aktivierter Abrechnungsfunktion
  • Eine aktive Gemini Enterprise-Lizenz oder ein 30‑tägiger Testzeitraum
  • IAM-Berechtigungen zum Bereitstellen von Netzwerkdiensten, Gemini Enterprise- und Agent Platform-Ressourcen
  • Eine POSIX-kompatible Shell (bash oder zsh) mit installierter Google Cloud CLI (gcloud), curl und jq

Damit sind wir mit der Einführung fertig. Als Nächstes folgt der Abschnitt Konzepte.

2. Konzepte

Bereitstellungsreihenfolge

In diesem Codelab wird die Infrastruktur zuerst bereitgestellt, damit private Netzwerkpfade und Governance-Kontrollen betriebsbereit sind, bevor MCP-Tools registriert und mit Gemini Enterprise verbunden werden:

  1. Netzwerkinfrastruktur:Stellen Sie VPC-Subnetze, einen PSC-Endpunkt, einen PSC-Netzwerkanhang, Cloud NGFW-Richtlinienregeln und private Cloud DNS-Zonen bereit.
  2. Agent Gateway:Stellen Sie Agent Gateway im Egress-Modus mit Agent Registry-Integration (registries) und privatem VPC-Egress (networkAttachment) bereit.
  3. Autorisierungsrichtlinien:Konfigurieren Sie die IAP-Autorisierungserweiterung, die Gateway-Autorisierungsrichtlinie und die einheitliche IAM-Zugriffsrichtlinie (Unified Access Policy, UAP) mit destination.is_registered- und destination.agent_registry.*-CEL-Bedingungen.
  4. MCP-Server bereitstellen und registrieren:Stellen Sie den Math-MCP-Server aus der Quelle in Cloud Run (--ingress=internal) bereit und registrieren Sie die Dienst- und Tool-Spezifikationen (add und subtract) in der Agent Registry.
  5. Gemini Enterprise-App:Erstellen Sie die Gemini Enterprise-App (Engine), konfigurieren Sie die Identitäts- und Observability-Einstellungen und binden Sie den ausgehenden Egress an das Agent Gateway (agentGatewaySetting).
  6. Benutzerdefinierten MCP-Daten-Connector importieren:Erstellen und aktivieren Sie den REGISTRY_MCP-Daten-Connector (:setUpDataConnector), um den zugrunde liegenden Datenspeicher des registrierten MCP-Servers mit der Gemini Enterprise App zu verknüpfen.
  7. Validieren:Testen Sie zulässige und abgelehnte Tool-Ausführungen im Chat und prüfen Sie die Richtliniendurchsetzung in den Protokollen von Agent Gateway, DNS, Firewall und Cloud Run.

Gemini Enterprise-Ausgang

Gemini Enterprise leitet Toolanfragen für benutzerdefinierte MCP-Server an das Agent Gateway weiter, wenn sowohl agentGatewaySetting auf dem Engine als auch use_agent_gateway_egress: true auf dem DataConnector konfiguriert sind.

figure2

Abbildung 2. Gemini Enterprise-Architektur für den Datenexport

Die Gemini Enterprise App organisiert das Tool-Routing in vier wichtigen Bereichen:

  1. Widget (default_search_widget_config):
    • Stellt die Weboberfläche des Clients bereit. Das Widget empfängt Prompts vom Nutzer und startet Chatsitzungen mit der zugrunde liegenden Engine.
  2. Core Assistant (assistants/default_assistant/agents/default/core_assistant):
    • Der konversationelle Reasoning-Root-Agent in der Engine. Bei der Auswertung einer Nutzeranfrage ermittelt der Core Assistant, ob eine arithmetische Berechnung erforderlich ist, prüft die verfügbaren Tools und delegiert die Ausführung an den synthetisierten Agent Gateway-Unter-Agent.
  3. Datenspeicher und Daten-Connector:
    • DataStore: Wird in einem dedizierten Collection bereitgestellt, wenn :setUpDataConnector ausgeführt wird. Es verknüpft (dataStoreIds) die importierten Tool-Schemas der Agent Registry (add, subtract), Argumenttypen und Agent-Anweisungen mit dem Gemini Enterprise-Engine.
    • DataConnector: Verwaltet die REGISTRY_MCP-Aktionsverbindung (createBapConnection: true) zum Remote-MCP-Server (instance_uri), löst die MCP-Serverressource der Agent Registry (registry_mcp_server_name) auf und ermöglicht den Agent Gateway-Ausgang (use_agent_gateway_egress: true).
  4. Agent Identity, Agent Registry und Agent Gateway:
    • Wenn der Data Connector den ausgehenden Tool-Aufruf sendet, wird der Traffic an das in agentGatewaySetting angegebene Gateway weitergeleitet. Der Gacklaxiekern-Assistent erstellt ein SPIFFE-Identitätstoken, das seine Identität bestätigt: principal://agents.global.org-.../agents/default/core_assistant.
    • Agent Gateway wird über das Feld registries in Agent Registry eingebunden, um Zielendpunkte und registrierte Tool-Schemas dynamisch aufzulösen. Sie füllt die Attribute destination.is_registered und destination.agent_registry.* aus und übergibt sie an IAP v2, damit sie anhand der CEL-Regeln der IAM Unified Access Policy (UAP) ausgewertet werden, bevor der Transit in das VPC-Netzwerk zugelassen wird.

VPC-Verbindung des Gateways

Agent Gateway ermöglicht private VPC-Netzwerkverbindungen über zwei YAML-Felder:

  • networkConfig.egress.networkAttachment:Leitet privaten IP-Traffic über die PSC-Netzwerkverbindung in das VPC-Netzwerk weiter.
  • dnsPeeringConfig.domains:Die DNS-Auflösung wird mit der Cloud DNS-Zone des VPC-Netzwerks durchgeführt, sodass Ziel-Hostnamen (*.run.app) in die private PSC-Endpunkt-IP-Adresse aufgelöst werden, die im VPC-Netzwerk definiert ist.

Beschränkungen und Anforderungen

  • Nur StreamableHTTP:Der alte SSE-Transport (Server-Sent Events) wird nicht unterstützt. MCP-Server müssen StreamableHTTP verwenden.
  • Öffentliche CA-TLS erforderlich:Für MCP-Endpunkte müssen TLS-Zertifikate verwendet werden, die von einer öffentlich vertrauenswürdigen CA signiert wurden, auch wenn privat über PSC darauf zugegriffen wird.
  • Überschreiben der Organisationsrichtlinie:Sie müssen die Organisationsrichtlinie für benutzerdefinierte MCP-Datenspeicher explizit überschreiben, bevor Sie den Datenspeicher registrieren.

Damit sind wir mit den Konzepten fertig. Weiter geht es mit dem Abschnitt Einrichtung.

3. Einrichtung

Erforderliche IAM-Rollen

Für dieses Codelab sind die folgenden Rollen erforderlich:

Domain

Erforderliche IAM-Rollen

Projekt und IAM

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

Netzwerk und Gateway

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

Gemini Enterprise und Registry

roles/discoveryengine.admin
roles/agentregistry.admin (oder roles/apphub.admin)

Workloads und Entwicklung

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

Beobachtbarkeit

roles/logging.viewer
roles/logging.logWriter

Oder Sie verwenden eine allgemeine einfache Rolle wie roles/owner in Kombination mit roles/orgpolicy.policyAdmin, da mit roles/owner allein keine Organisationsrichtlinien geändert werden können.

Auf Ihr Projekt zugreifen

In diesem Codelab wird ein einzelnes Google Cloud-Projekt verwendet. Bei den Konfigurationsschritten werden die gcloud-Befehlszeile und Linux-Shell-Befehle verwendet.

Rufen Sie zuerst die Befehlszeile Ihres Google Cloud-Projekts auf:

Projekt-ID festlegen

gcloud config set project SET_YOUR_PROJECT_ID_HERE

Sitzung authentifizieren

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

Shell-Umgebungsvariablen festlegen

# 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}

Vertrauenswürdige Domains für die Identität von KI‑Agenten festlegen

Mit der if-then-else-Anweisung wird geprüft, ob das Projekt zu einer Organisation gehört, um die richtige Vertrauensdomäne für die Identitäten des Haupt-Agents festzulegen.

# 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}"

Abrechnungs- und Kontingentprojekt festlegen

# 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}

Lokales Verzeichnis für Konfigurationsdateien erstellen

# create config folder
mkdir -p cfg

Wenn Sie eine selbstverwaltete Installation des Google Cloud SDK ausführen (d. h. außerhalb von Cloud Shell), aktualisieren Sie die Komponenten auf die neueste Version.

# update gcloud cli
gcloud components update

API-Dienste aktivieren

# 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

Organisationsrichtlinien

Die standardmäßigen Einschränkungen für verwaltete Organisationsrichtlinien für Google Cloud schränken die in diesem Codelab verwendeten Funktionen ein:

Überschreiben Sie alle geerbten Einschränkungen für Organisationsrichtlinien auf Projektebene, indem Sie enforce: false explizit festlegen.

Benutzerdefinierte MCP-Einschränkung deaktivieren

# 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

Einschränkung für Zugriffsrichtlinie deaktivieren

# 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

Bedingte Einschränkungen für Daten-Connectors prüfen und deaktivieren

Standardmäßig wird die Connector-Erstellung durch discoveryengine.managed.allowedEgressFqdns und discoveryengine.managed.allowedDataSources nur blockiert, wenn sich Ihr Projekt in einem VPC Service Controls-Perimeter (VPC SC) befindet oder wenn ein Organisationsadministrator Ihr Projekt zu enforcedProjects hinzugefügt hat.

Sehen Sie sich zuerst die geltenden Richtlinien für Ihr Projekt an:

# 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~~ diese Einschränkungen erzwungen werden, legen Sie enforce: false für beide Richtlinien für Ihr Projekt fest, damit sie die Einrichtung des custom_mcp-Connectors in einer VPC SC oder einer organisationsrichtlinienbeschränkten Organisation nicht blockieren:

# 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-Berechtigungen

Weisen Sie Ihrem Nutzerkonto und dem von Cloud Build verwendeten Compute Engine-Standarddienstkonto die erforderlichen IAM-Rollen zu:

  • Nutzerkonto (${USER_IDENTITY})
      :
    • Erfordert Berechtigungen zum Bereitstellen und Aufrufen von Cloud Run-Diensten (roles/run.admin, roles/run.invoker, roles/iam.serviceAccountUser), zum Erstellen von Container-Images (roles/cloudbuild.builds.editor), zum Verwalten von Gemini Enterprise (roles/discoveryengine.admin) und zum Erstellen von Unified Access Policies (roles/iam.accessPolicyAdmin).
  • Standardmäßiges Compute Engine-Dienstkonto(${PROJ_NO}-compute@developer.gserviceaccount.com)
      :
    • Wird von Cloud Build verwendet, um Quellcode in Cloud Storage (roles/storage.admin) bereitzustellen, Images in Artifact Registry (roles/artifactregistry.writer) zu übertragen und Build-Logs zu schreiben (roles/logging.logWriter).

Führen Sie die folgenden Befehle aus, um die Rollenbindungen zuzuweisen:

# 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-Berechtigungen überprüfen

Prüfen Sie, ob für das Nutzerkonto die sechs Rollenbindungen (6) vorhanden sind.

# 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)"

Prüfen Sie, ob die drei (3) Rollenbindungen für das Standarddienstkonto für Compute Engine vorhanden sind.

# 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)"

Bindungen des Dienst-Agents prüfen (Vorsichtsmaßnahme)

In einem neuen Projekt stellt Google Cloud automatisch den Agent Gateway-Dienst-Agent bereit und gewährt ihm roles/agentgateway.serviceAgent, wenn networkservices.googleapis.com zum ersten Mal aktiviert wird. Wenn Sie ein vorhandenes Projekt wiederverwenden, in dem durch vorherige Bereinigungen möglicherweise Standardbindungen für Dienst-Agents entfernt wurden, führen Sie die folgenden Befehle als Fail-Safe aus, um sicherzustellen, dass die Identitäts- und Rollenbindung intakt sind:

# 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"

Das war der Einrichtungsteil. Weiter geht es mit dem Abschnitt Netzwerk.

4. Netzwerk

In diesem Abschnitt stellen Sie ein VPC-Netzwerk im benutzerdefinierten Modus mit einem dedizierten /28-Subnetz (192.168.10.0/28) bereit, das die Netzwerk-Attachment für Private Service Connect (PSC) für den Netzwerk-Egress von Agent Gateway in das VPC-Netzwerk unterstützt.

Der PSC-Endpunkt für Google APIs wird mit einer einzelnen /32globalen internen IPv4-Adresse (172.16.20.20) bereitgestellt, um den privaten internen Zugriff auf Google APIs und Google-Dienste zu unterstützen. In diesem Codelab wird Cloud Run über den PSC-Endpunkt als Ziel für das Agent Gateway verwendet. Dazu wird die run.app.-Domain über Cloud DNS-Peering aufgelöst.

Netzwerke erstellen

Globales VPC-Netzwerk erstellen

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

Subnetze für die PSC-Netzwerkverbindung des Agent Gateway erstellen:

# 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

Firewallregeln erstellen

Erstellen Sie eine Firewallrichtlinie, die den gesamten ausgehenden Traffic mit aktiviertem Logging zulässt. Damit wird der Traffic überwacht, der vom Agent Gateway zum VPC-Netzwerk übertragen wird. Cloud NGFW unterstützt sowohl die Essentials- als auch die Standardstufe für Netzwerksicherheit und Traffic-Monitoring.

# 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-Netzwerkanhang erstellen

Erstellen Sie einen Private Service Connect-Netzwerkanhang (PSC), der so konfiguriert ist, dass Verbindungen von Agent Gateway automatisch akzeptiert werden. Der Netzwerkanhang stellt die Nutzer-VPC-Netzwerkseite der Verbindung her, um eine sichere Verbindung mit der Produzenten-Seite des Agent Gateway für ausgehenden Traffic herzustellen. Weitere Informationen zu Subnetzanforderungen und IP-Bereichsspezifikationen finden Sie unter VPC-Verbindung konfigurieren.

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

PSC-Netzwerkanhang prüfen

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

Rufen Sie den Ressourcen-URI der PSC-Netzwerkverbindung ab und speichern Sie ihn in der Umgebungsvariable PSC_NA_URI. Auf diesen URI wird in der Agent Gateway-Konfiguration (networkConfig.egress.networkAttachment) verwiesen, um die PSC-Schnittstelle für den Netzwerkausgang in das VPC-Netzwerk bereitzustellen:

# 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-Endpunkt erstellen

Ein Private Service Connect-Endpunkt (PSC) für Google APIs wird für Agent Gateway verwendet, um eine private Verbindung zum Cloud Run-MCP-Server über einen internen Netzwerkpfad herzustellen, ohne Traffic im öffentlichen Internet verfügbar zu machen. Bei ausgehenden Tool-Aufrufen, die von Agent Gateway in das VPC-Netzwerk geleitet werden, wird die Ziel-Cloud Run-Dienst-URL (*.run.app) in diese private Endpunkt-IP-Adresse aufgelöst.

Reservieren Sie eine globale interne IPv4-Adresse für den PSC-Endpunkt. Die ausgewählte IP-Adresse muss eine /32-Adresse sein, die sich nicht mit vorhandenen Subnetzen in Ihrem VPC-Netzwerk überschneidet:

# 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}

Erstellen Sie einen PSC-Endpunkt für Google APIs mit dem all-apis-Bundle, das Cloud Run (run.app) enthält.

# 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-Endpunkt prüfen

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

DNS-Zone und ‑Einträge erstellen

Cloud DNS wird verwendet, damit das Agent Gateway privat mit dem in Cloud Run gehosteten MCP-Server kommunizieren kann. Wenn Agent Gateway ausgehende Tool-Anfragen an Cloud Run auswertet, wird DNS-Peering (dnsPeeringConfig.domains) verwendet, um DNS-Abfragen für *.run.app mit Ihrer privaten Cloud DNS-Zone aufzulösen, die Ihrem VPC-Netzwerk zugeordnet ist. Der private DNS-Eintrag gibt die Anfrage mit der internen PSC-Endpunkt-IP-Adresse (172.16.20.20) zurück, sodass MCP-Toolanfragen über einen privaten Netzwerkpfad weitergeleitet werden können.

Erstellen Sie eine private, von Cloud DNS verwaltete Zone für die Domain run.app.:

# 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}

Erstellen Sie einen Platzhalter-DNS-Eintrag vom Typ A für *.run.app., der auf die IP-Adresse des PSC-Endpunkts verweist:

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

Erstellen Sie eine Cloud DNS-Richtlinie, um das Logging von DNS-Abfragen zu aktivieren. Beim DNS-Logging werden Domainauflösungsanfragen erfasst, die vom Agent Gateway in Ihrem VPC-Netzwerk stammen. So können Sie prüfen, ob *.run.app-Toolanfragen korrekt zum internen PSC-Endpunkt aufgelöst werden:

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

Damit ist der Netzwerkteil abgeschlossen. Fahren Sie mit dem Abschnitt Agent Gateway fort.

5. Agent Gateway

Agent Gateway gibt registries für Agent Registry-Instanzen zusammen mit den Feldern networkConfig an, die den PSC-Netzwerkanhang und die DNS-Peering-Einstellungen für private VPC-Verbindungen konfigurieren:

  • registries:Ordnet das Gateway bis zu zwei Agent Registry-Instanzen zu: einer regionalen (../locations/${REGION}) und einer globalen (../locations/global). Dadurch wird Agent Gateway in Agent Registry eingebunden, um sowohl regionale Bereitstellungen (z. B. Cloud Run-MCP-Server in ${REGION}) als auch globale Ressourcen (z. B. Gemini Enterprise-Agents und globale Endpunkte) für die detaillierte IAP v2-Richtlinienerzwingung aufzulösen. Regionale Einträge haben Vorrang vor globalen Einträgen, wenn Ziel-URLs aufgelöst werden.
  • networkAttachment:Verweist auf den PSC-Netzwerkanhang (psc-na-${REGION}-agw), der das Agent Gateway für den privaten ausgehenden Traffic mit Ihrem VPC-Netzwerk verbindet.
  • dnsPeeringConfig.domains:Konfiguriert run.app. so, dass DNS-Anfragen, die von Agent Gateway für Cloud Run-Dienste stammen, DNS-Peering verwenden, um Hostnamen in die private Google APIs PSC-Endpunkt-IP-Adresse (172.16.20.20) aufzulösen, die in Ihrer privaten Cloud DNS-Zone konfiguriert ist.

KI-Agenten-Gateway bereitstellen

Konfigurationsdatei für das Agent Gateway erstellen und importieren

# 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-Bereitstellung überprüfen

Bestätigen Sie die Agent-Registrierung und die Netzwerkkonfiguration:

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

Erwartete Ausgabe:

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}

Prüfen Sie, ob in der Ausgabe die erforderlichen Konfigurationsdetails angezeigt werden:

  • registries:Listet den regionalen (${REGION}) Agent Registry-URI auf, der dem Gateway zugeordnet ist.
  • egress.networkAttachment:Gibt den URI des PSC-Netzwerk-Attachments für VPC-Ausgang an.
  • dnsPeeringConfig.domains:Enthält run.app., die auf targetNetwork für die Auflösung privater Domains verweisen.

Prüfen Sie die PSC-Netzwerkverbindung, um die Gateway-Verbindung zu bestätigen:

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

Prüfen Sie, ob ein akzeptierter Verbindungsendpunkt vorhanden ist:

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

Autorisierung delegieren

Agent Gateway schützt und steuert ausgehenden Tool-Traffic mithilfe von Autorisierungsrichtlinien (networksecurity.authzPolicies), die in Identity-Aware Proxy (IAP) Unified Access Policies (UAP) eingebunden sind.

Agent Gateway unterstützt zwar grundlegende Inline-ALLOW- und DENY-Regeln, in Unternehmensumgebungen ist jedoch eine zentrale, identitätsbezogene Verwaltung erforderlich. Mit IAM Unified Access Policies (oder Zugriffsrichtlinien) verwalten Sie Regeln für den ausgehenden Zugriff mit standardmäßigen IAM v3-Zugriffsrichtlinien.

figure3

Abbildung 3. Autorisierungsarchitektur

Der Autorisierungsablauf verbindet drei Komponenten:

  1. Gateway Authorization Policy (authzPolicy):
    • Eine regionale Ressource, die auf das Agent Gateway ausgerichtet ist.
    • Mit policyProfile: REQUEST_AUTHZ und action: CUSTOM konfiguriert, um alle ausgehenden Autorisierungsprüfungen an die IAP Authz Extension weiterzuleiten.
  2. IAP Service Extension (authzExtension):
    • Eine regionale Ressource, die die Autorisierung von Anfragen an Identity-Aware Proxy (iap.googleapis.com) delegiert.
    • Bewertet Richtlinien im ENFORCE-Modus mit Richtlinienversion V2.
  3. IAM Unified Access Policy and Binding (accessPolicy & policyBinding):
    • Globale IAM v3-Ressourcen mit detaillierten Zugriffsregeln.
    • Authentifiziert die SPIFFE-Hauptidentität des aufrufenden Agents, prüft die universelle Berechtigung iap.googleapis.com/resources.egressViaIAP und wertet CEL-Bedingungen (Common Expression Language) anhand von Zielattributen aus.

Autorisierungserweiterung bereitstellen

Erstellen Sie eine service-extensions-Autorisierungserweiterungskonfiguration, die Autorisierungsentscheidungen an den IAP-Dienst delegiert:

# 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}

Autorisierungserweiterung überprüfen

Prüfen Sie, ob die Autorisierungserweiterung aktiv ist:

# 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
  )"

Autorisierungsrichtlinie bereitstellen

Erstellen Sie eine network-security-Autorisierungsrichtlinienkonfiguration, die auf das Agent Gateway ausgerichtet ist und die Anfrageüberprüfung an die Autorisierungserweiterung für IAP delegiert:

# 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}

Autorisierungsrichtlinie prüfen

Prüfen Sie, ob die Autorisierungsrichtlinie aktiv ist:

# 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-Zugriffsrichtlinien erstellen

Agent Gateway delegiert Autorisierungsprüfungen jetzt an IAP und löst Zielmetadaten aus Agent Registry auf. Definieren Sie als Nächstes eine IAM Unified Access Policy-Regel, um die Ausführung ausgehender Tools zu steuern.

IAP wertet CEL-Attributausdrücke anhand der folgenden Zielattribute der Agent Registry aus:

  • Registrierter Status (destination.is_registered):
    • Boolescher Wert (true/false), der angibt, ob das Ziel in der Agent Registry katalogisiert ist.
  • Name des MCP-Servers (destination.agent_registry.mcp_server.name):
    • Der kanonische MCP-Server-Ressourcenname, der in Agent Registry registriert ist.
  • MCP-Methode (destination.agent_registry.mcp_server.method):
    • Die aufgerufene MCP-Methode, z. B. tools/call, tools/list oder initialize.
  • Name des Tools (destination.agent_registry.mcp_server.tool.name):
    • Der Name des aufgerufenen Tools, z. B. subtract oder add. Dies ermöglicht eine detaillierte Autorisierung auf Tool-Ebene auf registrierten MCP-Servern.

IAM-Zugriffsrichtlinienregel definieren

Das Manifest der IAM-Richtlinienregel gibt Folgendes an:

  • Principals:Die SPIFFE-Hauptidentität, die den Gemini Enterprise-Kernassistenten-Agenten repräsentiert.
  • Berechtigungen:Die universelle Berechtigung iap.googleapis.com/resources.egressViaIAP, die für den gesamten ausgehenden Traffic, der von IAP verwaltet wird, erforderlich ist.
  • Bedingungen:Ein CEL-Ausdruck (destination.is_registered == true), der dafür sorgt, dass der Agent nur Endpunkte aufrufen kann, die in der Agent Registry katalogisiert sind.

Manifestdatei für die Richtlinienregel erstellen:

# 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-Zugriffsrichtlinie bereitstellen

Erstellen Sie die globale IAM-Zugriffsrichtlinie anhand der in der Manifestdatei definierten Regeln:

# 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-Zugriffsrichtlinie überprüfen

Prüfen Sie, ob die IAM-Zugriffsrichtlinie erfolgreich erstellt wurde, und sehen Sie sich die Regeldetails an:

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

Erwartete Ausgabe:

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-Zugriffsrichtlinie an Projekt binden

Wenn Sie die Erzwingung für alle Agent Gateways in Ihrem Projekt aktivieren möchten, erstellen Sie eine Richtlinienbindung, mit der die IAM-Zugriffsrichtlinie an die Projektressource angehängt wird:

# 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-Richtlinienbindung für den Zugriff prüfen

Prüfen Sie, ob die aktiven Richtlinienbindungspunkte auf die richtige Richtlinie und das richtige Ziel verweisen:

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

Erwartete Ausgabe:

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}

Damit ist der Abschnitt zum Agent Gateway abgeschlossen. Als Nächstes folgt der Abschnitt zum MCP-Server.

6. MCP-Server

In diesem Abschnitt erstellen Sie einen benutzerdefinierten FastMCP-Server, der die Tools add und subtract bereitstellt, und stellen ihn direkt aus der Quelle in Cloud Run bereit. Während der Quellcodebereitstellung (--source) verpackt Cloud Build das Container-Image mit dem enthaltenen Dockerfile und uv (wodurch die in pyproject.toml definierten Abhängigkeiten installiert und server.py gestartet wird).

Sobald der Cloud Run-Dienst bereitgestellt wurde, registrieren Sie den MCP-Server in der Agent Registry zusammen mit der zugehörigen Tool-Spezifikation (toolspec.json), damit Gemini Enterprise die Tools erkennen und aufrufen kann.

MCP-Serveranwendung erstellen

Erstellen Sie ein math-wizard-Projektverzeichnis für den Anwendungscode:

# create directory for code
mkdir -p math-wizard

Manifestdatei für das Python-Projekt schreiben:

# 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

Einige zusätzliche Instrumentierungsfunktionen sind im Code enthalten, um eingehende HTTP-Header (mcp-session-id, x-forwarded-for, user-agent und x-cloud-trace-context) für die Cloud Logging- und Cloud Trace-Validierung zu erfassen.

Schreiben Sie die Anwendungscode-Datei:

# 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

Schreiben Sie die Dockerfile, um Anleitungen zum Erstellen von Container-Images und Startbefehle zu definieren:

# 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

Dienst in Cloud Run bereitstellen

Stellen Sie den MCP-Server aus der Quelle mit Cloud Build bereit (dabei wird das Compute-Standarddienstkonto des Projekts ${PROJ_NO}-compute@developer.gserviceaccount.com verwendet):

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

Cloud Run-Bereitstellung prüfen

Prüfen Sie die Details des Cloud Run-Dienstes, um die aktive Konfiguration zu ermitteln:

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

Erwartete Ausgabe:

<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>

MCP-Server in Agent Registry registrieren

Damit Gemini Enterprise die genauen Tools erkennen kann, die auf dem MCP-Server verfügbar sind, muss bei der Registrierung in Agent Registry eine Tool-Spezifikationsdatei (toolspec.json) angegeben werden.

MCP-Tool-Spezifikation erstellen

# 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

MCP-Server in Agent Registry registrieren

# 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}"

MCP-Server in Agent Registry überprüfen

Prüfen Sie, ob der bereitgestellte Cloud Run-Dienst in der Region als registrierter MCP-Server mit seiner Endpunkt-URL und den verfügbaren Tools aufgeführt ist:

# 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
  )"

Erwartete Ausgabe:

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

Sehen Sie sich die Dienstkonfigurationsspezifikation an, um zu sehen, dass sie die genauen Tool-Definitionen, Eingabeschemas und Verhaltensanmerkungen für jedes Tool registriert:

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

Damit ist der Teil zum MCP-Server abgeschlossen. Weiter geht es mit dem Abschnitt zu Gemini Enterprise.

7. Gemini Enterprise

In diesem Abschnitt erstellen und konfigurieren Sie eine Gemini Enterprise-App und eine verknüpfte benutzerdefinierte MCP-Server-Datenspeicher-Ressource.

Discovery Engine-Ressourcenmodell

Eine Gemini Enterprise-App (in der Discovery Engine API als Engine-Ressource dargestellt) ist die zentrale Orchestrierungsebene und Konversationsschnittstelle für Endnutzer. Sie verwaltet Nutzer-Chatsitzungen, stützt generative Modelle auf Unternehmensdaten und koordiniert die dynamische Ausführung von Tools.

Gemini Enterprise-Apps interagieren über Datenspeicher mit Daten und Systemen:

  • Wissensdatenspeicher:Statische Inhalte (z. B. Cloud Storage, Google Drive, BigQuery) für Retrieval Augmented Generation (RAG) aufnehmen und indexieren.
  • Daten-Connectors (Aktionsanbieter): Sie können eine Verbindung zu dynamischen Drittanbieter- oder benutzerdefinierten APIs herstellen. Ein benutzerdefinierter MCP-Server-Datenspeicher stellt Tools bereit, die durch das Model Context Protocol (MCP) definiert werden. So kann das Modell während einer Unterhaltung dynamisch externe Funktionen aufrufen.

Routing für ausgehenden Traffic über Agent Gateway

Standardmäßig leitet Gemini Enterprise Connector- und Tool-Ausführungstraffic über öffentliche Netzwerke weiter. Für private VPC-Arbeitslasten und Zero-Trust-Governance kann die Engine jedoch so konfiguriert werden, dass der ausgehende Traffic über das Agent Gateway geleitet wird:

  • Wenn Sie den benutzerdefinierten MCP-Server-Datenspeicher später in diesem Lab erstellen, aktivieren Sie in den Datenspeichereinstellungen die Option Route egress through Agent Gateway (Ausgang über Agent Gateway weiterleiten).
  • Dadurch werden die ausgehenden Tool-Aufrufe der Engine an Ihr regionales Agent Gateway gebunden. So wird sichergestellt, dass alle MCP-Anfragen die Agent Identity der App enthalten, die Laufzeitautorisierung über IAP und IAM Unified Access Policies (UAP) erfolgt und die PSC-Netzwerkverbindung in Ihre private VPC führt.

Gemini Enterprise-App erstellen

Bei der folgenden Methode wird die discoveryengine.googleapis.com API verwendet, um die Ressourcen und Konfiguration der Gemini Enterprise-App zu erstellen. Eine Anleitung zur Konfiguration über die Google Cloud Console-UI finden Sie unter App erstellen.

# 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

App-Erstellung bestätigen

# 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}"

So rufen Sie die erstellte Konfiguration auf:

# 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}"

Beachten Sie die folgenden serverseitig ausgefüllten Attribute in der JSON-Antwort:

  • name: Kanonischer Ressourcenpfad (projects/${PROJ_NO}/locations/global/collections/default_collection/engines/${GE_APP_ID}).
  • sessionConfig.sessionManagementPolicy: Standardmäßig wird "VERTEX_AI_MANAGED" verwendet, wodurch der Status von Multi-Turn-Chats und Tool-Aufrufen in der Agent Platform (früher Vertex AI) beibehalten wird.
  • observabilityConfig.observabilityEnabled: Der Standardwert für Basismesswerte ist true. Das detaillierte Logging von Prompts und Tool-Nutzlasten wird in einem späteren Schritt aktiviert.

Identitätsanbieter aktivieren

Aktivieren Sie Google Identity als Identitätsanbieter für die Endnutzerauthentifizierung in Ihrer Gemini Enterprise-App.

Bei der folgenden Methode wird die discoveryengine.googleapis.com API verwendet, um den Identitätsanbieter der Gemini Enterprise-App zu konfigurieren. Eine Anleitung zur Konfiguration über die Google Cloud Console-Benutzeroberfläche finden Sie unter Identitätsanbieter konfigurieren.

# 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

Identitätsanbieter bestätigen

# 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}"

Die Ausgabe "idpType": "GSUITE" entspricht dem Google-Identitätsanbieter.

(Optional) Gemini Enterprise-Testlizenz aktivieren

Wenn Sie ein Projekt mit zugewiesenen Gemini Enterprise-Lizenzen verwenden, können Sie diesen Schritt überspringen. Wenn Sie ein neues Projekt ohne Lizenz verwenden, fahren Sie mit den folgenden Schritten fort.

Erstellen Sie eine Lizenzkonfigurationsressource, um Gemini Enterprise-Nutzerplätze für 30 Tage zu autorisieren. Dadurch wird die Standardlizenz auf den neuen Testzeitraum festgelegt, sodass jeder Nutzer, der sich anmeldet, automatisch einen Arbeitsplatz erhält:

# 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

Prüfen, ob die Lizenz angewendet wurde

# 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}"

Prüfen Sie "subscriptionTerm": "SUBSCRIPTION_TERM_ONE_MONTH" und "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}"

Prüfen Sie ../free_trial_gemini" und "enableLicenseAutoRegister": true.

Einstellungen für die Beobachtbarkeit aktivieren

Wenn Sie Beobachtbarkeit auf Ebene der Gemini Enterprise App (Engine) aktivieren, können Sie die Interaktionen des Hauptassistenten mit Messwertdaten im Metrics Explorer ansehen und End-to-End-Traces in Cloud Trace korrelieren.

# 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

Einstellungen für Beobachtbarkeit überprüfen

# 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}'

Suchen Sie nach "sensitiveLoggingEnabled": true.

An Agent Gateway binden

Wenn ausgehender Traffic von Gemini Enterprise über Agent Gateway weitergeleitet wird, wird eine zentrale Zero-Trust-Grenze für Governance und Sicherheit für alle Tool-Aufrufe von KI-Agenten eingerichtet:

  • Zentrale Richtliniendurchsetzung:Agent Gateway fungiert als Inline-Proxy, der ausgehende Toolanfragen anhand von Autorisierungsrichtlinien und Governance-Kontrollen auswertet, bevor der Traffic die Agent-Umgebung verlässt.
  • Ausgehender Traffic aus dem privaten Netzwerk:Durch die Bindung von Gemini Enterprise an das Agent Gateway werden Tool-Aufrufe, die auf private MCP-Server in Cloud Run ausgerichtet sind, sicher über Private Service Connect (PSC) geleitet und das öffentliche Internet wird umgangen.
  • Einheitliche Prüfbarkeit: Bietet eine zentrale Protokollierung von Anfragen, Telemetrie und Prüfpfaden für alle verbundenen MCP-Server und externen Tools.

Wenn Sie agentGatewaySetting in Ihrer Gemini Enterprise-App konfigurieren, werden ausgehende Tool- und Agent-Aufrufe, die durch Endnutzeranfragen initiiert werden (z. B. Aufrufe benutzerdefinierter MCP-Server, die aus der Agent Registry importiert wurden, und A2A-Agents), automatisch über das Agent Gateway weitergeleitet.

Patchen Sie die Engine agentGatewaySetting, um Folgendes zu aktivieren:

# 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-Bindung überprüfen

Rufen Sie die App-Konfiguration ab, um die agentGatewaySetting-Bindung zu bestätigen:

# 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}'

Erwartete Ausgabe:

{
  "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}"
    }
  }
}

Benutzerdefinierten MCP-Server-Datenspeicher erstellen

In diesem Abschnitt verbinden Sie den MCP-Server mit Gemini Enterprise, indem Sie einen benutzerdefinierten MCP-Datenspeicher erstellen.

Mit der Discovery Engine API ist dies ein zweistufiger Prozess:

  1. Erstellen (:setUpDataConnector): Erstellt eine dedizierte Collection-Ressource (${MCP_NAME}-%timestamp-collection), hängt die DataConnector (custom_mcp) an und stellt die zugrunde liegende DataStore (..._mcp_data) bereit.
  2. Aktivieren (PATCH .../dataConnector?updateMask=actionConfig): Aktiviert die Aktionslaufzeit des Connectors (actionState: "ACTIVE") mithilfe der Tool-Spezifikation der Agent Registry und bindet die DataStore (dataStoreIds) an Ihre Engine von Gemini Enterprise.
# 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}"

Daten-Connector erstellen

# 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

Erstellung des Daten-Connectors prüfen

# 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}"

Prüfen Sie, ob das Feld "registry_mcp_server_name" mit der Agent Registry-UUID für den MCP-Server ausgefüllt wird:

# 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}'

So rufen Sie den MCP-Serverregistrierungseintrag in der Google Cloud Console auf:

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}"

Daten-Connector aktivieren

# 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

Verknüpfungen mit benutzerdefinierten MCP-Servern überprüfen

# 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}'

Suchen Sie nach dem verknüpften Datenspeicher "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}'

Suchen Sie nach "state": "ACTIVE" mit allen ausgefüllten Parametern.

Tool-Aktionen

Wenn Sie den math-wizard-collection-Datenspeicher im Gemini Enterprise-Dashboard untersuchen, werden Sie feststellen, dass der Tab Aktionen nicht verwendet wird und die Schaltfläche Benutzerdefinierte Aktionen ↻ neu laden deaktiviert ist. Das ist ganz normal.

So rufen Sie die Seite mit den Datenspeicherdetails in der Google Cloud Console-UI auf:

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}"

Je nachdem, wie Sie einen benutzerdefinierten MCP-Server mit Gemini Enterprise verbinden, werden die Tool-Erkennung und ‑Verwaltung auf eine von zwei Arten gehandhabt:

  • Direkter benutzerdefinierter MCP (BYO_MCP-Workflow): Wenn Sie einen benutzerdefinierten MCP-Server direkt in Gemini Enterprise ohne Agent Registry konfigurieren, wird der Toolkatalog (connectorModes: ["FEDERATED", "ACTIONS"]) vom Datenspeicher selbst verwaltet. Sie müssen den Tab Aktionen öffnen, auf ↻ Benutzerdefinierte Aktionen neu laden klicken, um das tools/list-Schema abzurufen, und einzelne Tools (add und subtract) manuell in der Benutzeroberfläche aktivieren oder deaktivieren.
  • Agent Registry Import (REGISTRY_MCP-Workflow, der in diesem Codelab verwendet wird): Wenn Sie einen MCP-Server aus der Agent Registry importieren, dient die Agent Registry als maßgebliche Quelle für den MCP-Endpunkt, seine Schnittstellenmetadaten und seinen Toolkatalog (connectorModes: ["FEDERATED"]). Gemini Enterprise aktiviert die registrierten MCP-Tools automatisch zur Laufzeit über das Agent Gateway der Engine, ohne dass Sie Aktionen in der Benutzeroberfläche des Datenspeichers manuell neu laden oder ein- bzw. ausschalten müssen.

Damit ist der Teil zur Gemini Enterprise-App abgeschlossen. Weiter geht es mit dem Abschnitt Validieren.

8. Validieren

In diesem Abschnitt lösen Sie Live-MCP-Tool-Aufrufe über die Gemini Enterprise-Web-App aus und verfolgen den Anfragefluss über Agent Gateway, Cloud DNS, VPC-Firewall und Cloud Run-Logs. Anschließend verschärfen Sie die IAM Unified Access Policy, um subtract zuzulassen und add zu blockieren. So wird die Zero-Trust-Durchsetzung am Gateway überprüft.

Nutzerzugriff

Erstellen Sie die URL für die Gemini Enterprise-Webanwendung:

# 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}"

Folgen Sie dem Link, um die Gemini Enterprise-Webanwendung in Ihrem Browser zu öffnen, und klicken Sie auf Erste Schritte.

Agent-Anfragen im Chat testen

Prüfen Sie in der Chat-Benutzeroberfläche, ob der math-wizard-collection-Daten-Connector aktiviert ist. Klicken Sie dazu unten im Chatfeld auf das Puzzlesymbol für Connectors. Es sollte ein Ein/Aus-Schalter angezeigt werden, der aktiviert ist (farbig dargestellt).

Probieren Sie die folgenden Testabfragen aus:

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

Prüfen Sie, ob der Assistent die richtigen Antworten zurückgibt und unter jeder Antwort ein interaktives Badge für die Aktionsquelle (z. B. Math Calculation (8s) 🤖 Agentgateway Agent) angezeigt wird, um zu bestätigen, dass das Tool ausgeführt wurde.

Logs in Cloud Logging ansehen

Prüfen Sie in Cloud Logging, ob Gemini Enterprise die Tool-Aufrufe über Agent Gateway und das private VPC-Netzwerk weitergeleitet hat.

1. Agent Gateway- und IAP-Autorisierung überprüfen

Prüfen Sie, ob Agent Gateway die Anfrage abgefangen, das Ziel in der Agent Registry aufgelöst, die Autorisierung an IAP delegiert und den Tool-Aufruf zugelassen hat:

# 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
  )"

Prüfen Sie, ob die Ausgabe Folgendes enthält:

  • STATUS: 200 (erfolgreiche Ausführung) und 202 (notifications/initialized-Handshake).
  • SERVER_IP: Google APIs PSC-Endpunkt-IP (172.16.20.20:443).
  • MCP_METHOD und TOOL: Die MCP-Protokollsequenz (notifications/initialized, tools/list und tools/call mit add oder subtract).
  • AUTHZ: ALLOWED (IAP-Autorisierung für Egress zulässig).
  • REGISTRY_MCP: Aufgelöste Ressourcen-ID der Agent Registry (agentregistry-...).

2. DNS- und Firewall-Transit überprüfen

Prüfen Sie, ob Cloud DNS den Hostnamen in den PSC-Endpunkt aufgelöst hat und ob die Firewall Traffic von der Agent Gateway-Schnittstelle zugelassen hat:

# 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
  )"

Prüfen Sie die folgenden Werte:

  • DNSQUERY_NAME &RDATA: Löst math-wizard-...run.app. (A-Eintrag, NOERROR) in 172.16.20.20 auf.
  • Firewall SRC_IP & DEST_IP: 192.168.10.2 (IP der Agent Gateway PSC-Schnittstelle) bis 172.16.20.20:443.
  • FirewallRULE & DISPOSITION: Abgleich von firewallPolicy:fw-policy-... mit ALLOWED.

3. Ausführung des Cloud Run-Tools überprüfen

Prüfen Sie, ob der Cloud Run-Container den Toolaufruf empfangen und verarbeitet hat:

# 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)"

Prüfen Sie, ob textPayload Einträge zur Toolausführung enthält (z. B. >>> 🛠️ Tool: 'subtract' called with numbers '[x]' and '[y]').

Erzwingung der Richtlinie für die geringsten Berechtigungen testen

In der ursprünglichen IAM-Zugriffsrichtlinie war jede Methode oder jedes Tool zulässig, sofern das Ziel registriert war (destination.is_registered == true). In diesem Schritt aktualisieren Sie die Richtlinie, um das Prinzip der geringsten Berechtigung zu erzwingen. Dazu lassen Sie nur das Tool subtract zu und blockieren add.

IAM-Zugriffsrichtlinie aktualisieren

Wenn Sie die Ausführung von MCP-Tools einschränken, verwenden Sie ein Muster mit zwei Regeln:

  1. Regel 1 (MCP-Erkennung und ‑Handshake): Erlaubt MCP-Lifecycle-Methoden ohne Toolaufruf (destination.is_registered == true und destination.agent_registry.mcp_server.method != 'tools/call'). Da Gemini Enterprise die Stream-Einrichtung und ‑Erkennung (initialize, notifications/initialized, tools/list) vor dem Aufrufen eines Tools aushandelt und destination.agent_registry.mcp_server.tool.name erst während tools/call ausgefüllt wird, ist Regel 1 erforderlich, damit die Sitzungsinitialisierung und die Katalogerkennung funktionieren.
  2. Regel 2 (Einschränkung auf Tool-Ebene): Beschränkt die Ausführung von tools/call, sodass nur das Tool subtract zulässig ist (destination.is_registered == true, destination.agent_registry.mcp_server.method == 'tools/call' und destination.agent_registry.mcp_server.tool.name == 'subtract').

Aktualisieren Sie die Manifestdatei der Zugriffsrichtlinienregel mit beiden Regeln:

# 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

Wenden Sie die aktualisierten Regeln auf die IAM-Zugriffsrichtlinie an:

# 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-Zugriffsrichtlinie überprüfen

Prüfen Sie, ob die neue IAM-Zugriffsrichtlinie angewendet wird und nur das Tool zum Entfernen von Objekten zulässig ist:

# 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
  )"

Unzulässigen Tool-Aufruf testen

Kehren Sie zur Chat-Benutzeroberfläche der Gemini Enterprise Web-App zurück und versuchen Sie es mit einer anderen Testanfrage:

what is 100 plus 20?

Der Assistent versucht, add aufzurufen, aber Agent Gateway und IAP bewerten die IAM-Richtlinienbedingung als false und lehnen die Egress-Anfrage mit HTTP 403 Forbidden ab. In der Chat-Benutzeroberfläche wird angezeigt, dass der Assistent Calculate Sum anzeigt und 🤖 Agentgateway Agent ... Working on it. ausführt, während er den blockierten Tool-Aufruf wiederholt. Das ist ganz normal. Es wird bestätigt, dass Agent Gateway und IAP unzulässige Tool-Ausführungen auf Netzwerkebene aktiv abfangen und ablehnen.

Logs in Cloud Logging noch einmal prüfen

Sehen Sie sich die Logeinträge für das Agent Gateway an. Beachten Sie die neuen 403-Einträge, die dem unzulässigen add-Tool-Aufruf entsprechen:

# 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
  )"

Erwartete Ausgabe:

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

Prüfen Sie, ob die zusätzliche Anfrage das Cloud Run-Backend nie erreicht hat:

# 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)"

Der Befehl gibt keine neuen Einträge zurück. Das bestätigt, dass das Agent Gateway die IAM-Zugriffsrichtlinie erfolgreich durchgesetzt hat.

Damit ist der Validierungsteil abgeschlossen. Weiter geht es mit dem Abschnitt Bereinigen.

9. Bereinigen

Führen Sie die folgenden Schritte aus, um die in diesem Lab erstellten Ressourcen und Konfigurationen zu löschen.

Gemini Enterprise-Komponenten entfernen

# 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-Serverkomponenten entfernen

# 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 und IAM-Zugriffsrichtlinien entfernen

# 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- und Firewallkomponenten entfernen

# 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- und VPC-Netzwerkkomponenten entfernen

# 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}

Überschreibungen von Organisationsrichtlinien und lokale Dateien entfernen

# 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

Damit ist die Bereinigung abgeschlossen. Weiter geht es mit dem Fazit.

10. Fazit

Glückwunsch! Sie haben eine End-to-End-Architektur erstellt, die es einer Gemini Enterprise-App ermöglicht, Tools auf einem privaten benutzerdefinierten MCP-Server sicher zu erkennen und aufzurufen:

  • Benutzerdefinierter MCP-Server und Agent Registry:Ein privater FastMCP-Dienst wurde in Cloud Run (--ingress=internal) bereitgestellt und sein Endpunkt und sein Tool-Schema (add und subtract) wurden in Agent Registry registriert.
  • Gemini Enterprise-Integration:Sie haben eine Gemini Enterprise-App bereitgestellt, ausgehenden Tool-Traffic an das Agent Gateway gebunden und den registrierten MCP-Server als REGISTRY_MCP-Daten-Connector angehängt.
  • Privater VPC-Ausgang und Zero-Trust-Governance:Die Ausführung von Tools wird privat über PSC (172.16.20.20) weitergeleitet und das Tool-Level-Prinzip der geringsten Berechtigung wird mit IAP und IAM Unified Access Policies (destination.agent_registry.*) erzwungen.

cosmopup

Cosmpup findet Codelabs einfach nur genial!

Wie geht es weiter?

Wenn Sie Kommentare, Fragen oder Korrekturen haben, können Sie dieses Feedbackformular verwenden.

Vielen Dank!