1. Introduction
Cet atelier de programmation explore la connectivité de sortie avec adresse IP statique pour Gemini Enterprise à l'aide de la passerelle d'agent en mode agent-to-anywhere (sortie). Vous allez configurer une application Gemini Enterprise pour appeler un serveur MCP (Model Context Protocol) personnalisé, protégé par une liste d'adresses IP sources autorisées stricte et une authentification OAuth 2.0, en acheminant tout le trafic sortant via Agent Gateway à l'aide d'une configuration de modèle de connectivité. Un rattachement de réseau Private Service Connect (PSC) connecte Agent Gateway au réseau VPC, et Cloud NAT fournit une adresse IP externe stable pour le trafic sortant vers Internet.
Par défaut, les connexions sortantes de Gemini Enterprise vers des points de terminaison Internet publics proviennent de pools d'adresses IP Google dynamiques et partagées qui ne peuvent pas être associées à une seule règle de liste d'autorisation d'adresses IP appartenant au client. L'association d'Agent Gateway à un AgentConnectivityTemplate en mode ALL_TRAFFIC achemine tout le trafic sortant de l'agent vers le réseau VPC, où Cloud NAT traduit les connexions Internet en une adresse IPv4 externe statique réservée que vous contrôlez, tout en préservant la gouvernance centralisée des outils MCP via Agent Registry et Identity-Aware Proxy (IAP).
Objectif de l'atelier
- Modèle de connectivité d'agent (
vpcEgress: ALL_TRAFFIC) et Agent Gateway fonctionnant en mode sortie (agent vers n'importe quelle destination) avec validation du point de terminaison Agent Registry - Réseau VPC, rattachement de réseau PSC, routeur Cloud Router et passerelle Cloud NAT liés à une adresse IPv4 externe statique réservée
- Serveur de ressources MCP HTTP diffusables externes (
mcp-sprockets) avec Caddy TLS en façade, limité par des règles de pare-feu à l'adresse IP statique Cloud NAT et validant les jetons porteurs Google OAuth 2.0 délégués par l'utilisateur par rapport àhttps://oauth2.googleapis.com/tokeninfo - Écran de consentement OAuth 2.0 de la plate-forme d'authentification Google et identifiants client OAuth 2.0 pour les applications Web (
accounts.google.cometoauth2.googleapis.com/token) - Entrée du catalogue de serveurs MCP Agent Registry et spécification de l'outil (
toolspec.json) - Extension d'autorisation Identity-Aware Proxy (IAP) et règle d'autorisation de la passerelle pour Agent Gateway
- Application Gemini Enterprise liée à Agent Gateway et connectée à un datastore de serveur MCP personnalisé OAuth 2.0 importé depuis Agent Registry
Fig. 1 Architecture de l'atelier de programmation
Objectifs
- Configurer un
AgentConnectivityTemplateavecvpcEgress: ALL_TRAFFICpour acheminer tout le trafic sortant d'Agent Gateway vers un réseau VPC - Réserver une adresse IPv4 externe statique et l'associer à Cloud NAT sur un sous-réseau de rattachement de réseau PSC
- Déployer un serveur de ressources MCP HTTP diffusable externe qui valide les jetons porteurs Google OAuth 2.0 (
oauth2.googleapis.com/tokeninfo) et restreint strictement son pare-feu d'entrée à l'adresse IP statique Cloud NAT (${NAT_EXT_IP}/32) - Configurer les identifiants client Google Identity OAuth 2.0 et enregistrer un serveur MCP et son schéma d'outil dans Agent Registry
- Connecter un serveur MCP OAuth 2.0 enregistré à Gemini Enterprise et router les appels d'outils délégués par l'utilisateur via Agent Gateway
- Valider la traduction d'adresses IP statiques, la validation de l'identité OAuth 2.0 de l'utilisateur final (
authenticated_user) et l'application des règles de la passerelle à l'aide des commandes CLI et de Cloud Logging
Ce dont vous avez besoin
- Un projet Google Cloud avec facturation activée
- Une licence Gemini Enterprise active ou un essai de 30 jours
- Autorisations IAM pour provisionner les services réseau, les règles d'administration, Gemini Enterprise et les ressources Agent Platform
- Un shell compatible POSIX (
bashouzsh) avec Google Cloud CLI (gcloud),curletjqinstallés
La partie "Introduction" est terminée. Passons à la section Concepts.
2. Concepts
Séquence de déploiement
Cet atelier de programmation déploie d'abord l'infrastructure de mise en réseau et de gouvernance afin que les chemins de sortie IP statiques et les contrôles de passerelle soient opérationnels avant l'enregistrement et la connexion des outils MCP avec Gemini Enterprise :
- Infrastructure réseau : réservez des adresses IPv4 externes statiques et provisionnez le VPC de sortie, le sous-réseau de rattachement PSC, le rattachement de réseau PSC, Cloud Router, la passerelle Cloud NAT et les règles de pare-feu réseau MCP externes.
- Modèle de connectivité d'agent et Agent Gateway : déployez
AgentConnectivityTemplate(vpcEgress: ALL_TRAFFIC) etAgentGatewayrégional en mode sortie (AGENT_TO_ANYWHERE) avec l'intégration d'Agent Registry (registries). - Règles d'autorisation : configurez l'extension d'autorisation IAP (
AuthzExtension), la règle d'autorisation de la passerelle (AuthzPolicy) et la règle d'accès unifiée IAM v3 (AccessPolicyetPolicyBinding). - Déployer et enregistrer le serveur MCP : déployez le serveur de ressources OAuth 2.0
mcp-sprocketsexterne derrière Caddy TLS, vérifiez l'applicationtokeninfode Google OAuth 2.0, verrouillez strictement son pare-feu d'entrée sur l'adresse IP statique Cloud NAT (${NAT_EXT_IP}/32), puis enregistrez les spécifications du service et de l'outil (get_sprocketsetget_sprocket_by_id) dans Agent Registry. - Application Gemini Enterprise et client OAuth 2.0 : configurez le fournisseur d'identité Google, la licence d'essai, l'écran de consentement OAuth 2.0 et les identifiants client de l'application Web (
OAUTH_CLIENT_IDetOAUTH_CLIENT_SECRET), créez l'application Gemini Enterprise (Engine) et associez la sortie sortante à Agent Gateway (agentGatewaySetting). - Importer un connecteur de données MCP personnalisé : créez et activez le connecteur de données
REGISTRY_MCP(:setUpDataConnector) configuré avecauth_type: "OAUTH"pour associer le datastore de sauvegarde du serveur MCP enregistré à l'application Gemini Enterprise. - Valider : effectuez le flux de consentement OAuth 2.0 unique de l'utilisateur, appelez les outils MCP via l'assistant Gemini Enterprise (en confirmant
egress_source_ipetauthenticated_user), puis vérifiez l'application des règles et la traduction NAT d'adresse IP statique dans Cloud Logging.
Architecture de serveur de ressources MCP protégé par OAuth et IdP central
Dans les déploiements d'entreprise, la gestion des identités et l'exécution des outils suivent la séparation standard des rôles OAuth 2.0 entre un fournisseur d'identité centralisé (serveur d'autorisation) et un serveur de ressources MCP protégé :
Rôle OAuth 2.0 | Composant de cet atelier de programmation | Responsabilité |
Propriétaire de la ressource | Utilisateur final ( | Se connecte à l'application Web Gemini Enterprise et accorde l'autorisation lors du flux d'autorisation OAuth 2.0 à trois étapes. |
Client OAuth 2.0 | Gemini Enterprise | Contient |
Serveur d'autorisation | Google Identity OAuth 2.0 ( | Authentifie l'utilisateur lors de la redirection du consentement du navigateur et émet les jetons d'accès et d'actualisation OAuth 2.0 pour Gemini Enterprise. |
Serveur de ressources | Serveur | Applique l'identité réseau de couche 3 à l'aide de son pare-feu VPC ( |
Étant donné que la redirection du consentement du navigateur (accounts.google.com) et l'échange de jetons du canal de communication inverse (oauth2.googleapis.com/token) se produisent au niveau des points de terminaison OAuth 2.0 gérés par Google, le pare-feu du serveur MCP externe ne reçoit que des requêtes JSON-RPC MCP d'exécution (POST /mcp) de l'Agent Gateway via Cloud NAT, ce qui permet de limiter strictement son pare-feu d'entrée à ${NAT_EXT_IP}/32.
Modèle de ressources Discovery Engine
Une application Gemini Enterprise (représentée par une ressource Engine dans l'API Discovery Engine) est la couche d'orchestration centrale et l'interface conversationnelle pour les utilisateurs finaux. Il gère les sessions de chat des utilisateurs, ancre les modèles génératifs sur les données de l'entreprise et coordonne l'exécution dynamique des outils.
Les applications Gemini Enterprise interagissent avec les données et les systèmes par le biais de datastores :
- Dépôts de données de connaissances : ingérez et indexez du contenu statique (par exemple, Cloud Storage, Google Drive, BigQuery) pour la génération augmentée par récupération (RAG).
- Connecteurs de données (fournisseurs d'actions) : connectez-vous à des API tierces ou personnalisées dynamiques. Un datastore de serveur MCP personnalisé expose les outils définis par le protocole MCP (Model Context Protocol), ce qui permet au modèle d'appeler dynamiquement des fonctions externes lors d'une conversation.
Sortie de données Gemini Enterprise
Gemini Enterprise achemine les requêtes d'outils de serveur MCP personnalisé vers Agent Gateway lorsque agentGatewaySetting sur Engine et use_agent_gateway_egress: true sur DataConnector sont configurés.
Fig. 2. Architecture de sortie Gemini Enterprise
L'application Gemini Enterprise organise le routage des outils dans quatre domaines clés :
- Widget (
default_search_widget_config) :- Fournit l'interface client Web. Le widget reçoit les requêtes de l'utilisateur, déclenche la redirection unique du consentement utilisateur OAuth 2.0 lorsqu'un outil nécessite une autorisation et lance des sessions de chat avec le moteur sous-jacent.
- Assistant Core (
assistants/default_assistant/agents/default/core_assistant) :- Agent de raisonnement conversationnel racine dans le moteur. Lorsqu'il évalue une requête utilisateur, l'Assistant Core inspecte les outils disponibles et délègue l'exécution au sous-agent Agent Gateway synthétisé.
- Data Store et connecteur de données :
DataStore: provisionné dans unCollectiondédié lorsque:setUpDataConnectors'exécute, il associe (dataStoreIds) les schémas d'outils de l'Agent Registry importés (get_sprockets,get_sprocket_by_id), les types d'arguments et les instructions de l'agent auEngineGemini Enterprise.DataConnector: gère la connexion d'actionREGISTRY_MCP(createBapConnection: true) au serveur MCP distant (instance_uri), résout la ressource de serveur MCP du registre d'agent (registry_mcp_server_name), associe le jeton porteur OAuth 2.0 mis en coffre par l'utilisateur (Authorization: Bearer [access_token]) et active la sortie de la passerelle d'agent (use_agent_gateway_egress: true).
- Agent Identity, Agent Registry et Agent Gateway :
- Lorsque le connecteur de données distribue l'appel d'outil sortant, il achemine le trafic vers la passerelle spécifiée dans
agentGatewaySetting. L'assistant Core génère un jeton d'identité SPIFFE qui affirme son identité de charge de travail :principal://agents.global.org-.../agents/default/core_assistant. - Agent Gateway s'intègre à Agent Registry à l'aide du champ
registriespour résoudre dynamiquement les points de terminaison de destination et les schémas d'outils enregistrés, évaluer les règles d'autorisation à l'aide d'IAP et transférer les requêtes autorisées (en conservant l'en-têteAuthorization: Bearerde l'utilisateur) dans le réseau VPC à l'aide deAgentConnectivityTemplate.
- Lorsque le connecteur de données distribue l'appel d'outil sortant, il achemine le trafic vers la passerelle spécifiée dans
Connectivité du réseau VPC de passerelle et NAT avec adresse IP statique
Agent Gateway est compatible avec la connectivité au réseau VPC à l'aide d'une ressource AgentConnectivityTemplate référencée par agentConnectivityTemplate sur la passerelle. Le modèle egressNetworkConfig définit la manière dont le trafic entre dans votre VPC via un rattachement de réseau PSC :
PRIVATE_RANGES_ONLY(par défaut) : achemine uniquement les plages d'adresses IP privées RFC 1918, RFC 6598 et de classe E via le rattachement de réseau PSC. Le trafic destiné à Internet contourne votre VPC et sort directement via la sortie Internet par défaut de Google.ALL_TRAFFIC(utilisé dans cet atelier de programmation) : achemine tout le trafic sortant d'Agent Gateway (y compris les points de terminaison MCP Internet public et partenaires externes) vers votre sous-réseau VPC via le rattachement de réseau PSC (10.10.10.2).
Lorsque vous utilisez le mode ALL_TRAFFIC, le sous-réseau de rattachement du PSC nécessite deux configurations :
- Accès privé à Google (
--enable-private-ip-google-access) : permet de s'assurer que les appels internes aux API Google Cloud (*.googleapis.com) continuent d'être acheminés de manière privée au sein du réseau Google. - Cloud Router et Cloud NAT (
MANUAL_ONLY) : le trafic destiné à Internet qui entre dans le sous-réseau de rattachement PSC suit la route par défaut (0.0.0.0/0) via Cloud NAT, qui effectue la traduction d'adresse réseau source (SNAT) vers votre adresse IPv4 externe statique réservée (${NAT_EXT_IP}). Les pare-feu externes peuvent donc limiter l'accès entrant strictement à${NAT_EXT_IP}/32.
Limites et exigences
- StreamableHTTP uniquement : le transport hérité des événements envoyés par le serveur (SSE) n'est pas pris en charge. Les serveurs MCP doivent utiliser StreamableHTTP.
- Remplacer la règle d'administration : vous devez remplacer explicitement la règle d'administration pour les dépôts de données MCP personnalisés avant d'enregistrer le connecteur de données.
- Alignement régional : Gemini Enterprise applique un alignement régional entre l'emplacement de l'application, Agent Gateway et Agent Registry :
Emplacement de l'application Gemini Enterprise | Emplacement de l'Agent Gateway et de la passerelle NAT | Emplacement d'Agent Registry |
|
|
|
|
|
|
|
|
|
La partie sur les concepts est terminée. Passons à la section Configuration.
3. Configuration
Rôles IAM requis
Les rôles suivants sont requis pour effectuer cet atelier de programmation :
Domaine | Rôles IAM requis |
Projet et IAM |
|
Réseau et passerelle |
|
Gemini Enterprise et Registry |
|
Charges de travail |
|
Observabilité |
|
Vous pouvez également utiliser un rôle de base étendu tel que roles/owner combiné à roles/orgpolicy.policyAdmin (car roles/owner seul ne peut pas modifier les règles d'administration).
Accéder à votre projet
Cet atelier de programmation utilise un seul projet Google Cloud. Les étapes de configuration utilisent la CLI gcloud et les commandes du shell Linux.
Commencez par accéder à la ligne de commande de votre projet Google Cloud :
- Cloud Shell à l'adresse
shell.cloud.google.com, ou - Un terminal local avec
gcloudCLI installé
Définir l'ID de votre projet
# set target project id
gcloud config set project SET_YOUR_PROJECT_ID_HERE
Authentifier la session
# login to gcloud cli
gcloud auth login
# login for gcloud api
gcloud auth application-default login
Définir des variables d'environnement de shell
# set custom var for slug (eg, "foo") and region preference
export SLUG="foo"
export REGION="us-central1"
export ZONE="us-central1-a"
echo ${SLUG}
echo ${REGION}
echo ${ZONE}
# 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 MCP_NAME="mcp-sprockets"
echo ${AGW_NAME}
echo ${AGW_URI}
echo ${MCP_NAME}
# create resource vars for gemini enterprise (automatic)
export GE_LOCATION="global"
export GE_APP_ORG_NAME="${SLUG}, Inc."
export GE_APP_DISPLAY_NAME="${SLUG} ${GE_LOCATION} app"
export GE_APP_NAME="app-${SLUG}-${GE_LOCATION}"
export GE_APP_INIT="${GE_APP_NAME}_$(date +%s)"
echo ${GE_LOCATION}
echo ${GE_APP_ORG_NAME}
echo ${GE_APP_DISPLAY_NAME}
echo ${GE_APP_NAME}
echo ${GE_APP_INIT}
Définir des domaines de confiance pour l'identité de l'agent
L'instruction if-then-else vérifie si le projet appartient à une organisation afin de définir le domaine de confiance approprié pour les identités d'agent 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}"
Définir le projet de facturation et de quota
# 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}
Créer un répertoire local pour les fichiers de configuration
# create config folder
mkdir -p cfg
Mettre à jour gcloud cli (recommandé)
Si vous exécutez une installation autogérée du Google Cloud SDK (c'est-à-dire en dehors de Cloud Shell), mettez à jour les composants vers la dernière version.
# update gcloud cli
gcloud components update
Activer les services d'API
# enable google cloud apis
gcloud services enable \
agentregistry.googleapis.com \
aiplatform.googleapis.com \
cloudapiregistry.googleapis.com \
cloudresourcemanager.googleapis.com \
compute.googleapis.com \
discoveryengine.googleapis.com \
dns.googleapis.com \
iam.googleapis.com \
iap.googleapis.com \
logging.googleapis.com \
monitoring.googleapis.com \
networkconnectivity.googleapis.com \
networksecurity.googleapis.com \
networkservices.googleapis.com \
orgpolicy.googleapis.com \
serviceextensions.googleapis.com \
serviceusage.googleapis.com
Règles d'administration
Les contraintes de règles d'administration gérées par défaut de Google Cloud et les règles du bac à sable peuvent limiter les fonctionnalités utilisées dans cet atelier de programmation :
compute.vmExternalIpAccess: limite les adresses IPv4 externes sur les VM Compute Engine dans les organisations sandbox verrouillées.discoveryengine.managed.disableCustomMcpServerConnector: limite la création de connecteurs de données qui utilisent un serveur MCP personnalisé (custom_mcp) comme source de données (appliqué par défaut).discoveryengine.managed.allowedEgressFqdns: limite les domaines de sortie sortants (noms de domaine completsinstance_uri) pour les connecteurs de données lorsque VPC Service Controls (VPC-SC) est actif ou que le projet est listé dansenforcedProjects.discoveryengine.managed.allowedDataSources: limite les types de connecteurs de données autorisés (dataSource) lorsque VPC-SC est actif ou que le projet est listé dansenforcedProjects.
Remplacez les restrictions héritées des règles d'administration au niveau du projet.
Désactiver une contrainte MCP personnalisée
# disable data connector constraint (allow custom mcp servers)
gcloud org-policies set-policy "/dev/stdin" <<EOF
name: projects/${PROJ_ID}/policies/discoveryengine.managed.disableCustomMcpServerConnector
spec:
rules:
- enforce: false
EOF
Désactiver les contraintes de connecteur de données conditionnelles
# disable egress fqdn constraint on project
gcloud org-policies set-policy "/dev/stdin" <<EOF
name: projects/${PROJ_ID}/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_ID}/policies/discoveryengine.managed.allowedDataSources
spec:
rules:
- enforce: false
EOF
Désactiver la contrainte de règle d'accès
# 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
Autoriser les adresses IP externes
# allow external ip address for vms on project
gcloud org-policies set-policy "/dev/stdin" <<EOF
name: projects/${PROJ_ID}/policies/compute.vmExternalIpAccess
spec:
rules:
- allowAll: true
EOF
Vérifier les règles d'administration
Vérifiez que compute.vmExternalIpAccess est défini sur allowAll: True et que les autres règles sont définies sur enforce: False :
# verify effective org policy constraints on project
for policy in \
discoveryengine.managed.disableCustomMcpServerConnector \
discoveryengine.managed.allowedEgressFqdns \
discoveryengine.managed.allowedDataSources \
iam.managed.disableAccessPolicyBinding \
compute.vmExternalIpAccess; do
gcloud org-policies describe ${policy} \
--project=${PROJ_ID} \
--effective \
--format="flattened[no-pad](name.basename(),spec.rules[0])"
done
Vérifier les liaisons de l'agent de service (par précaution)
Dans un nouveau projet, Google Cloud provisionne automatiquement l'agent de service Agent Gateway et lui attribue roles/agentgateway.serviceAgent lorsque networkservices.googleapis.com est activé pour la première fois. Si vous réutilisez un projet existant dans lequel un nettoyage antérieur a pu supprimer les liaisons d'agent de service par défaut, exécutez les commandes suivantes pour vous assurer que l'identité et la liaison de rôle sont intactes :
# 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"
La partie concernant la configuration est terminée. Passons à la section Réseau.
4. Réseau
Dans cette section, vous allez réserver les adresses IPv4 externes statiques, créer le réseau VPC de sortie interne et le réseau VPC externe isolé, provisionner le rattachement de réseau PSC, configurer Cloud NAT et créer des règles de pare-feu.
Réserver des adresses IP externes statiques
Réservez deux adresses IPv4 externes régionales statiques pour Cloud NAT et la VM du serveur MCP externe :
# reserve static external ipv4 address for cloud nat
gcloud compute addresses create ip-${SLUG}-nat \
--region=${REGION}
# reserve static external ipv4 address for the mcp server
gcloud compute addresses create ip-${SLUG}-mcp \
--region=${REGION}
Vérifier les adresses IP externes statiques
Gemini Enterprise exige que les points de terminaison MCP distants utilisent HTTPS avec un certificat TLS publiquement approuvé. Au lieu d'enregistrer un domaine personnalisé pour cet atelier, vous allez utiliser sslip.io, un service DNS générique sans frais qui résout directement tout nom d'hôte contenant une adresse IP (comme mcp.[IP].sslip.io) en cette adresse IP. Étant donné que les autorités de certification telles que Let's Encrypt n'émettent pas de certificats pour les adresses IP brutes, ce nom d'hôte sslip.io fournit au proxy inverse Caddy un nom de domaine valide pour provisionner automatiquement un certificat TLS de confiance pour le serveur MCP.
Exportez les adresses IPv4 et créez le nom de domaine et l'URL sslip.io pour le serveur MCP externe :
# export static ip addresses and set vars for domain
export NAT_EXT_IP=$(gcloud compute addresses describe ip-${SLUG}-nat \
--region=${REGION} \
--format="value(address)")
export MCP_EXT_IP=$(gcloud compute addresses describe ip-${SLUG}-mcp \
--region=${REGION} \
--format="value(address)")
export MCP_DOMAIN="mcp.${MCP_EXT_IP}.sslip.io"
export MCP_URL="https://${MCP_DOMAIN}/mcp"
echo "cloud nat external ip : ${NAT_EXT_IP}"
echo "mcp server external ip : ${MCP_EXT_IP}"
echo "mcp url : ${MCP_URL}"
Exemple de résultat :
cloud nat external ip : 203.0.113.10
mcp server external ip : 203.0.113.20
mcp url : https://mcp.203.0.113.20.sslip.io/mcp
Créer un réseau interne
Lorsque le modèle de connectivité Agent Gateway est configuré pour utiliser un egressNetworkConfig avec un networkAttachment, le sous-réseau hébergeant l'association de réseau PSC doit être au moins un bloc CIDR /28 et avoir l'accès privé à Google (--enable-private-ip-google-access) activé.
Créez un réseau VPC mondial pour la sortie de l'Agent Gateway interne :
# create vpc network
gcloud compute networks create vnet-${SLUG}-internal --subnet-mode=custom
# create subnet for agent gateway psc na
gcloud compute networks subnets create subnet-${REGION}-agw \
--network=vnet-${SLUG}-internal \
--range=10.10.10.0/28 \
--region=${REGION} \
--enable-private-ip-google-access
Créer des règles de pare-feu internes
Créez une stratégie de pare-feu pour autoriser tout le trafic sortant avec la journalisation activée. Il servira à surveiller le trafic sortant d'Agent Gateway vers le réseau VPC interne. Cloud NGFW est compatible avec les niveaux Essentials et Standard pour la sécurité du réseau et la surveillance du trafic.
# create fw policy
gcloud compute network-firewall-policies create fw-policy-${SLUG}-internal --global
# create fw policy rule
gcloud compute network-firewall-policies rules create 1001 \
--description="allow all out and log" \
--firewall-policy=fw-policy-${SLUG}-internal \
--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}-internal \
--firewall-policy=fw-policy-${SLUG}-internal \
--network=vnet-${SLUG}-internal \
--global-firewall-policy
Créer un rattachement de réseau PSC
Créez un rattachement de réseau Private Service Connect (PSC) configuré pour accepter automatiquement les connexions depuis Agent Gateway. Le rattachement de réseau établit le côté consommateur du réseau VPC de la connexion pour l'associer de manière sécurisée au côté producteur de l'Agent Gateway pour le trafic de sortie. Pour en savoir plus sur les exigences concernant les sous-réseaux et les spécifications des plages d'adresses IP, consultez Configurer la connectivité VPC.
# create psc network attachment
gcloud compute network-attachments create psc-na-${REGION}-agw \
--region=${REGION} \
--subnets=subnet-${REGION}-agw \
--connection-preference=ACCEPT_AUTOMATIC
Vérifier le rattachement de réseau PSC
# show psc network attachment details
gcloud compute network-attachments describe psc-na-${REGION}-agw --region=${REGION}
Récupérez l'URI de ressource du rattachement de réseau PSC et stockez-le dans la variable d'environnement PSC_NA_URI. Cet URI sera référencé dans la configuration Agent Gateway (networkConfig.egress.networkAttachment) pour provisionner l'interface PSC pour la sortie réseau dans le réseau 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}
Créer Cloud NAT
Cloud NAT est utilisé pour traduire l'adresse IP source du trafic sortant Agent Gateway vers l'adresse IP publique réservée pour le routage sur l'Internet public.
Seules les sources du sous-réseau de rattachement de réseau de sortie Agent Gateway sont définies comme éligibles à l'utilisation de Cloud NAT.
# create router for nat
gcloud compute routers create cr-nat-${SLUG}-${REGION} \
--network=vnet-${SLUG}-internal \
--asn=16550 \
--region=${REGION}
# create nat
gcloud compute routers nats create nat-${SLUG}-${REGION} \
--router=cr-nat-${SLUG}-${REGION} \
--region=${REGION} \
--nat-custom-subnet-ip-ranges="subnet-${REGION}-agw" \
--nat-external-ip-pool="ip-${SLUG}-nat" \
--enable-logging \
--log-filter=ALL
Vérifier Cloud NAT
Vérifiez l'état de Cloud NAT et que la source natIP attendue est configurée :
# verify cloud nat configuration
gcloud compute routers nats describe nat-${SLUG}-${REGION} \
--router=cr-nat-${SLUG}-${REGION} \
--region=${REGION} \
--format="yaml(name,natIps,subnetworks.name)"
Exemple de résultat :
name: nat-foo-us-central1
natIps:
- https://www.googleapis.com/compute/v1/projects/[PROJ_ID]/regions/us-central1/addresses/ip-foo-nat
Créer un réseau externe
Créez un réseau VPC distinct et isolé pour héberger la VM du serveur MCP externe.
# create vpc network
gcloud compute networks create vnet-${SLUG}-external --subnet-mode=custom
# create subnet for mcp server
gcloud compute networks subnets create subnet-${REGION}-mcp \
--network=vnet-${SLUG}-external \
--range=240.240.240.0/24 \
--region=${REGION} \
--enable-private-ip-google-access
Créer des règles de pare-feu externes
Créez deux règles de pare-feu d'entrée sur le réseau VPC externe :
2001: autorise le port TCP entrant80afin que Let's Encrypt puisse relever le défi de validation de domaine ACME HTTP-01 pour${MCP_DOMAIN}.2002: autorise initialement le port TCP entrant443de0.0.0.0/0pour vérifier la compatibilité TLS et l'application OAuth 2.0tokeninfoà partir du shell local avant de le verrouiller strictement sur${NAT_EXT_IP}/32.
# create fw policy
gcloud compute network-firewall-policies create fw-policy-${SLUG}-external --global
# create fw policy rules
gcloud compute network-firewall-policies rules create 2001 \
--description="allow in any http" \
--firewall-policy=fw-policy-${SLUG}-external \
--global-firewall-policy \
--action=allow \
--direction=INGRESS \
--layer4-configs=tcp:80 \
--src-ip-ranges=0.0.0.0/0 \
--dest-ip-ranges=240.240.240.0/24 \
--enable-logging
gcloud compute network-firewall-policies rules create 2002 \
--description="allow in any https" \
--firewall-policy=fw-policy-${SLUG}-external \
--global-firewall-policy \
--action=allow \
--direction=INGRESS \
--layer4-configs=tcp:443 \
--src-ip-ranges=0.0.0.0/0 \
--dest-ip-ranges=240.240.240.0/24 \
--enable-logging
# bind fw policy to network
gcloud compute network-firewall-policies associations create \
--name=fw-policy-bind-${SLUG}-external \
--firewall-policy=fw-policy-${SLUG}-external \
--network=vnet-${SLUG}-external \
--global-firewall-policy
La partie sur le réseau est terminée. Passons à la section Agent Gateway.
5. Agent Gateway
Dans cette section, vous allez déployer le modèle de connectivité de l'agent avec vpcEgress: ALL_TRAFFIC, déployer l'Agent Gateway régionale, déléguer l'autorisation à Identity-Aware Proxy (IAP) et définir des règles de stratégie d'accès unifiées IAM pour régir les requêtes réseau sortantes.
Créer un modèle de connectivité
La spécification du modèle de connectivité définit les éléments suivants :
egressNetworkConfig.networkAttachment: pointe vers le rattachement de réseau PSC, qui connecte Agent Gateway à votre réseau VPC.egressNetworkConfig.vpcEgress: définissez la valeur surALL_TRAFFICafin que toutes les connexions d'agent sortantes (y compris les points de terminaison MCP Internet publics) soient acheminées vers le réseau VPC et quittent le réseau à l'aide de la traduction d'adresse IP source Cloud NAT.
Créez et importez le fichier de configuration du modèle de connectivité :
# create connectivity template config file (vpcEgress: ALL_TRAFFIC)
cat > cfg/act-${AGW_NAME}.yaml << EOF
accessPath: AGENT_TO_ANYWHERE
name: projects/${PROJ_NO}/locations/${REGION}/agentConnectivityTemplates/act-${AGW_NAME}
deploymentModel: CENTRALIZED
egressNetworkConfig:
networkAttachment: ${PSC_NA_URI}
vpcEgress: ALL_TRAFFIC
EOF
# import connectivity template file (create template)
gcloud network-services agent-connectivity-templates import act-${AGW_NAME} \
--source="cfg/act-${AGW_NAME}.yaml" \
--location=${REGION}
Créer une passerelle d'agent
La spécification Agent Gateway définit les éléments suivants :
agentConnectivityTemplate: pointe vers le modèle de connectivité afin que la passerelle puisse utiliser le rattachement de réseau PSC pour la connectivité VPC.registries: associe la passerelle au registre d'agents régional pour résoudre les schémas d'outils et les points de terminaison MCP catalogués.
Créez et importez le fichier de configuration Agent Gateway :
# create agent gateway config file
cat > cfg/${AGW_NAME}.yaml << EOF
name: ${AGW_NAME}
protocols:
- MCP
googleManaged:
governedAccessPath: AGENT_TO_ANYWHERE
agentConnectivityTemplate: projects/${PROJ_NO}/locations/${REGION}/agentConnectivityTemplates/act-${AGW_NAME}
registries:
- "//agentregistry.googleapis.com/projects/${PROJ_ID}/locations/${REGION}"
EOF
# import agent gateway config file (create gateway)
gcloud network-services agent-gateways import ${AGW_NAME} \
--source="cfg/${AGW_NAME}.yaml" \
--location=${REGION}
Vérifier le déploiement d'Agent Gateway
Vérifiez la configuration du modèle de connectivité et du registre d'agents :
# verify agent gateway deployment details
gcloud network-services agent-gateways describe ${AGW_NAME} \
--location=${REGION} \
--format="yaml(name,agentConnectivityTemplate,registries)"
Exemple de résultat :
agentConnectivityTemplate: projects/[PROJ_NO]/locations/us-central1/agentConnectivityTemplates/act-foo-us-central1
name: projects/[PROJ_ID]/locations/us-central1/agentGateways/agw-foo-us-central1-ata
registries:
- //agentregistry.googleapis.com/projects/[PROJ_ID]/locations/us-central1
Inspectez le rattachement de réseau PSC pour confirmer la connexion à la passerelle :
# show psc network attachment details
gcloud compute network-attachments describe psc-na-${REGION}-agw \
--region=${REGION} \
--format="yaml(connectionEndpoints)"
Exemple de résultat :
connectionEndpoints:
- ipAddress: 10.10.10.2
projectIdOrNum: '[TENANT_PROJ_NO]'
status: ACCEPTED
subnetwork: https://www.googleapis.com/compute/v1/projects/[PROJ_ID]/regions/us-central1/subnetworks/subnet-us-central1-agw
Déléguer l'autorisation
Agent Gateway sécurise et régit le trafic sortant des outils à l'aide de Règles d'autorisation (networksecurity.authzPolicies) intégrées aux Règles d'accès unifiées (UAP) Identity-Aware Proxy (IAP).
Bien qu'Agent Gateway soit compatible avec les règles ALLOW et DENY de base, les environnements d'entreprise nécessitent une gouvernance centralisée axée sur l'identité. Avec les stratégies d'accès unifiées IAM (ou stratégies d'accès), vous gérez les règles d'accès sortant à l'aide des stratégies d'accès IAM v3 standards.
Fig. 3. Architecture d'autorisation
Le flux d'autorisation connecte trois composants :
- Règle d'autorisation de la passerelle (
authzPolicy) :- Ressource régionale ciblant Agent Gateway.
- Configuré avec
policyProfile: REQUEST_AUTHZetaction: CUSTOMpour acheminer toutes les vérifications d'autorisation sortantes vers l'extension d'autorisation IAP.
- Extension de service IAP (
authzExtension) :- Ressource régionale qui délègue l'autorisation des requêtes à Identity-Aware Proxy (
iap.googleapis.com). - Évalue les règles en mode
ENFORCEà l'aide de la versionV2des règles.
- Ressource régionale qui délègue l'autorisation des requêtes à Identity-Aware Proxy (
- Règlement et liaison d'accès unifiés IAM (
accessPolicyetpolicyBinding) :- Ressources IAM v3 globales contenant des règles d'accès précises.
- Authentifie l'identité de principal SPIFFE de l'agent appelant, vérifie l'autorisation universelle
iap.googleapis.com/resources.egressViaIAPet évalue les conditions CEL (Common Expression Language) par rapport aux attributs de destination.
Déployer l'extension d'autorisation
# 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 authz extension config file (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}
Vérifier l'extension d'autorisation
Vérifiez que l'extension d'autorisation est active :
# list authz extensions
gcloud service-extensions authz-extensions list \
--location=${REGION} \
--format="table(
name.basename():label=NAME,
createTime.date(tz=LOCAL):label=CREATED,
service:label=SERVICE,
metadata:label=METADATA,
timeout:label=TIMEOUT
)"
Déployer une règle d'autorisation
Créez une configuration de règle d'autorisation network-security qui cible Agent Gateway et délègue la validation des requêtes à l'extension d'autorisation pour 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}
Vérifier la règle d'autorisation
Vérifiez que la règle d'autorisation est active :
# list authz policies
gcloud network-security authz-policies list \
--location=${REGION} \
--format="table(
name.basename():label=NAME,
action:label=ACTION,
policyProfile:label=POLICY_PROFILE,
customProvider.authzExtension.resources[0].basename():label=CUSTOM_PROVIDER_RESOURCE
)"
Créer des stratégies d'accès IAM
Agent Gateway délègue désormais les vérifications d'autorisation à IAP et résout les métadonnées de destination à partir d'Agent Registry. Ensuite, définissez une règle de stratégie d'accès unifiée IAM pour régir l'exécution des outils sortants.
IAP évalue les expressions d'attribut CEL par rapport aux attributs de destination suivants du registre d'agents :
- État enregistré (
destination.is_registered) :- Valeur booléenne (
true/false) indiquant si la destination est cataloguée dans le registre d'agents.
- Valeur booléenne (
- Nom du serveur MCP (
destination.agent_registry.mcp_server.name) :- Nom de ressource du serveur MCP canonique enregistré dans Agent Registry.
- Méthode MCP (
destination.agent_registry.mcp_server.method) :- Méthode MCP appelée (par exemple,
tools/call,tools/list,initialize).
- Méthode MCP appelée (par exemple,
- Nom de l'outil (
destination.agent_registry.mcp_server.tool.name) :- Nom de l'outil spécifique appelé (par exemple,
get_sprocket_by_idouget_sprockets), permettant une autorisation précise au niveau de l'outil sur les serveurs MCP enregistrés.
- Nom de l'outil spécifique appelé (par exemple,
Définir une règle de stratégie d'accès IAM
Le fichier manifeste de la règle de stratégie IAM spécifie :
- Comptes principaux : identité principale SPIFFE représentant l'agent assistant principal de Gemini Enterprise.
- Autorisations : autorisation universelle
iap.googleapis.com/resources.egressViaIAPrequise pour tout le trafic sortant régi par IAP. - Conditions : expression CEL (
destination.is_registered == true) garantissant que l'agent ne peut invoquer que les points de terminaison catalogués dans l'Agent Registry.
Créez le fichier manifeste des règles :
# create access policy rule file
cat > cfg/uap-policy-${SLUG}-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
Déployer une stratégie d'accès IAM
Créez la stratégie d'accès IAM globale à l'aide des règles définies dans le fichier manifeste :
# create iam access policy
gcloud iam access-policies create uap-policy-${SLUG} \
--details-rules=cfg/uap-policy-${SLUG}-rules.json \
--project=${PROJ_ID} \
--location=global
Vérifier la stratégie d'accès IAM
Vérifiez que la stratégie d'accès IAM a bien été créée et examinez les détails de la règle :
# show iam access policy details
gcloud iam access-policies describe uap-policy-${SLUG} \
--project=${PROJ_ID} \
--location=global
Exemple de résultat :
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/app-foo-global_[EPOCH]/assistants/default_assistant/agents/default/core_assistant
name: projects/[PROJ_ID]/locations/global/accessPolicies/uap-policy-foo
Associer une stratégie d'accès IAM à un projet
Pour activer l'application sur toutes les passerelles d'agent de votre projet, créez une liaison de stratégie qui associe la stratégie d'accès IAM à la ressource du projet :
# bind iam access policy to project resource
gcloud iam policy-bindings create uap-bind-${SLUG} \
--policy="projects/${PROJ_ID}/locations/global/accessPolicies/uap-policy-${SLUG}" \
--target-resource="//cloudresourcemanager.googleapis.com/projects/${PROJ_ID}" \
--project=${PROJ_ID} \
--location=global
Vérifier la liaison de la stratégie d'accès IAM
Vérifiez que les points de liaison actifs de la règle renvoient à la règle et à la cible appropriées :
# show policy binding details
gcloud iam policy-bindings describe uap-bind-${SLUG} \
--project=${PROJ_ID} \
--location=global
La partie concernant la passerelle d'agent est terminée. Passons à la section Serveur MCP.
6. Serveur MCP
Dans cette section, vous allez déployer un serveur de ressources OAuth 2.0 FastMCP externe (mcp-sprockets) exposant les outils get_sprockets et get_sprocket_by_id, et vérifier qu'il valide de manière cryptographique les jetons porteurs Google OAuth 2.0 par rapport à https://oauth2.googleapis.com/tokeninfo. Vous allez ensuite verrouiller la règle de pare-feu externe strictement sur l'adresse IP statique Cloud NAT.
Déployer un serveur MCP externe
Un script de démarrage installe Caddy et FastMCP, lance le serveur mcp-sprockets sur 127.0.0.1:8080 et configure Caddy pour qu'il diffuse HTTPS sur ${MCP_DOMAIN}.
Chaque fois que Gemini Enterprise appelle un outil MCP (par exemple, get_sprockets et get_sprocket_by_id), le serveur :
- Lecture de l'adresse IP source de l'appelant à partir de l'en-tête
X-Forwarded-For(egress_source_ip). - Extrayez l'en-tête
Authorization: Bearer [access_token]et validez le jeton par rapport au point de terminaison de validation Google OAuth 2.0 (https://oauth2.googleapis.com/tokeninfo?access_token=[token]). - Renvoie
"authenticated_user"([user_email]) à côté de"egress_source_ip", ce qui prouve que le serveur MCP externe a validé à la fois l'adresse IP statique Cloud NAT et l'identité Google OAuth 2.0 de l'utilisateur final.
# create startup script for the sprockets mcp server vm
cat > cfg/server-startup.sh << 'EOF'
#!/bin/bash
set -euo pipefail
MCP_DOMAIN=$(curl -s -H "Metadata-Flavor: Google" \
http://metadata.google.internal/computeMetadata/v1/instance/attributes/mcp-domain)
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
apt-get install -y caddy python3-venv curl
mkdir -p /opt/mcp-sprockets
python3 -m venv /opt/mcp-sprockets/venv
/opt/mcp-sprockets/venv/bin/pip install --upgrade pip
/opt/mcp-sprockets/venv/bin/pip install "fastmcp>=2.14.0" "uvicorn>=0.34.0"
cat <<'PYEOF' > /opt/mcp-sprockets/main.py
import json
import urllib.parse
import urllib.request
from typing import Any, Dict
from fastmcp import FastMCP
from fastmcp.server.dependencies import get_http_headers
from mcp.types import ToolAnnotations
mcp = FastMCP("mcp-sprockets")
SPROCKETS = {
"SPK-101": {"id": "SPK-101", "model": "ANSI-40-12T", "teeth": 12, "pitch_in": 0.5, "material": "1045 Carbon Steel", "stock": 140, "unit_price": 18.50},
"SPK-102": {"id": "SPK-102", "model": "ANSI-40-24T", "teeth": 24, "pitch_in": 0.5, "material": "1045 Carbon Steel", "stock": 85, "unit_price": 29.00},
"SPK-103": {"id": "SPK-103", "model": "ANSI-60-16T", "teeth": 16, "pitch_in": 0.75, "material": "304 Stainless Steel", "stock": 60, "unit_price": 42.00},
"SPK-104": {"id": "SPK-104", "model": "ANSI-60-32T", "teeth": 32, "pitch_in": 0.75, "material": "304 Stainless Steel", "stock": 35, "unit_price": 68.00},
"SPK-105": {"id": "SPK-105", "model": "ANSI-80-20T", "teeth": 20, "pitch_in": 1.0, "material": "4140 Alloy Steel", "stock": 50, "unit_price": 95.00}
}
def verify_google_oauth_token(headers: Dict[str, str]) -> str:
token = headers.get("authorization", "")[7:].strip() if headers.get("authorization", "").lower().startswith("bearer ") else ""
if not token:
return "unauthenticated (missing Bearer token)"
url = "https://oauth2.googleapis.com/tokeninfo?" + urllib.parse.urlencode({"access_token": token})
with urllib.request.urlopen(url, timeout=5) as resp:
info = json.loads(resp.read().decode("utf-8"))
return info.get("email", info.get("sub", "verified-oauth-user"))
@mcp.tool(
description="list all sprockets in the inventory catalog",
annotations=ToolAnnotations(
readOnlyHint=True,
destructiveHint=False,
idempotentHint=True,
openWorldHint=False
)
)
def get_sprockets() -> Dict[str, Any]:
headers = get_http_headers(include_all=True)
caller_ip = headers.get("x-forwarded-for", "unknown").split(",")[0].strip()
try:
user_email = verify_google_oauth_token(headers)
except Exception as exc:
return {"egress_source_ip": caller_ip, "authenticated_user": None, "error": f"OAuth token verification failed: {exc}"}
return {
"egress_source_ip": caller_ip,
"authenticated_user": user_email,
"sprockets": list(SPROCKETS.values())
}
@mcp.tool(
description="fetch details of a specific sprocket by its ID (eg, SPK-101)",
annotations=ToolAnnotations(
readOnlyHint=True,
destructiveHint=False,
idempotentHint=True,
openWorldHint=False
)
)
def get_sprocket_by_id(sprocket_id: str) -> Dict[str, Any]:
headers = get_http_headers(include_all=True)
caller_ip = headers.get("x-forwarded-for", "unknown").split(",")[0].strip()
try:
user_email = verify_google_oauth_token(headers)
except Exception as exc:
return {"egress_source_ip": caller_ip, "authenticated_user": None, "error": f"OAuth token verification failed: {exc}"}
sprocket = SPROCKETS.get(sprocket_id.upper())
if sprocket:
return {
"egress_source_ip": caller_ip,
"authenticated_user": user_email,
"sprocket": sprocket
}
return {
"egress_source_ip": caller_ip,
"authenticated_user": user_email,
"error": f"Sprocket '{sprocket_id}' not found."
}
app = mcp.http_app(stateless_http=True)
PYEOF
cat <<'SVCEOF' > /etc/systemd/system/mcp-sprockets.service
[Unit]
Description=Sprockets FastMCP Server
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/mcp-sprockets
ExecStart=/opt/mcp-sprockets/venv/bin/uvicorn main:app --host 127.0.0.1 --port 8080 --forwarded-allow-ips="*"
Restart=always
[Install]
WantedBy=multi-user.target
SVCEOF
systemctl daemon-reload
systemctl enable --now mcp-sprockets.service
systemctl restart mcp-sprockets.service
cat <<CADDYEOF > "/etc/caddy/Caddyfile"
${MCP_DOMAIN} {
reverse_proxy 127.0.0.1:8080
}
CADDYEOF
systemctl restart caddy
EOF
# create vm instance
gcloud compute instances create vm-${MCP_NAME} \
--zone=${ZONE} \
--machine-type=e2-micro \
--image-family=debian-12 \
--image-project=debian-cloud \
--shielded-secure-boot \
--network-interface="subnet=subnet-${REGION}-mcp,address=${MCP_EXT_IP}" \
--metadata="mcp-domain=${MCP_DOMAIN}" \
--metadata-from-file="startup-script=cfg/server-startup.sh"
Vérifier que le serveur MCP est prêt et valider OAuth 2.0 tokeninfo
Patientez quelques minutes pour que le script de démarrage installe FastMCP et Caddy, et provisionne le certificat TLS Let's Encrypt.
# poll until caddy serves valid tls and fastmcp responds to tools/list
for i in $(seq 1 30); do
RESP=$(curl -s -X POST "${MCP_URL}" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}' || true)
if echo "${RESP}" | grep -q "get_sprockets"; then
echo "mcp server and let's encrypt tls ready"
break
fi
echo "...waiting for mcp server and let's encrypt tls (attempt ${i}/30)..."
sleep 5
done
Validez la résolution DNS sslip.io, le certificat TLS Let's Encrypt fourni par Caddy et la réponse tools/list FastMCP :
# query mcp server for tools list
curl -v -X POST "${MCP_URL}" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}' \
2>&1 | grep -E "Connected to|subject:|issuer:|SSL certificate|HTTP/|event:|data:"
Exemple de résultat :
* Connected to mcp.203.0.113.20.sslip.io (203.0.113.20) port 443
* subject: CN=mcp.203.0.113.20.sslip.io
* issuer: C=US; O=Let's Encrypt; CN=E5
* SSL certificate verify ok.
> POST /mcp HTTP/2
< HTTP/2 200
event: message
data: {"jsonrpc":"2.0","id":1,"result":{"tools":[{"name":"get_sprockets","description":"list all sprockets in the inventory catalog","inputSchema":{"properties":{},"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true}},{"name":"get_sprocket_by_id","description":"fetch details of a specific sprocket by its ID (eg, SPK-101)","inputSchema":{"properties":{"sprocket_id":{"type":"string"}},"required":["sprocket_id"],"type":"object"},"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true}}]}}
Avant de verrouiller le pare-feu externe, exécutez un test tools/call en transmettant un jeton Google OAuth 2.0 Bearer (gcloud auth print-access-token) pour vérifier que mcp-sprockets valide le jeton par rapport à https://oauth2.googleapis.com/tokeninfo et renvoie votre adresse e-mail "authenticated_user" ainsi que l'adresse IP source de l'appelant :
# query mcp server (test tools/call with google oauth 2.0 bearer token)
curl -s -X POST "${MCP_URL}" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_sprocket_by_id",
"arguments": {"sprocket_id": "SPK-105"}
}
}' | sed -n 's/^data: //p' | jq '.result.structuredContent'
Exemple de résultat (indiquant votre adresse IP Cloud Shell directe avant le verrouillage du pare-feu et votre adresse e-mail Google OAuth validée) :
{
"egress_source_ip": "198.51.100.154",
"authenticated_user": "user@example.com",
"sprocket": {
"id": "SPK-105",
"model": "ANSI-80-20T",
"teeth": 20,
"pitch_in": 1.0,
"material": "4140 Alloy Steel",
"stock": 50,
"unit_price": 95.0
}
}
Verrouiller le pare-feu sur l'adresse IP statique Cloud NAT
Mettez à jour la stratégie de pare-feu du réseau VPC externe afin que le port TCP 443 n'accepte le trafic que provenant de l'adresse IP externe statique Cloud NAT (${NAT_EXT_IP}/32) :
# create fw policy rule allowing https only from cloud nat static ip
gcloud compute network-firewall-policies rules create 2003 \
--description="allow in any https from nat ip" \
--firewall-policy=fw-policy-${SLUG}-external \
--global-firewall-policy \
--action=allow \
--direction=INGRESS \
--layer4-configs=tcp:443 \
--src-ip-ranges="${NAT_EXT_IP}/32" \
--dest-ip-ranges=240.240.240.0/24 \
--enable-logging
# delete temporary open fw policy rules
gcloud compute network-firewall-policies rules delete 2001 \
--firewall-policy=fw-policy-${SLUG}-external \
--global-firewall-policy
gcloud compute network-firewall-policies rules delete 2002 \
--firewall-policy=fw-policy-${SLUG}-external \
--global-firewall-policy
Vérifiez que les règles de stratégie de pare-feu externe sont en place :
# list all rules in the global network firewall policy
gcloud compute network-firewall-policies describe fw-policy-${SLUG}-external \
--global \
--flatten="rules[]" \
--format="table(
rules.priority:label=RULE,
rules.action:label=ACTION,
rules.direction:label=DIRECTION,
firstof(
rules.match.srcIpRanges,
rules.match.srcAddressGroups,
rules.match.srcSecureTags.name
).map().sub('projects/[^/]+/(locations/global/|global/)', '').list():label=SRC,
firstof(
rules.targetForwardingRules,
rules.match.destIpRanges,
rules.targetType
).map().sub('projects/[^/]+/(locations/global/|global/)', '').list():label=DST
)"
Vérifiez que les connexions directes en dehors de l'adresse IP statique Cloud NAT sont désormais bloquées :
# query mcp server
curl -i --connect-timeout 5 "${MCP_URL}" \
|| echo "Expected: Direct access blocked (not originating from ${NAT_EXT_IP})"
Exemple de résultat :
curl: (28) Connection timed out after 5001 milliseconds
Expected: Direct access blocked (not originating from 203.0.113.10)
La partie concernant le serveur MCP est terminée. Passons maintenant à la section Agent Registry.
7. Agent Registry
Agent Registry est un inventaire centralisé de tous les agents, serveurs MCP et points de terminaison (API) de l'écosystème d'IA. Il s'agit également d'un catalogue qui peut être utilisé pour lister, rechercher et découvrir d'autres outils et services enregistrés à utiliser par les applications d'IA. Agent Gateway utilise le modèle de données du registre comme framework de gouvernance pour appliquer le contrôle des accès sortants. Les attributions de rôle IAM pour les agents appelants principaux sont vérifiées par rapport à la stratégie liée à la ressource de registre.
Dans cette section, vous allez enregistrer le serveur MCP et son schéma d'outil (toolspec.json) dans Agent Registry. Pour permettre à Gemini Enterprise d'interagir avec les API et services Google via Agent Gateway, vous devez également créer un service de point de terminaison de registre unique (oauth2-googleapis) qui spécifie les interfaces d'API Google utilisées par Gemini Enterprise pour échanger le code d'authentification contre des jetons.
Enregistrer un serveur MCP
Pour permettre à Gemini Enterprise de découvrir les outils disponibles sur le serveur MCP, fournissez un fichier de spécifications d'outil (cfg/toolspec.json) lorsque vous enregistrez le service dans Agent Registry.
Créer une spécification d'outil MCP
# create tool spec file for the sprockets mcp server
cat <<'EOF' > cfg/toolspec.json
{
"tools": [
{
"name": "get_sprockets",
"description": "List all sprockets in the inventory catalog.",
"inputSchema": {
"type": "object",
"properties": {}
},
"isReadOnly": true,
"isDestructive": false,
"isIdempotent": true,
"isOpenWorld": false
},
{
"name": "get_sprocket_by_id",
"description": "Fetch details of a specific sprocket by its ID (e.g., SPK-101).",
"inputSchema": {
"type": "object",
"properties": {
"sprocket_id": {
"type": "string",
"description": "The sprocket identifier (e.g., SPK-101, SPK-105)."
}
},
"required": [
"sprocket_id"
]
},
"isReadOnly": true,
"isDestructive": false,
"isIdempotent": true,
"isOpenWorld": false
}
]
}
EOF
Créer un service de serveur MCP
# create registry service (mcp server)
gcloud agent-registry services create ${MCP_NAME} \
--project=${PROJ_ID} \
--location=${REGION} \
--display-name="${MCP_DOMAIN}" \
--description="MANDATORY SPROCKETS INVENTORY & CATALOG AGENT: You MUST \
ALWAYS invoke this tool (get_sprockets or get_sprocket_by_id) for ANY question \
about sprockets, inventory catalog listings, sprocket IDs (SPK-101 through \
SPK-105), ANSI models (ANSI-40, ANSI-60, ANSI-80), tooth counts, pitch, \
material, stock levels, unit prices, authenticated_user, or egress_source_ip \
verification. NEVER guess or fabricate inventory data yourself and NEVER \
transfer sprocket queries to file_and_coding_agent or web search. Always \
delegate every sprocket or inventory lookup to this tool." \
--mcp-server-spec-type=tool-spec \
--mcp-server-spec-content=cfg/toolspec.json \
--interfaces=protocolBinding=JSONRPC,url="${MCP_URL}"
Vérifier le serveur MCP dans Agent Registry
Vérifiez que le service est répertorié en tant que serveur MCP enregistré dans la région, avec l'URL de son point de terminaison et les outils disponibles :
# list registry regional mcp servers
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
)"
Exemple de résultat :
REGISTRY_ID DISPLAY_NAME ENDPOINT_URL TOOLS
agentregistry-00000000-0000-0000-5c39-1f6e542bb2b8 mcp.203.0.113.20.sslip.io https://mcp.203.0.113.20.sslip.io/mcp get_sprockets,get_sprocket_by_id
Consultez la spécification de configuration du service pour voir qu'elle enregistre les définitions exactes des outils, les schémas d'entrée et les annotations de comportement pour chaque outil :
# describe mcp server tool specs
gcloud agent-registry services describe ${MCP_NAME} \
--location=${REGION} \
--project=${PROJ_ID} \
--format="yaml(mcpServerSpec.content.tools)"
Enregistrer le point de terminaison OAuth
Pour permettre au backend Gemini Enterprise DataConnector (qui fait office de client OAuth dans le flux d'autorisation) d'envoyer des requêtes POST au serveur d'autorisation Google OAuth 2.0 (https://oauth2.googleapis.com/token) via Agent Gateway, le point de terminaison du jeton doit être enregistré dans Agent Registry afin qu'IAP évalue destination.is_registered == true.
Créer un service de point de terminaison
# create registry service (endpoint)
gcloud agent-registry services create oauth2-googleapis \
--project=${PROJ_ID} \
--location=${REGION} \
--display-name="oauth2.googleapis.com" \
--description="google oauth2 endpoint" \
--endpoint-spec-type=no-spec \
--interfaces=protocolBinding=JSONRPC,url=https://oauth2.googleapis.com
Vérifier l'enregistrement du point de terminaison
# list registry regional endpoints
gcloud agent-registry endpoints list \
--project=${PROJ_ID} \
--location=${REGION} \
--flatten="interfaces[]" \
--format="table(
displayName,
name.basename():label=ENDPOINT_ID,
interfaces.url:label=URL
)"
Résultat attendu :
DISPLAY_NAME ENDPOINT_ID URL
oauth2.googleapis.com agentregistry-00000000-0000-0000-0012-3456789abcde https://oauth2.googleapis.com
Stratégie d'accès IAM
Étant donné que la stratégie d'accès IAM définit une stratégie d'autorisation pour tout service enregistré demandé par l'identité de l'agent core_assistant de l'application Gemini Enterprise, aucune liaison de stratégie IAM supplémentaire n'est requise pour l'échange de jetons OAuth.
- conditions:
iap.googleapis.com:
expression: destination.is_registered == true
description: allow ge assistant to any registered service
effect: ALLOW
La partie concernant le registre d'agents est terminée. Passons à la section Gemini Enterprise.
8. Gemini Enterprise
Dans cette section, vous allez configurer le fournisseur d'identité, la licence d'essai et les identifiants client Google Identity OAuth 2.0, créer une application Gemini Enterprise (${GE_APP_ID}), associer la sortie sortante à votre Agent Gateway (${AGW_URI}) et connecter le serveur MCP sprockets enregistré en tant que datastore MCP personnalisé OAuth 2.0.
Créer une application Gemini Enterprise
La méthode suivante utilise l'API discoveryengine.googleapis.com pour créer les ressources et la configuration de l'application Gemini Enterprise. Pour configurer l'application à l'aide de l'interface utilisateur de la console Google Cloud, consultez Créer une application pour obtenir des instructions.
# 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}"
},
"observabilityConfig": {
"observabilityEnabled": true,
"sensitiveLoggingEnabled": true
}
}
EOF
Vérifier la création de l'application
# 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}"
Affichez les détails du moteur pour voir la configuration créée :
# 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}"
Activer un fournisseur d'identité
Activez Google Identity comme fournisseur d'identité pour l'authentification des utilisateurs finaux sur votre application Gemini Enterprise.
La méthode suivante utilise l'API discoveryengine.googleapis.com pour configurer le fournisseur d'identité de l'application Gemini Enterprise. Pour configurer l'authentification à l'aide de l'interface utilisateur de la console Google Cloud, consultez Configurer le fournisseur d'identité pour obtenir des instructions.
# 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
Valider le fournisseur d'identité
# 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}"
La sortie "idpType": "GSUITE" correspond au fournisseur d'identité Google.
(Facultatif) Activer la licence d'essai Gemini Enterprise
Si vous utilisez un projet auquel des licences Gemini Enterprise sont attribuées, vous pouvez ignorer cette étape. Si vous utilisez un nouveau projet sans licence, continuez et suivez ces étapes.
Créez une ressource de configuration de licence pour accorder des licences Gemini Enterprise aux utilisateurs pendant 30 jours. Cela définira la nouvelle version d'essai comme licence par défaut. Ainsi, chaque utilisateur qui se connecte se verra automatiquement attribuer un siège :
# 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
Vérifier que la licence a été appliquée
# 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}"
Recherchez "subscriptionTerm": "SUBSCRIPTION_TERM_ONE_MONTH" et "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}"
Recherchez ../free_trial_gemini" et "enableLicenseAutoRegister": true.
Configurer le consentement et les identifiants OAuth 2.0
Pour permettre à Gemini Enterprise (le client OAuth 2.0) d'obtenir un jeton Bearer Google OAuth 2.0 délégué par l'utilisateur et de le présenter au serveur de ressources mcp-sprockets en votre nom, configurez l'écran de consentement Google Auth Platform OAuth et créez un ID client OAuth 2.0 pour application Web dans votre projet.
1. Configurer l'écran d'autorisation OAuth
Imprimez l'URL directe de la console Google Cloud pour la présentation de Google Auth Platform dans votre projet :
# print google auth platform consent screen url
echo "https://console.cloud.google.com/auth/overview?project=${PROJ_ID}"
- Ouvrez l'URL dans votre navigateur, puis cliquez sur Commencer (si ce n'est pas déjà configuré pour votre projet).
- Sous Informations sur l'application, définissez Nom de l'application sur
mcp-sprockets-oauth, sélectionnez votre adresse e-mail (${USER_IDENTITY}) comme Adresse e-mail d'assistance utilisateur, puis cliquez sur Suivant. - Sous Audience, sélectionnez Interne (recommandé si votre compte appartient à une organisation Google Workspace) ou Externe (si vous utilisez un compte personnel). Si vous sélectionnez Externe, ajoutez
${USER_IDENTITY}sous **Testeurs de l'audience**, puis cliquez sur Suivant. - Saisissez votre adresse e-mail sous Coordonnées, acceptez le règlement, puis cliquez sur Créer.
2. Créer l'ID client OAuth 2.0 pour l'application Web
Imprimez l'URL directe de la console Google Cloud pour la page Clients :
# print google auth platform clients url
echo "https://console.cloud.google.com/auth/clients?project=${PROJ_ID}"
- Ouvrez l'URL et cliquez sur + Créer un client.
- Sélectionnez Application Web comme Type d'application et définissez Nom sur
ge-mcp-sprockets-client. - Cochez la case Ce client sera utilisé par un agent optimisé par l'IA pour désigner le client OAuth pour les workflows d'agent IA agissant pour le compte des utilisateurs.
- Sous URI de redirection autorisés, cliquez sur + Ajouter un URI et ajoutez l'URI de rappel OAuth de Gemini Enterprise :
https://vertexaisearch.cloud.google.com/oauth-redirect
- Cliquez sur Create (Créer), copiez l'ID client et le code secret du client générés, puis exportez-les dans votre session shell :
Définissez l'ID client et le code secret client OAuth 2.0 générés à l'étape précédente :
# set oauth 2.0 client id (paste in id)
export OAUTH_CLIENT_ID="SET_YOUR_OAUTH_CLIENT_ID_HERE"
# set oauth 2.0 client secret (paste in secret)
export OAUTH_CLIENT_SECRET="SET_YOUR_OAUTH_CLIENT_SECRET_HERE"
Vérifiez que l'ID client est défini :
# print oauth 2.0 client id
echo "oauth client id: ${OAUTH_CLIENT_ID}"
Associer à Agent Gateway
Le routage du trafic sortant de Gemini Enterprise via Agent Gateway établit une limite d'application centralisée et de routage d'adresse IP statique pour tous les appels d'outils d'agents d'IA :
- Application centralisée des règles : Agent Gateway sert de proxy intégré qui évalue les demandes d'outils sortantes par rapport aux règles d'autorisation avant que le trafic ne quitte l'environnement de l'agent.
- Sortie VPC et Cloud NAT déterministe : associer Gemini Enterprise à une Agent Gateway configurée avec
vpcEgress: ALL_TRAFFICpermet de s'assurer que les appels d'outils sont acheminés via le rattachement de réseau PSC et sortent à l'aide de votre adresse IP statique Cloud NAT réservée. - Auditabilité unifiée : fournit une journalisation centralisée des requêtes et des pistes d'audit sur tous les serveurs MCP connectés.
Corrigez le moteur agentGatewaySetting pour l'activer :
# 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": "${AGW_URI}"
}
}
}
EOF
Vérifier la liaison Agent Gateway
Récupérez la configuration de l'application pour confirmer la liaison 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 print-access-token)" \
-H "X-Goog-User-Project: ${PROJ_ID}" \
| jq '{name: .name, displayName: .displayName, agentGatewaySetting: .agentGatewaySetting}'
Exemple de résultat :
{
"name": "projects/[PROJ_NO]/locations/global/collections/default_collection/engines/app-foo-global_[EPOCH]",
"displayName": "foo global app",
"agentGatewaySetting": {
"defaultEgressAgentGateway": {
"name": "projects/[PROJ_ID]/locations/us-central1/agentGateways/agw-foo-us-central1-ata"
}
}
}
Créer un datastore de serveur MCP personnalisé
Dans cette section, vous allez connecter le serveur mcp-sprockets à Gemini Enterprise en créant un datastore MCP OAuth 2.0 personnalisé configuré avec Google Identity (https://accounts.google.com/o/oauth2/v2/auth et https://oauth2.googleapis.com/token).
Avec l'API Discovery Engine, le processus se déroule en deux étapes :
- Create (
:setUpDataConnector) : crée une ressourceCollectiondédiée (${MCP_NAME}-collection-%timestamp), associe leDataConnector(custom_mcp) avecauth_type: "OAUTH"et provisionne sonDataStorede sauvegarde (..._mcp_data). - Activer (
PATCH .../dataConnector?updateMask=actionConfig) : active le runtime de l'action du connecteur (actionState: "ACTIVE") à l'aide de la spécification de l'outil Agent Registry, des paramètres Google Identity OAuth 2.0 et lie leDataStore(dataStoreIds) à votreEngineGemini 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_DOMAIN}" \
--format="value(name)")
echo "mcp registry name: ${MCP_REGISTRY_URI}"
echo "mcp url: ${MCP_URL}"
Créer un connecteur de données
# create custom mcp data connector with google identity oauth 2.0 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}-collection-$(date +%s)",
"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": "OAUTH",
"instance_uri": "${MCP_URL}",
"auth_uri": "https://accounts.google.com/o/oauth2/v2/auth",
"auth_uri_params": "&access_type=offline&prompt=consent",
"token_uri": "https://oauth2.googleapis.com/token",
"client_id": "${OAUTH_CLIENT_ID}",
"client_secret": "${OAUTH_CLIENT_SECRET}",
"scopes": "openid email profile",
"client_secret_basic_override": true,
"mcp_server_source": "REGISTRY_MCP",
"registry_mcp_server_name": "${MCP_REGISTRY_URI}",
"mcp_agent_instructions": "MANDATORY SPROCKETS INVENTORY & CATALOG AGENT: Always invoke get_sprockets or get_sprocket_by_id for any question about sprockets, inventory catalog listings, sprocket IDs (SPK-101 through SPK-105), ANSI models (ANSI-40, ANSI-60, ANSI-80), tooth counts, pitch, material, stock levels, unit prices, authenticated_user, or egress_source_ip verification.",
"use_agent_gateway_egress": true,
"agent_gateway_engine": "projects/${PROJ_ID}/locations/global/collections/default_collection/engines/${GE_APP_ID}"
}
}
}
}
EOF
Vérifier la création du connecteur de données
# 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}"
Vérifiez que le champ "registry_mcp_server_name" est renseigné avec l'UUID Agent Registry du serveur MCP et que "auth_type" est défini sur OAUTH :
# 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, auth_type: .actionConfig.actionParams.auth_type, registry_mcp_server_name: .actionConfig.actionParams.registry_mcp_server_name}'
Affichez l'entrée du registre du serveur MCP dans l'interface utilisateur de la console 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}"
Activer le connecteur de données
# activate and bind data connector with google identity oauth 2.0
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": "OAUTH",
"instance_uri": "${MCP_URL}",
"auth_uri": "https://accounts.google.com/o/oauth2/v2/auth",
"auth_uri_params": "&access_type=offline&prompt=consent",
"token_uri": "https://oauth2.googleapis.com/token",
"client_id": "${OAUTH_CLIENT_ID}",
"client_secret": "${OAUTH_CLIENT_SECRET}",
"scopes": "openid email profile",
"client_secret_basic_override": true,
"mcp_server_source": "REGISTRY_MCP",
"registry_mcp_server_name": "${MCP_REGISTRY_URI}",
"mcp_agent_instructions": "MANDATORY SPROCKETS INVENTORY & CATALOG AGENT: Always invoke get_sprockets or get_sprocket_by_id for any question about sprockets, inventory catalog listings, sprocket IDs (SPK-101 through SPK-105), ANSI models (ANSI-40, ANSI-60, ANSI-80), tooth counts, pitch, material, stock levels, unit prices, authenticated_user, or egress_source_ip verification.",
"use_agent_gateway_egress": true,
"agent_gateway_engine": "projects/${PROJ_ID}/locations/global/collections/default_collection/engines/${GE_APP_ID}"
}
}
}
EOF
Vérifier les liens vers le serveur MCP personnalisé
# 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}'
Vérifiez si le datastore "dataStoreIds": ["mcp-sprockets-collection-[EPOCH]_mcp_data"] est associé.
# 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, auth_type: .actionConfig.actionParams.auth_type}'
Recherchez "state": "ACTIVE" et "auth_type": "OAUTH".
Actions de l'outil
Lorsque vous inspectez le datastore mcp-sprockets-collection dans le tableau de bord Gemini Enterprise, vous remarquerez que l'onglet Actions n'est pas utilisé et que le bouton ↻ Recharger les actions personnalisées est désactivé. Ce comportement est normal.
Affichez la page d'informations sur le datastore dans l'interface utilisateur de la console 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}"
Selon la façon dont vous connectez un serveur MCP personnalisé à Gemini Enterprise, la découverte et la gouvernance des outils sont gérées de deux manières :
- Workflow MCP personnalisé direct (
BYO_MCP) : lorsque vous configurez un serveur MCP personnalisé directement dans Gemini Enterprise sans Agent Registry, le catalogue d'outils est géré par le datastore lui-même (connectorModes: ["FEDERATED", "ACTIONS"]). Vous devez ouvrir l'onglet Actions, cliquer sur ↻ Recharger les actions personnalisées pour récupérer le schématools/list, puis activer ou désactiver manuellement les outils individuels (addetsubtract) dans l'interface utilisateur. - Importation Agent Registry (workflow
REGISTRY_MCPutilisé dans cet atelier de programmation) : lorsque vous importez un serveur MCP depuis Agent Registry, Agent Registry sert de source de référence pour le point de terminaison MCP, ses métadonnées d'interface et son catalogue d'outils (connectorModes: ["FEDERATED"]). Gemini Enterprise active automatiquement les outils MCP enregistrés au moment de l'exécution via le paramètre Agent Gateway du moteur, sans que vous ayez à recharger ou à activer/désactiver manuellement les actions dans l'UI du datastore.
La partie concernant Gemini Enterprise est terminée. Passons maintenant à la section Valider.
9. Valider
Dans cette section, vous allez effectuer le parcours de consentement utilisateur unique de Google OAuth 2.0, appeler des outils MCP sur le serveur mcp-sprockets externe à partir de Gemini Enterprise, et vérifier que le serveur MCP externe a validé à la fois votre adresse IP statique Cloud NAT réservée (egress_source_ip) et votre identité Google OAuth 2.0 (authenticated_user).
Accès des utilisateurs
Construisez l'URL de l'application Web 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 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}"
Accorder le consentement OAuth
Avant d'interroger l'agent, vous devez effectuer un flux de consentement OAuth 2.0 unique qui accorde à Gemini Enterprise l'autorisation d'obtenir un jeton d'accès pour votre identité Google (${USER_IDENTITY}). Cela permet à Gemini Enterprise d'authentifier les appels d'outils sortants via Agent Gateway afin que le serveur mcp-sprockets externe puisse vérifier votre identité à chaque requête.
- Ouvrez
${GE_APP_USER_URL}dans votre navigateur, puis cliquez sur Premiers pas. - Dans la zone de discussion, cliquez sur l'icône Connecteurs (en forme de pièce de puzzle), puis sur Autoriser à côté de
mcp-sprockets-collection. - Une nouvelle fenêtre s'affiche et vous invite à choisir un compte pour continuer vers
mcp-sprockets-oauth(le nom de l'application de l'écran de consentement OAuth que vous avez configuré). Sélectionnez ensuite votre compte utilisateur (${USER_IDENTITY}). - Sur l'écran de consentement Google OAuth, examinez les autorisations demandées qui permettent à Google (le fournisseur d'identité) de partager votre identité utilisateur (
openid,email,profile) avecmcp-sprockets-oauth, puis cliquez sur Continuer. - Cliquez à nouveau sur l'icône Connecteurs et vérifiez que le bouton bascule pour
mcp-sprockets-collectionest activé, ce qui confirme que l'autorisation a réussi.
Tester les requêtes de l'agent
Tests de l'UI du chat avec l'Assistant
Envoyez la requête de test suivante dans le chat :
look up sprocket SPK-105 and confirm the model, material, unit_price, authenticated_user, and egress_source_ip
Essayez une deuxième requête dans le chat :
list all sprockets in the inventory catalog and report the authenticated_user and egress_source_ip
Vérifiez que l'assistant renvoie les bonnes réponses et affiche un badge de citation d'action interactif.
Par exemple, "Sprocket Lookup SPK-105 (5s)Agent Gateway" sous chaque réponse confirme que l'outil a été exécuté.
Vérifiez que l'assistant renvoie les caractéristiques du pignon avec "authenticated_user" correspondant à ${USER_IDENTITY} et "egress_source_ip" correspondant à votre ${NAT_EXT_IP} réservé.
Tests de l'API Assistant streamAssist
Une fois que votre compte utilisateur a autorisé le connecteur OAuth 2.0, vous pouvez également appeler l'API default_assistant:streamAssist directement depuis la CLI et vérifier que le serveur mcp-sprockets externe renvoie à la fois votre adresse IP statique Cloud NAT (${NAT_EXT_IP}) et votre identité Google OAuth 2.0 validée (${USER_IDENTITY}) :
Envoyez la requête de test suivante :
# query engine (ge app) streamAssist
curl -s -X POST "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}/assistants/default_assistant:streamAssist" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "X-Goog-User-Project: ${PROJ_ID}" \
-H "Content-Type: application/json" \
-d @- <<EOF | jq -r '.[].answer.replies[]?.groundedContent?.content?.text // empty'
{
"query": {
"text": "look up sprocket SPK-103 and confirm the model, material, unit_price, authenticated_user, and egress_source_ip"
},
"toolsSpec": {
"vertexAiSearchSpec": {
"dataStoreSpecs": [
{
"dataStore": "projects/${PROJ_NO}/locations/${GE_LOCATION}/collections/default_collection/dataStores/${GE_COLLECTION_ID}_mcp_data"
}
]
}
}
}
EOF
Exemple de résultat :
Here are the details for sprocket SPK-103 from the inventory catalog:
- Model: ANSI-60-16T
- Material: 304 Stainless Steel
- Unit Price: $42.00
- Authenticated User (Google OAuth 2.0): user@example.com
- Egress Source IP (Cloud NAT): 203.0.113.10
Essayez une autre requête :
# query engine (ge app) streamAssist
curl -s -X POST "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}/assistants/default_assistant:streamAssist" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "X-Goog-User-Project: ${PROJ_ID}" \
-H "Content-Type: application/json" \
-d @- <<EOF | jq -r '.[].answer.replies[]?.groundedContent?.content?.text // empty'
{
"query": {
"text": "find a sprocket model i can get for under \$20 and report the details, authenticated_user, and egress_source_ip"
},
"toolsSpec": {
"vertexAiSearchSpec": {
"dataStoreSpecs": [
{
"dataStore": "projects/${PROJ_NO}/locations/${GE_LOCATION}/collections/default_collection/dataStores/${GE_COLLECTION_ID}_mcp_data"
}
]
}
}
}
EOF
Inspecter les journaux dans Cloud Logging
Vérifiez que Gemini Enterprise a acheminé les appels d'outils via Agent Gateway, le rattachement de réseau PSC et Cloud NAT en inspectant les journaux dans Cloud Logging.
Vérifier les journaux Agent Gateway
Vérifiez que l'Agent Gateway a intercepté la requête, résolu la cible dans l'Agent Registry, évalué la règle d'autorisation et transféré l'appel d'outil :
# show agent gateway logs
gcloud logging read \
"resource.type=networkservices.googleapis.com/Gateway
AND resource.labels.location=${REGION}" \
--project=${PROJ_ID} \
--limit=8 \
--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
)"
Exemple de résultat :
TIMESTAMP STATUS SERVER_IP MCP_METHOD TOOL AUTHZ REGISTRY_MCP
YYYY-MM-DDTHH:MM:SS.ZZZ 200 203.0.113.20:443 tools/call get_sprocket_by_id ALLOWED agentregistry-00000000-0000-0000-5c39-1f6e542bb2b8
YYYY-MM-DDTHH:MM:SS.ZZZ 200 203.0.113.20:443 tools/list ALLOWED agentregistry-00000000-0000-0000-5c39-1f6e542bb2b8
YYYY-MM-DDTHH:MM:SS.ZZZ 202 203.0.113.20:443 notifications/initialized ALLOWED agentregistry-00000000-0000-0000-5c39-1f6e542bb2b8
YYYY-MM-DDTHH:MM:SS.ZZZ 200 203.0.113.20:443 initialize ALLOWED agentregistry-00000000-0000-0000-5c39-1f6e542bb2b8
Vérifiez que le résultat contient les éléments suivants :
STATUS:200(exécution réussie) et202(établissement de la liaisonnotifications/initialized).SERVER_IP: adresse IP et port du serveur MCP externe (${MCP_EXT_IP}:443).MCP_METHODetTOOL: séquence du protocole MCP (initialize,notifications/initialized,tools/listettools/callavecget_sprocket_by_id).AUTHZ:ALLOWED(sortie autorisée par IAP).REGISTRY_MCP: ID de ressource de l'Agent Registry résolu (agentregistry-...).
Vérifier les journaux Cloud NAT
Vérifiez que Cloud NAT a traduit la connexion sortante de l'adresse IP du rattachement de réseau PSC de l'Agent Gateway (10.10.10.2) en votre adresse IPv4 externe statique réservée (${NAT_EXT_IP}) lors de la connexion à ${MCP_EXT_IP}:443 :
# show cloud nat logs
gcloud logging read \
"resource.type=nat_gateway
AND resource.labels.gateway_name=nat-${SLUG}-${REGION}
AND jsonPayload.connection.dest_ip=${MCP_EXT_IP}" \
--project=${PROJ_ID} \
--limit=8 \
--format="table(
timestamp.date('', tz=LOCAL):label=TIMESTAMP,
jsonPayload.allocation_status:label=ALLOCATION_STATUS,
jsonPayload.connection.src_ip:label=SRC_IP,
jsonPayload.connection.nat_ip:label=NAT_IP,
jsonPayload.connection.dest_ip:label=DEST_IP,
jsonPayload.connection.dest_port:label=PORT
)"
Exemple de résultat :
TIMESTAMP ALLOCATION_STATUS SRC_IP NAT_IP DEST_IP PORT
YYYY-MM-DDTHH:MM:SS.ZZZ OK 10.10.10.2 203.0.113.10 203.0.113.20 443
Vérifier les journaux de pare-feu
Vérifiez que la stratégie de pare-feu interne (fw-policy-${SLUG}-internal) autorise le trafic sortant de l'Agent Gateway vers la destination Internet :
# show firewall policy logs (internal)
gcloud logging read \
"logName:compute.googleapis.com%2Ffirewall
AND jsonPayload.rule_details.reference:fw-policy-${SLUG}-internal" \
--project=${PROJ_ID} \
--limit=8 \
--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.vpc.vpc_name:label=VPC_NETWORK,
jsonPayload.rule_details.reference.basename():label=POLICY,
jsonPayload.rule_details.priority:label=RULE,
jsonPayload.rule_details.direction:label=DIRECTION,
jsonPayload.disposition:label=DISPOSITION
)"
Vérifiez que la stratégie de pare-feu externe (fw-policy-${SLUG}-external) autorise le trafic entrant vers le serveur MCP à partir de l'adresse IP NAT publique du réseau interne :
# show firewall policy logs (external)
gcloud logging read \
"logName:compute.googleapis.com%2Ffirewall
AND jsonPayload.rule_details.reference:fw-policy-${SLUG}-external" \
--project=${PROJ_ID} \
--limit=8 \
--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.vpc.vpc_name:label=VPC_NETWORK,
jsonPayload.rule_details.reference.basename():label=POLICY,
jsonPayload.rule_details.priority:label=RULE,
jsonPayload.rule_details.direction:label=DIRECTION,
jsonPayload.disposition:label=DISPOSITION
)"
La partie concernant la validation est terminée. Passons à la section Nettoyage.
10. Nettoyage
Suivez ces étapes pour supprimer les ressources et les configurations créées dans cet atelier.
Supprimer les composants 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"}}'
Pour supprimer les identifiants client OAuth 2.0 (ge-mcp-sprockets-client), ouvrez la page "Clients de la plate-forme Google Auth" et cliquez sur l'icône Supprimer (corbeille) à côté de ge-mcp-sprockets-client :
# print google auth platform clients url
echo "https://console.cloud.google.com/auth/clients?project=${PROJ_ID}"
Supprimer le serveur MCP et les composants Agent Registry
# delete external mcp server vm
gcloud -q compute instances delete vm-${MCP_NAME} --zone=${ZONE}
# delete agent registry mcp service
gcloud -q agent-registry services delete ${MCP_NAME} --location=${REGION}
# delete agent registry oauth2 endpoint
gcloud -q agent-registry services delete oauth2-googleapis --location=${REGION}
Supprimer les composants de l'Agent Gateway
# delete gateway authz policy and iap service extension
gcloud -q network-security authz-policies delete ${AGW_NAME}-authz-policy-iap \
--location=${REGION}
gcloud -q service-extensions authz-extensions delete ${AGW_NAME}-svc-ext-authz-iap \
--location=${REGION}
# delete agent gateway and connectivity template
gcloud -q network-services agent-gateways delete ${AGW_NAME} \
--location=${REGION}
gcloud -q network-services agent-connectivity-templates delete act-${AGW_NAME} \
--location=${REGION}
# delete iam unified access policy binding and access policy
gcloud -q iam policy-bindings delete uap-bind-${SLUG} \
--location=global \
--project=${PROJ_ID}
gcloud -q iam access-policies delete uap-policy-${SLUG} \
--location=global \
--project=${PROJ_ID}
Supprimer des composants de pare-feu
# delete network firewall policy associations
gcloud -q compute network-firewall-policies associations delete \
--name=fw-policy-bind-${SLUG}-internal \
--firewall-policy=fw-policy-${SLUG}-internal \
--global-firewall-policy
gcloud -q compute network-firewall-policies associations delete \
--name=fw-policy-bind-${SLUG}-external \
--firewall-policy=fw-policy-${SLUG}-external \
--global-firewall-policy
# delete custom firewall policy rules
gcloud -q compute network-firewall-policies rules delete 1001 \
--firewall-policy=fw-policy-${SLUG}-internal \
--global-firewall-policy
gcloud -q compute network-firewall-policies rules delete 2003 \
--firewall-policy=fw-policy-${SLUG}-external \
--global-firewall-policy
# delete network firewall policies
gcloud -q compute network-firewall-policies delete fw-policy-${SLUG}-internal \
--global
gcloud -q compute network-firewall-policies delete fw-policy-${SLUG}-external \
--global
Supprimer des composants réseau
# delete cloud nat gateway and cloud router
gcloud -q compute routers nats delete nat-${SLUG}-${REGION} \
--router=cr-nat-${SLUG}-${REGION} \
--region=${REGION}
gcloud -q compute routers delete cr-nat-${SLUG}-${REGION} \
--region=${REGION}
# delete psc network attachment
gcloud -q compute network-attachments delete psc-na-${REGION}-agw \
--region=${REGION}
# delete subnets
gcloud -q compute networks subnets delete subnet-${REGION}-agw \
--region=${REGION}
gcloud -q compute networks subnets delete subnet-${REGION}-mcp \
--region=${REGION}
# delete reserved static external ip addresses
gcloud -q compute addresses delete ip-${SLUG}-nat ip-${SLUG}-mcp \
--region=${REGION}
# delete internal and external vpc networks
gcloud -q compute networks delete \
vnet-${SLUG}-internal \
vnet-${SLUG}-external
Supprimer les remplacements des règles d'administration et les fichiers locaux
# delete project-level organization policy overrides
for policy in \
discoveryengine.managed.disableCustomMcpServerConnector \
discoveryengine.managed.allowedEgressFqdns \
discoveryengine.managed.allowedDataSources \
iam.managed.disableAccessPolicyBinding \
compute.vmExternalIpAccess; do
gcloud -q org-policies delete ${policy} --project=${PROJ_ID} 2>/dev/null || true
done
# remove local project files
rm -rf cfg
Le nettoyage est terminé. Passons à la conclusion !
11. Conclusion
Félicitations ! Vous avez créé une architecture de bout en bout permettant à une application Gemini Enterprise de découvrir et d'appeler des outils de manière sécurisée sur un serveur MCP personnalisé externe protégé par OAuth 2.0 et dont l'adresse IP est autorisée :
- Sortie VPC avec adresse IP statique (
ALL_TRAFFICet Cloud NAT) : tout le trafic sortant de l'Agent Gateway a été acheminé via un rattachement de réseau PSC (10.10.10.2), et les requêtes destinées à Internet ont été traduites en une adresse IPv4 externe statique réservée (${NAT_EXT_IP}) à l'aide de Cloud NAT. - Serveur de ressources MCP OAuth 2.0 et Agent Registry : déploiement d'un serveur FastMCP HTTP externe et diffusable (
mcp-sprockets) protégé par une liste d'autorisation stricte du pare-feu d'adresse IP source (${NAT_EXT_IP}/32) et la validation Google OAuth 2.0tokeninfo, et enregistrement de son point de terminaison et de son schéma d'outil (get_sprocketsetget_sprocket_by_id) dans Agent Registry. - Intégration et gouvernance OAuth 2.0 de Gemini Enterprise : provisionnement d'une application Gemini Enterprise, liaison du trafic d'outils sortant à Agent Gateway, association du serveur MCP enregistré en tant que connecteur de données OAuth 2.0
REGISTRY_MCPet vérification deegress_source_ipetauthenticated_useravec la télémétrie Cloud Logging.

Cosmopup pense que les ateliers de programmation sont géniaux !
Et ensuite ?
- Consultez la documentation Gemini Enterprise Agent Platform pour découvrir les fonctionnalités avancées et les tutoriels.
- Configurez des garde-fous Model Armor sur Agent Gateway pour renforcer la sécurité de l'IA.
- Découvrez les Règles de gouvernance sémantique pour appliquer les règles commerciales et la conformité aux requêtes en langage naturel.
N'hésitez pas à nous faire part de vos commentaires, questions ou corrections en remplissant ce formulaire.
Merci !