Gemini Enterprise con salida de Agent Gateway a un servidor de MCP personalizado privado a través de Agent Registry

1. Introducción

En este codelab, se explora la conectividad de salida privada y administrada para Gemini Enterprise con Agent Gateway en el modo agent-to-anywhere (salida). Configurarás una app de Gemini Enterprise para invocar de forma segura un servidor personalizado del Protocolo de contexto del modelo (MCP) alojado en Cloud Run a través del enrutamiento del tráfico por Agent Gateway con interfaces de Private Service Connect (PSC) para conectarse a un extremo de PSC para las APIs de Google en una red de VPC.

En los entornos empresariales, otorgar a los agentes autónomos acceso directo a la red conlleva el riesgo de robo de datos y de ejecución de herramientas no verificadas. Agent Gateway proporciona un punto de aplicación de confianza cero centralizado a nivel de la plataforma que inspecciona de forma dinámica las cargas útiles de herramientas de MCP HTTP transmitibles. Las solicitudes salientes se autentican con una identidad del agente verificable de forma criptográfica y se autorizan a través de Identity-Aware Proxy (IAP) con políticas de acceso unificado (UAP) de IAM con reglas de Common Expression Language (CEL). Esto permite un control de acceso detallado a herramientas y métodos específicos de MCP sin exponer las cargas de trabajo de backend a Internet pública.

Qué compilarás

  • Agent Gateway que opera en modo de salida (del agente a cualquier lugar) con verificación del extremo de Agent Registry
  • Servicio de Cloud Run que aloja un servidor de MCP HTTP privado y transmitible (--ingress=internal) registrado con sus especificaciones de herramientas en Agent Registry
  • Extensión de autorización de Identity-Aware Proxy (IAP) para Agent Gateway
  • Políticas de acceso unificado (UAP) de IAM con condiciones de CEL para la autorización de la herramienta de MCP
  • App de Gemini Enterprise vinculada a Agent Gateway y conectada a un almacén de datos del servidor de MCP personalizado importado de Agent Registry
  • Recursos de red de VPC, zona de Cloud DNS y extremo de PSC para las APIs de Google
  • Adjunto de red de PSC para la salida de VPC privada de Agent Gateway
  • Reglas de políticas de Cloud Next Generation Firewall (NGFW) para proteger el tráfico de VPC

figure1

Fig. 1: Arquitectura del codelab

Qué aprenderá

  • Cómo implementar un servidor de MCP HTTP privado y transmitible desde la fuente en Cloud Run y registrar su endpoint y esquema de herramientas en Agent Registry
  • Cómo configurar Agent Gateway con entradas de registro que cumplen con los requisitos y enrutar las llamadas a herramientas de la app de Gemini Enterprise a través de la puerta de enlace
  • Cómo establecer la salida de VPC privada con interfaces y adjuntos de red de PSC
  • Cómo delegar la autorización de Agent Gateway a Identity-Aware Proxy (IAP)
  • Cómo crear y vincular políticas de acceso unificado (UAP) de IAM con atributos de CEL de destination.agent_registry.* y destination.is_registered para restringir la ejecución de la herramienta de MCP
  • Cómo validar la aplicación de políticas y el tráfico de salida de la red con Cloud Logging

Requisitos

  • Un proyecto de Google Cloud con la facturación habilitada.
  • Una licencia activa de Gemini Enterprise o una prueba de 30 días
  • Permisos de IAM para aprovisionar servicios de redes, Gemini Enterprise y recursos de Agent Platform
  • Una shell compatible con POSIX (bash o zsh) con Google Cloud CLI (gcloud), curl y jq instalados

Con esto, concluye la sección de introducción. A continuación, se abordará la sección de Conceptos.

2. Conceptos

Secuencia de implementación

En este codelab, primero se implementa la infraestructura para que las rutas de red privada y los controles de administración estén operativos antes de registrar y conectar las herramientas de MCP con Gemini Enterprise:

  1. Infraestructura de red: Se aprovisionan subredes de VPC, un extremo de PSC, un adjunto de red de PSC, reglas de política de Cloud NGFW y zonas privadas de Cloud DNS.
  2. Agent Gateway: Implementa Agent Gateway en modo de salida con la integración de Agent Registry (registries) y la salida de VPC privada (networkAttachment).
  3. Políticas de autorización: Configura la extensión de autorización de IAP, la política de autorización de Gateway y la política de acceso unificada (UAP) de IAM con las condiciones de CEL destination.is_registered y destination.agent_registry.*.
  4. Implementa y registra el servidor de MCP: Implementa el servidor de MCP de Math desde la fuente en Cloud Run (--ingress=internal) y registra las especificaciones del servicio y la herramienta (add y subtract) en Agent Registry.
  5. App de Gemini Enterprise: Crea la app de Gemini Enterprise (Engine), configura los parámetros de identidad y observabilidad, y vincula la salida saliente a Agent Gateway (agentGatewaySetting).
  6. Importa un conector de datos de MCP personalizado: Crea y activa el conector de datos REGISTRY_MCP (:setUpDataConnector) para vincular el almacén de datos de respaldo del servidor de MCP registrado a la app de Gemini Enterprise.
  7. Validar: Prueba las ejecuciones de herramientas permitidas y rechazadas en el chat, y verifica la aplicación de políticas en los registros de Agent Gateway, DNS, Firewall y Cloud Run.

Salida de datos de Gemini Enterprise

Gemini Enterprise enruta las solicitudes de herramientas del servidor de MCP personalizado a Agent Gateway cuando se configuran agentGatewaySetting en Engine y use_agent_gateway_egress: true en DataConnector.

figure2

Fig. 2: Arquitectura de salida de Gemini Enterprise

La app de Gemini Enterprise organiza el enrutamiento de herramientas en cuatro áreas clave:

  1. Widget (default_search_widget_config):
    • Publica la interfaz del cliente web. El widget recibe instrucciones del usuario y, luego, inicia sesiones de chat con el motor subyacente.
  2. Asistente principal (assistants/default_assistant/agents/default/core_assistant):
    • Es el agente de razonamiento conversacional raíz dentro del motor. Cuando evalúa una búsqueda del usuario, el Asistente principal determina si se requiere un cálculo aritmético, inspecciona las herramientas disponibles y delega la ejecución al subagente sintetizado de Agent Gateway.
  3. Almacén de datos y Conector de datos:
    • DataStore: Se aprovisiona dentro de un Collection dedicado cuando se ejecuta :setUpDataConnector, y vincula (dataStoreIds) los esquemas de herramientas (add, subtract) importados de Agent Registry, los tipos de argumentos y las instrucciones del agente al Engine de Gemini Enterprise.
    • DataConnector: Administra la conexión de acción REGISTRY_MCP (createBapConnection: true) al servidor de MCP remoto (instance_uri), resuelve el recurso del servidor de MCP de Agent Registry (registry_mcp_server_name) y habilita la salida de Agent Gateway (use_agent_gateway_egress: true).
  4. Agent Identity, Agent Registry y Agent Gateway:
    • Cuando el conector de datos envía la llamada a la herramienta saliente, enruta el tráfico a la puerta de enlace especificada en agentGatewaySetting. El Núcleo Asistente genera un token de identidad SPIFFE que afirma su identidad: principal://agents.global.org-.../agents/default/core_assistant.
    • Agent Gateway se integra con Agent Registry a través del campo registries para resolver de forma dinámica los extremos de destino y los esquemas de herramientas registrados. Propaga los atributos destination.is_registered y destination.agent_registry.*, y los pasa a IAP v2 para que se evalúen en función de las reglas de CEL de la política de acceso unificada (UAP) de IAM antes de permitir el tránsito a la red de VPC.

Conectividad de la VPC de la puerta de enlace

Agent Gateway habilita la conectividad privada de la red de VPC con dos campos YAML:

  • networkConfig.egress.networkAttachment: Dirige el tráfico de IP privada para que se enrute a través del adjunto de red de PSC hacia la red de VPC.
  • dnsPeeringConfig.domains: La resolución de DNS de las redes de intercambio de tráfico con la zona de Cloud DNS de la red de VPC para que los nombres de host de destino (*.run.app) se resuelvan en la dirección IP del extremo privado de PSC definida en la red de VPC.

Limitaciones y requisitos

Aquí concluye la sección de conceptos. A continuación, se encuentra la sección de Configuración.

3. Configuración

Roles de IAM obligatorios

Se requieren los siguientes roles para completar el codelab:

Dominio

Roles de IAM obligatorios

Proyecto y IAM

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

Redes y puerta de enlace

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

Gemini Enterprise y registro

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

Cargas de trabajo y compilación

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

Observabilidad

roles/logging.viewer
roles/logging.logWriter

También puedes usar un rol básico amplio, como roles/owner, combinado con roles/orgpolicy.policyAdmin (ya que roles/owner por sí solo no puede modificar las políticas de la organización).

Accede a tu proyecto

En este codelab, se usa un solo proyecto de Google Cloud. En los pasos de configuración, se usan la CLI de gcloud y los comandos de shell de Linux.

Para comenzar, accede a la línea de comandos de tu proyecto de Google Cloud:

Establece el ID del proyecto

gcloud config set project SET_YOUR_PROJECT_ID_HERE

Autentica la sesión

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

Establece variables de entorno de shell

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

Configura dominios de confianza de identidad del agente

La instrucción if-then-else verifica si el proyecto pertenece a una organización para establecer el dominio de confianza correcto para las identidades del agente principal.

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

Configura el proyecto de facturación y cuota

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

Crea un directorio local para los archivos de configuración

# create config folder
mkdir -p cfg

Si ejecutas una instalación autoadministrada del SDK de Google Cloud (es decir, fuera de Cloud Shell), actualiza los componentes a la versión más reciente.

# update gcloud cli
gcloud components update

Habilita los servicios de la 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

Políticas de la organización

Las restricciones de la política de la organización administradas predeterminadas de Google Cloud restringen las funciones que se usan en este Codelab:

Anula cualquier restricción de política de la organización heredada a nivel del proyecto estableciendo enforce: false de forma explícita.

Inhabilita la restricción personalizada de 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

Inhabilita la restricción de política de acceso

# 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

Cómo verificar y, luego, inhabilitar las restricciones del conector de datos condicionales

De forma predeterminada, discoveryengine.managed.allowedEgressFqdns y discoveryengine.managed.allowedDataSources solo bloquean la creación de conectores si tu proyecto está dentro de un perímetro de Controles del servicio de VPC (VPC SC) o si un administrador de la organización agregó tu proyecto a enforcedProjects.

Primero, inspecciona las políticas vigentes en tu proyecto:

# 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~~ estas restricciones se aplican, para garantizar que no bloqueen la configuración del conector custom_mcp en una organización restringida por políticas o por un SC de VPC, establece enforce: false en ambas políticas de tu proyecto:

# 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

Permisos de IAM

Otorga los roles de IAM necesarios a tu cuenta de usuario y a la cuenta de servicio predeterminada de Compute Engine que usa Cloud Build:

  • Cuenta de usuario (${USER_IDENTITY}):
    • Requiere permisos para implementar e invocar servicios de Cloud Run (roles/run.admin, roles/run.invoker, roles/iam.serviceAccountUser), compilar imágenes de contenedores (roles/cloudbuild.builds.editor), administrar Gemini Enterprise (roles/discoveryengine.admin) y crear políticas de acceso unificado (roles/iam.accessPolicyAdmin).
  • Cuenta de servicio predeterminada de Compute Engine(${PROJ_NO}-compute@developer.gserviceaccount.com):
    • Cloud Build lo usa para organizar el código fuente en Cloud Storage (roles/storage.admin), enviar imágenes a Artifact Registry (roles/artifactregistry.writer) y escribir registros de compilación (roles/logging.logWriter).

Ejecuta los siguientes comandos para asignar las vinculaciones de roles:

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

Verifica los permisos de IAM

Verifica las seis vinculaciones de roles (6) en la cuenta de usuario.

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

Verifica los tres enlaces de roles (3) en la cuenta de servicio de procesamiento predeterminada.

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

Verifica las vinculaciones del agente de servicio (precaución)

En un proyecto nuevo, Google Cloud aprovisiona automáticamente el agente de servicio de Agent Gateway y le otorga roles/agentgateway.serviceAgent cuando se habilita networkservices.googleapis.com por primera vez. Si reutilizas un proyecto existente en el que la limpieza anterior puede haber quitado las vinculaciones predeterminadas del agente de servicio, ejecuta los siguientes comandos como medida de seguridad para garantizar que la identidad y la vinculación de roles estén intactas:

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

Aquí concluye la parte de configuración… a continuación, la sección Red.

4. Red

En esta sección, implementarás una red de VPC con el modo personalizado con una subred /28 dedicada (192.168.10.0/28) que admite la adjunción de red de PSC para la salida de la red de Agent Gateway a la red de VPC.

El extremo de PSC para las APIs de Google se implementa con una sola /32dirección IPv4 interna global (172.16.20.20) para admitir el acceso interno privado a las APIs y los servicios de Google. En este codelab, Agent Gateway se dirige a Cloud Run a través del extremo de PSC resolviendo el dominio run.app. por medio del intercambio de tráfico de Cloud DNS.

Crea redes

Crea una red de VPC global.

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

Crea subredes para el adjunto de red de PSC de Agent Gateway:

# 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

Crea reglas de firewall

Crea una política de firewall para permitir todo el tráfico de salida con el registro habilitado. Se usará para supervisar el tráfico que sale de Agent Gateway hacia la red de VPC. Cloud NGFW admite los niveles Essentials y Standard para la seguridad de la red y la supervisión del tráfico.

# 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

Crea un adjunto de red de PSC

Crea un adjunto de red de Private Service Connect (PSC) configurado para aceptar automáticamente conexiones desde Agent Gateway. El adjunto de red establece el lado de la red de VPC del consumidor de la conexión para vincularse de forma segura con el lado del productor de la Agent Gateway para el tráfico de salida. Para obtener más información sobre los requisitos de subred y las especificaciones de rango de IP, consulta Configura la conectividad de VPC.

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

Verifica el adjunto de red de PSC

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

Recupera el URI del recurso del adjunto de red de PSC y almacénalo en la variable de entorno PSC_NA_URI. Se hará referencia a este URI en la configuración de Agent Gateway (networkConfig.egress.networkAttachment) para aprovisionar la interfaz de PSC para la salida de red a la red de VPC:

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

Crea el extremo de PSC

Se usa un extremo de Private Service Connect (PSC) para las APIs de Google para que Agent Gateway establezca conectividad privada con el servidor de MCP de Cloud Run a través de una ruta de red interna sin exponer el tráfico a Internet público. Las llamadas a herramientas salientes que salen de Agent Gateway hacia la red de VPC resolverán la URL del servicio de Cloud Run de destino (*.run.app) en la dirección IP de este extremo privado.

Reserva una dirección IPv4 interna global para el extremo de PSC. La dirección IP elegida debe ser una dirección /32 que no se superponga con ninguna subred existente en tu red de VPC:

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

Crea un extremo de PSC para las APIs de Google con el paquete all-apis, que incluye 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

Verifica el extremo de PSC

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

Crea una zona y registros de DNS

Cloud DNS se usa para permitir que Agent Gateway se comunique de forma privada con el servidor de MCP alojado en Cloud Run. Cuando Agent Gateway evalúa las solicitudes de herramientas salientes dirigidas a Cloud Run, usa el intercambio de tráfico de DNS (dnsPeeringConfig.domains) para resolver las consultas de DNS de *.run.app con tu zona privada de Cloud DNS asociada a tu red de VPC. El registro DNS privado devuelve la consulta con la dirección IP del extremo de PSC interno (172.16.20.20), lo que permite que las solicitudes de la herramienta de MCP se enruten a través de una ruta de red privada.

Crea una zona administrada de Cloud DNS privada para el dominio 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}

Crea un registro DNS comodín A para *.run.app. que apunte a la dirección IP del extremo de PSC:

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

Crea una política de Cloud DNS para habilitar el registro de consultas de DNS. El registro de DNS captura las solicitudes de resolución de dominio que se originan en Agent Gateway dentro de tu red de VPC, lo que proporciona auditabilidad y te permite verificar que las solicitudes de herramientas de *.run.app se resuelvan correctamente en el extremo interno de PSC:

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

Con esto, concluye la sección de redes. A continuación, se abordará la sección Agent Gateway.

5. Agent Gateway

Agent Gateway especifica registries para las instancias de Agent Registry junto con los campos networkConfig que configuran el adjunto de red de PSC y la configuración del intercambio de tráfico de DNS para la conectividad de VPC privada:

  • registries: Asocia la puerta de enlace con hasta dos instancias de Agent Registry: una regional (../locations/${REGION}) y una global (../locations/global). Esto integra Agent Gateway con Agent Registry para resolver tanto las implementaciones regionales (como los servidores MCP de Cloud Run en ${REGION}) como los recursos globales (como los agentes de Gemini Enterprise y los extremos globales) para la aplicación detallada de la política de IAP v2. Las entradas regionales tienen prioridad sobre las globales cuando se resuelven las URLs de destino.
  • networkAttachment: Apunta al adjunto de red de PSC (psc-na-${REGION}-agw) y conecta Agent Gateway a tu red de VPC para la salida privada.
  • dnsPeeringConfig.domains: Configura run.app. de modo que las consultas de DNS que se originan en Agent Gateway para los servicios de Cloud Run usen el intercambio de tráfico de DNS para resolver los nombres de host en la dirección IP del extremo de PSC de las APIs privadas de Google (172.16.20.20) configurada en tu zona privada de Cloud DNS.

Implementa Agent Gateway

Crea e importa el archivo de configuración de 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}

Verifica la implementación de Agent Gateway

Confirma el registro de agentes y la configuración de red:

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

Resultado esperado:

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}

Verifica que el resultado muestre los detalles de configuración requeridos:

  • registries: Enumera el URI del Agent Registry (${REGION}) regional asociado con la puerta de enlace.
  • egress.networkAttachment: Especifica el URI del adjunto de red de PSC para la salida de VPC.
  • dnsPeeringConfig.domains: Contiene run.app. que apunta a targetNetwork para la resolución de dominios privados.

Inspecciona el adjunto de red de PSC para confirmar la conexión de la puerta de enlace:

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

Verifica que haya un extremo de conexión aceptado:

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

Delegar la autorización

Agent Gateway protege y administra el tráfico de herramientas saliente con políticas de autorización (networksecurity.authzPolicies) integradas en las políticas de acceso unificado (UAP) de Identity-Aware Proxy (IAP).

Si bien Agent Gateway admite reglas básicas intercaladas de ALLOW y DENY, los entornos empresariales requieren una administración centralizada y centrada en la identidad. Con las políticas de acceso unificadas de IAM (o políticas de acceso), puedes administrar las reglas de acceso de salida con las políticas de acceso estándar de IAM v3.

figure3

Fig. 3. Arquitectura de autorización

El flujo de autorización conecta tres componentes:

  1. Política de autorización de la puerta de enlace (authzPolicy):
    • Es un recurso regional que segmenta Agent Gateway.
    • Se configura con policyProfile: REQUEST_AUTHZ y action: CUSTOM para enrutar todas las verificaciones de autorización salientes a la extensión de Authz de IAP.
  2. Extensión de servicio de IAP (authzExtension):
    • Es un recurso regional que delega la autorización de solicitudes a Identity-Aware Proxy (iap.googleapis.com).
    • Evalúa las políticas en el modo ENFORCE con la versión de política V2.
  3. Política y vinculación de acceso unificado de IAM (accessPolicy y policyBinding):
    • Son recursos globales de IAM v3 que contienen reglas de acceso detalladas.
    • Autentica la identidad principal de SPIFFE del agente que llama, verifica el permiso universal iap.googleapis.com/resources.egressViaIAP y evalúa las condiciones de Common Expression Language (CEL) en función de los atributos de destino.

Implementa la extensión de autorización

Crea una configuración de extensión de autorización service-extensions que delegue las decisiones de autorización al servicio de IAP:

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

Verifica la extensión de autorización

Verifica que la extensión de autorización esté activa:

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

Implementa la política de autorización

Crea una configuración de política de autorización de network-security que tenga como objetivo Agent Gateway y delegue la verificación de solicitudes en la extensión de autorización para IAP:

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

Verifica la política de autorización

Verifica que la política de autorización esté activa:

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

Crea políticas de acceso de IAM

Agent Gateway ahora delega las verificaciones de autorización a IAP y resuelve los metadatos de destino desde Agent Registry. A continuación, define una regla de política de acceso unificado de IAM para controlar la ejecución de herramientas salientes.

La IAP evalúa las expresiones de atributos de CEL en función de los siguientes atributos de destino del Registro de agentes:

  • Estado de registro (destination.is_registered):
    • Es un valor booleano (true/false) que indica si el destino está catalogado en Agent Registry.
  • Nombre del servidor de MCP (destination.agent_registry.mcp_server.name):
    • Es el nombre canónico del recurso del servidor de MCP registrado en Agent Registry.
  • Método del MCP (destination.agent_registry.mcp_server.method):
    • Es el método de MCP que se invoca (p. ej., tools/call, tools/list, initialize).
  • Nombre de la herramienta (destination.agent_registry.mcp_server.tool.name):
    • Es el nombre específico de la herramienta invocada (p. ej., subtract o add), lo que permite una autorización detallada a nivel de la herramienta en los servidores de MCP registrados.

Define la regla de la política de acceso de IAM

El manifiesto de la regla de política de IAM especifica lo siguiente:

  • Entidades principales: Es la identidad principal de SPIFFE que representa al agente asistente principal de Gemini Enterprise.
  • Permisos: El permiso universal iap.googleapis.com/resources.egressViaIAP que se requiere para todo el tráfico de salida regido por IAP.
  • Condiciones: Una expresión CEL (destination.is_registered == true) que garantiza que el agente solo pueda invocar extremos catalogados en el Agent Registry.

Crea el archivo de manifiesto de la regla de política:

# 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

Implementa la política de acceso de IAM

Crea la política de acceso global de IAM con las reglas definidas en el archivo de manifiesto:

# 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

Verifica la política de acceso de IAM

Verifica que la política de acceso de IAM se haya creado correctamente y, luego, inspecciona los detalles de la regla:

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

Resultado esperado:

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}

Vincula la política de acceso de IAM al proyecto

Para activar la aplicación en todas las puertas de enlace de agentes de tu proyecto, crea una vinculación de política que adjunte la política de acceso de IAM al recurso del proyecto:

# 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

Verifica la vinculación de la política de acceso de IAM

Verifica que los puntos de vinculación de la política activa apunten a la política y el destino correctos:

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

Resultado esperado:

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}

Aquí concluye la sección sobre la puerta de enlace del agente… A continuación, se abordará la sección sobre el servidor de MCP.

6. Servidor de MCP

En esta sección, crearás un servidor FastMCP personalizado que exponga las herramientas add y subtract, y lo implementarás en Cloud Run directamente desde el código fuente. Durante la implementación de la fuente (--source), Cloud Build empaquetará la imagen del contenedor con los Dockerfile y uv incluidos (que instalan las dependencias definidas en pyproject.toml y lanzan server.py).

Una vez que se implementa el servicio de Cloud Run, registras el servidor de MCP en Agent Registry junto con su especificación de herramientas (toolspec.json) para que Gemini Enterprise pueda descubrir e invocar sus herramientas.

Crea la aplicación del servidor de MCP

Crea un directorio de proyecto math-wizard para el código de la aplicación:

# create directory for code
mkdir -p math-wizard

Escribe el archivo de manifiesto del proyecto de 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

En el código, se incluyen algunas funciones de instrumentación adicionales para capturar los encabezados HTTP entrantes (mcp-session-id, x-forwarded-for, user-agent y x-cloud-trace-context) para la validación de Cloud Logging y Cloud Trace.

Escribe el archivo de código de la aplicación:

# 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

Escribe el archivo Dockerfile para definir las instrucciones de compilación de la imagen del contenedor y los comandos de inicio:

# 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

Implementa el servicio en Cloud Run

Implementa el servidor de MCP desde la fuente con Cloud Build (que usa la cuenta de servicio de Compute predeterminada del proyecto ${PROJ_NO}-compute@developer.gserviceaccount.com):

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

Verifica la implementación de Cloud Run

Verifica los detalles del servicio de Cloud Run para comprobar su configuración activa:

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

Resultado esperado:

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

Cómo registrar el servidor de MCP en Agent Registry

Para permitir que Gemini Enterprise descubra las herramientas exactas disponibles en el servidor de MCP, se debe proporcionar un archivo de especificaciones de herramientas (toolspec.json) durante el registro en Agent Registry.

Crea la especificación de la herramienta de 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

Cómo registrar el servidor de MCP en Agent Registry

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

Verifica el servidor de MCP en Agent Registry

Verifica que el servicio de Cloud Run implementado aparezca como un servidor de MCP registrado en la región junto con su URL de extremo y las herramientas disponibles:

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

Resultado esperado:

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

Consulta la especificación de configuración del servicio para ver que registra las definiciones exactas de herramientas, los esquemas de entrada y las anotaciones de comportamiento para cada herramienta:

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

Aquí concluye la sección del servidor de MCP. A continuación, se abordará la sección de Gemini Enterprise.

7. Gemini Enterprise

En esta sección, crearás y configurarás una app de Gemini Enterprise y un recurso de almacén de datos del servidor de MCP personalizado vinculado.

Modelo de recursos de Discovery Engine

Una app de Gemini Enterprise (representada como un recurso Engine en la API de Discovery Engine) es la capa central de organización y la interfaz de conversación para los usuarios finales. Administra las sesiones de chat de los usuarios, fundamenta los modelos generativos en los datos de la empresa y coordina la ejecución dinámica de herramientas.

Las apps de Gemini Enterprise interactúan con los datos y los sistemas a través de almacenes de datos:

  • Almacenes de datos de conocimiento: Transfiere y, luego, indexa contenido estático (p. ej., Cloud Storage, Google Drive, BigQuery) para la Generación mejorada por recuperación (RAG).
  • Conectores de datos (proveedores de acciones): Se conectan a APIs dinámicas de terceros o personalizadas. Un almacén de datos del servidor de MCP personalizado expone herramientas definidas por el Protocolo de contexto del modelo (MCP), lo que permite que el modelo llame de forma dinámica a funciones externas durante una conversación.

Enrutamiento de salida a través de Agent Gateway

De forma predeterminada, Gemini Enterprise enruta el tráfico de ejecución de conectores y herramientas a través de redes públicas. Sin embargo, para las cargas de trabajo de VPC privadas y la administración de confianza cero, el motor se puede configurar para enrutar el tráfico de salida a través de Agent Gateway:

  • Cuando crees el almacén de datos del servidor de MCP personalizado más adelante en este lab, habilitarás Route egress through Agent Gateway en la configuración del almacén de datos.
  • Esto vincula las llamadas a herramientas salientes del motor a tu Agent Gateway regional, lo que garantiza que todas las solicitudes de MCP incluyan el Agent Identity de la app, se sometan a la autorización en el tiempo de ejecución con las políticas de acceso unificado (UAP) de IAP y de IAM, y atraviesen el adjunto de red de PSC hacia tu VPC privada.

Crea una app de Gemini Enterprise

En el siguiente método, se usa la API de discoveryengine.googleapis.com para crear los recursos y la configuración de la app de Gemini Enterprise. Para realizar la configuración con la IU de la consola de Google Cloud, consulta Crea una app para obtener instrucciones.

# 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

Verifica la creación de la app

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

Consulta los detalles del motor para ver la configuración creada:

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

Ten en cuenta las siguientes propiedades completadas por el servidor en la respuesta JSON:

  • name: Es la ruta de acceso canónica al recurso (projects/${PROJ_NO}/locations/global/collections/default_collection/engines/${GE_APP_ID}).
  • sessionConfig.sessionManagementPolicy: El valor predeterminado es "VERTEX_AI_MANAGED", que conserva el estado de las conversaciones de varios turnos y las llamadas a herramientas en Agent Platform (anteriormente conocida como Vertex AI).
  • observabilityConfig.observabilityEnabled: El valor predeterminado es true para las métricas de referencia (el registro detallado de la carga útil de la herramienta y la instrucción se habilita en un paso posterior).

Habilita el proveedor de identidad

Habilita Google Identity como proveedor de identidad para la autenticación de usuarios finales en tu app de Gemini Enterprise.

El siguiente método usa la API de discoveryengine.googleapis.com para configurar el proveedor de identidad de la app de Gemini Enterprise. Para realizar la configuración con la IU de la consola de Google Cloud, consulta Configura el proveedor de identidad para obtener instrucciones.

# 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

Verifica el proveedor de identidad

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

El "idpType": "GSUITE" de salida corresponde al proveedor de identidad de Google.

(Opcional) Habilita la licencia de prueba de Gemini Enterprise

Si usas un proyecto que tiene licencias de Gemini Enterprise asignadas, puedes omitir este paso. Si usas un proyecto nuevo sin licencia, continúa y sigue estos pasos.

Crea un recurso de configuración de licencias para otorgar derechos a los usuarios de Gemini Enterprise durante 30 días. Esto establecerá la licencia predeterminada para la nueva prueba, de modo que a cualquier usuario que acceda se le otorgará automáticamente un puesto:

# 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

Verifica que se haya aplicado la licencia

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

Verifica "subscriptionTerm": "SUBSCRIPTION_TERM_ONE_MONTH" y "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}"

Verifica ../free_trial_gemini" y "enableLicenseAutoRegister": true.

Habilita la configuración de observabilidad

Habilitar la observabilidad a nivel de la app de Gemini Enterprise (motor) te permite ver las interacciones del asistente principal con los datos de métricas en el Explorador de métricas y correlacionar los seguimientos de extremo a extremo en 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

Verifica la configuración de observabilidad

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

Busca "sensitiveLoggingEnabled": true.

Vinculación a Agent Gateway

El enrutamiento del tráfico saliente de Gemini Enterprise a través de Agent Gateway establece un límite centralizado de administración y aplicación de seguridad de confianza cero para todas las invocaciones de herramientas de agentes de IA:

  • Aplicación centralizada de políticas: Agent Gateway actúa como un proxy intercalado que evalúa las solicitudes de herramientas salientes en función de las políticas de autorización y los controles de administración antes de que el tráfico salga del entorno del agente.
  • Salida de red privada: La vinculación de Gemini Enterprise a Agent Gateway garantiza que las llamadas a herramientas dirigidas a servidores de MCP privados en Cloud Run se enruten de forma segura a través de Private Service Connect (PSC), lo que omite Internet pública.
  • Capacidad de auditoría unificada: Proporciona registros de solicitudes, datos de telemetría y registros de auditoría centralizados en todos los servidores de MCP y las herramientas externas conectados.

Si configuras agentGatewaySetting en tu app de Gemini Enterprise, las llamadas salientes a herramientas y agentes que inician las búsquedas de los usuarios finales (como las llamadas a servidores MCP personalizados importados desde Agent Registry y agentes de A2A) se enrutan automáticamente a través de Agent Gateway.

Aplica parches al motor agentGatewaySetting para habilitarlo:

# 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

Verifica la vinculación de Agent Gateway

Recupera la configuración de la app para confirmar la vinculación de 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}'

Resultado esperado:

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

Crea un almacén de datos del servidor de MCP personalizado

En esta sección, conectarás el servidor de MCP a Gemini Enterprise creando un almacén de datos de MCP personalizado.

Con la API de Discovery Engine, este es un proceso de dos pasos:

  1. Crear (:setUpDataConnector): Crea un recurso Collection dedicado (${MCP_NAME}-%timestamp-collection), adjunta el DataConnector (custom_mcp) y aprovisiona su DataStore de respaldo (..._mcp_data).
  2. Activate (PATCH .../dataConnector?updateMask=actionConfig): Activa el entorno de ejecución de la acción del conector (actionState: "ACTIVE") con la especificación de la herramienta del Agent Registry y vincula el DataStore (dataStoreIds) a tu Engine de 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}"

Crea un conector de datos

# 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

Verifica la creación del conector de datos

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

Verifica que el campo "registry_mcp_server_name" se complete con el UUID de Agent Registry para el servidor de MCP:

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

Consulta la entrada del registro del servidor de MCP en la IU de la consola de Google Cloud:

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

Activa el conector de datos

# 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

Verifica las vinculaciones del servidor de MCP personalizado

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

Verifica si el almacén de datos "dataStoreIds": "collection-math-wizard-_mcp_data" está vinculado.

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

Verifica que "state": "ACTIVE" tenga todos los parámetros propagados.

Acciones de la herramienta

Cuando inspecciones el almacén de datos math-wizard-collection en el panel de Gemini Enterprise, notarás que no se usa la pestaña Acciones y que el botón ↻ Recargar acciones personalizadas está inhabilitado. Este es el comportamiento esperado.

Visualiza la página de detalles del almacén de datos en la IU de la consola de Google Cloud:

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

Según cómo conectes un servidor de MCP personalizado a Gemini Enterprise, el descubrimiento y la administración de herramientas se controlan de una de las siguientes dos maneras:

  • MCP personalizado directo (flujo de trabajo de BYO_MCP): Cuando configuras un servidor de MCP personalizado directamente en Gemini Enterprise sin Agent Registry, el almacén de datos administra el catálogo de herramientas (connectorModes: ["FEDERATED", "ACTIONS"]). Debes abrir la pestaña Actions, hacer clic en ↻ Reload custom actions para recuperar el esquema tools/list y activar o desactivar manualmente las herramientas individuales (add y subtract) en la IU.
  • Importación de Agent Registry (flujo de trabajo de REGISTRY_MCP que se usa en este codelab): Cuando importas un servidor de MCP desde Agent Registry, Agent Registry actúa como la fuente autorizada de verdad para el extremo de MCP, sus metadatos de interfaz y su catálogo de herramientas (connectorModes: ["FEDERATED"]). Gemini Enterprise habilita automáticamente las herramientas de MCP registradas en el tiempo de ejecución a través de la Agent Gateway del motor sin que tengas que volver a cargar o activar acciones de forma manual en la IU del almacén de datos.

Con esto, concluye la sección de la app de Gemini Enterprise. A continuación, se abordará la sección Validar.

8. Validar

En esta sección, activarás llamadas a herramientas de MCP en vivo desde la app web de Gemini Enterprise y rastrearás el flujo de solicitudes en los registros de Agent Gateway, Cloud DNS, el firewall de VPC y Cloud Run. Luego, ajustarás la política de acceso unificada de IAM para permitir subtract y bloquear add, y verificarás la aplicación de la política de confianza cero en la puerta de enlace.

Acceso de usuario

Construye la URL de la app web de Gemini Enterprise:

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

Sigue el vínculo para abrir la interfaz de chat de la app web de Gemini Enterprise en tu navegador y haz clic en Comenzar.

Probar consultas del agente en el chat

En la IU de chat, confirma que el conector de datos math-wizard-collection esté habilitado. Para ello, haz clic en el ícono de pieza de rompecabezas de Conectores en la parte inferior del cuadro de chat. Deberías ver un botón de activación que aparece activado (con color).

Prueba las siguientes consultas de prueba:

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

Verifica que el asistente devuelva las respuestas correctas y muestre una insignia de cita de acción interactiva (como Math Calculation (8s) 🤖 Agentgateway Agent) debajo de cada respuesta, lo que confirma que se ejecutó la herramienta.

Inspecciona los registros en Cloud Logging

Verifica que Gemini Enterprise haya enrutado las llamadas a herramientas a través de Agent Gateway y la red de VPC privada. Para ello, inspecciona los registros en Cloud Logging.

1. Verifica la autorización de Agent Gateway y de IAP

Confirma que Agent Gateway interceptó la solicitud, resolvió el destino en Agent Registry, delegó la autorización en IAP y permitió la llamada a la herramienta:

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

Verifica que el resultado contenga lo siguiente:

  • STATUS: 200 (ejecución correcta) y 202 (confirmación de notifications/initialized).
  • SERVER_IP: Es la IP del extremo del PSC de las APIs de Google (172.16.20.20:443).
  • MCP_METHOD y TOOL: Es la secuencia del protocolo de MCP (notifications/initialized, tools/list y tools/call con add o subtract).
  • AUTHZ: ALLOWED (egreso autorizado por IAP).
  • REGISTRY_MCP: Es el ID del recurso del Agent Registry resuelto (agentregistry-...).

2. Verifica el tránsito de DNS y firewall

Confirma que Cloud DNS resolvió el nombre de host en el extremo de PSC y que el firewall permitió el tráfico desde la interfaz de 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
  )"

Verifica los siguientes valores:

  • DNS QUERY_NAME y RDATA: Resuelve math-wizard-...run.app. (registro A, NOERROR) en 172.16.20.20.
  • Firewall SRC_IP y DEST_IP: 192.168.10.2 (IP de la interfaz de PSC de Agent Gateway) a 172.16.20.20:443.
  • Firewall RULE y DISPOSITION: Coincide firewallPolicy:fw-policy-... con ALLOWED.

3. Verifica la ejecución de la herramienta de Cloud Run

Confirma que el contenedor de Cloud Run recibió y procesó la llamada a la herramienta:

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

Verifica que textPayload muestre entradas de ejecución de herramientas (p. ej., >>> 🛠️ Tool: 'subtract' called with numbers '[x]' and '[y]').

Prueba la aplicación de la política de privilegio mínimo

En la política de acceso de IAM inicial, se permitía cualquier método o herramienta, siempre y cuando el destino estuviera registrado (destination.is_registered == true). En este paso, actualiza la política para aplicar el principio de privilegio mínimo permitiendo solo la herramienta subtract y bloqueando add.

Actualiza la política de acceso de IAM

Cuando restrinjas la ejecución de herramientas de MCP, usa un patrón de dos reglas:

  1. Regla 1 (descubrimiento y handshake del MCP): Permite métodos de ciclo de vida del MCP que no son de llamada a herramientas (destination.is_registered == true y destination.agent_registry.mcp_server.method != 'tools/call'). Dado que Gemini Enterprise negocia la configuración y el descubrimiento de transmisiones (initialize, notifications/initialized, tools/list) antes de invocar una herramienta, y destination.agent_registry.mcp_server.tool.name solo se completa durante tools/call, la regla 1 es necesaria para que funcionen la inicialización de la sesión y el descubrimiento del catálogo.
  2. Regla 2 (restricción a nivel de la herramienta): Restringe la ejecución de tools/call para que solo se permita la herramienta subtract (destination.is_registered == true, destination.agent_registry.mcp_server.method == 'tools/call' y destination.agent_registry.mcp_server.tool.name == 'subtract').

Actualiza el archivo de manifiesto de la regla de política de acceso con ambas reglas:

# 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

Aplica las reglas actualizadas a la política de acceso de 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

Verifica la política de acceso de IAM

Verifica que se aplique la nueva política de acceso de IAM y que solo se permita la herramienta de resta:

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

Prueba una llamada a la herramienta prohibida

Vuelve a la IU de chat de la app web de Gemini Enterprise y prueba otra consulta de prueba:

what is 100 plus 20?

El asistente intenta invocar add, pero Agent Gateway y IAP evalúan la condición de la política de IAM como false y rechazan la solicitud de salida con HTTP 403 Forbidden. En la IU de chat, verás que el asistente muestra Calculate Sum y gira sobre 🤖 Agentgateway Agent ... Working on it. mientras vuelve a intentar la llamada a la herramienta bloqueada. Este es el comportamiento esperado. Confirma que Agent Gateway y el IAP interceptan y rechazan activamente la ejecución de herramientas no permitidas a nivel de la red.

Vuelve a inspeccionar los registros en Cloud Logging

Visualiza las entradas de registro de Agent Gateway y observa las nuevas entradas 403 que corresponden a la llamada a la herramienta add no permitida:

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

Resultado esperado:

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

Verifica que la solicitud adicional nunca haya llegado al backend de 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)"

El comando no devuelve ninguna entrada nueva, lo que confirma que Agent Gateway aplicó correctamente la política de acceso de IAM.

Aquí concluye la parte de validación. A continuación, se encuentra la sección Limpieza.

9. Limpieza

Sigue estos pasos para borrar los recursos y la configuración que creaste en este lab.

Cómo quitar componentes de 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"}}'

Quita los componentes del servidor de 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}

Quita las políticas de acceso de IAM y de Agent Gateway

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

Cómo quitar los componentes de DNS y firewall

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

Quita los componentes de PSC y de la red de 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}

Cómo quitar anulaciones de políticas de la organización y archivos locales

# 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

Aquí concluye el trabajo de limpieza. A continuación, ve a la Conclusión.

10. Conclusión

¡Felicitaciones! Creaste una arquitectura de extremo a extremo que permite que una app de Gemini Enterprise descubra y llame de forma segura a herramientas en un servidor de MCP personalizado privado:

  • Servidor de MCP personalizado y Agent Registry: Se implementó un servicio de FastMCP privado en Cloud Run (--ingress=internal) y se registró su endpoint y esquema de herramientas (add y subtract) en Agent Registry.
  • Integración de Gemini Enterprise: Se aprovisionó una app de Gemini Enterprise, se vinculó el tráfico de herramientas saliente a Agent Gateway y se adjuntó el servidor de MCP registrado como un conector de datos de REGISTRY_MCP.
  • Salida de VPC privada y gobernanza de confianza cero: La ejecución de herramientas se enruta de forma privada a través de PSC (172.16.20.20) y se aplica el principio de privilegio mínimo a nivel de la herramienta con las políticas de acceso unificado de IAP y IAM (destination.agent_registry.*).

cosmopup

Cosmpup cree que los codelabs son lo mejor de lo mejor.

¿Qué sigue?

Si quieres hacer comentarios, preguntas o correcciones, usa este formulario de comentarios.

¡Gracias!