1. Introduzione
Questo codelab esplora la connettività di uscita IP statica per Gemini Enterprise utilizzando Agent Gateway in modalità agent-to-anywhere (uscita). Configurerai un'app Gemini Enterprise per richiamare un server Model Context Protocol (MCP) personalizzato, protetto da una rigorosa lista consentita di IP di origine e dall'autenticazione OAuth 2.0, instradando tutto il traffico in uscita tramite Agent Gateway utilizzando una configurazione del modello di connettività. Un collegamento di rete Private Service Connect (PSC) connette Agent Gateway alla rete VPC e Cloud NAT fornisce un indirizzo IP esterno stabile per il traffico in uscita verso internet.
Per impostazione predefinita, le connessioni in uscita da Gemini Enterprise agli endpoint internet pubblici hanno origine da pool di indirizzi IP Google condivisi e dinamici che non possono essere associati a una singola regola di elenco consentito di IP di proprietà del cliente. L'accoppiamento di Agent Gateway con un AgentConnectivityTemplate in modalità ALL_TRAFFIC instrada tutto il traffico in uscita dell'agente nella rete VPC, dove Cloud NAT traduce le connessioni destinate a internet in un indirizzo IPv4 esterno statico riservato sotto il tuo controllo, mantenendo al contempo la governance centralizzata dello strumento MCP tramite Agent Registry e Identity-Aware Proxy (IAP).
Cosa crei
- Modello di connettività dell'agente (
vpcEgress: ALL_TRAFFIC) e Agent Gateway in modalità di uscita (da agente a ovunque) con verifica dell'endpoint Agent Registry - Rete VPC, collegamento di rete PSC, router Cloud e gateway Cloud NAT associati a un indirizzo IPv4 esterno statico riservato
- Server di risorse HTTP MCP trasmissibili esternamente (
mcp-sprockets) front-end di Caddy TLS, limitato dalle regole firewall rigorosamente all'IP statico Cloud NAT e che verifica i token di autenticazione Google OAuth 2.0 con delega utente rispetto ahttps://oauth2.googleapis.com/tokeninfo - Schermata per il consenso OAuth 2.0 della piattaforma di autenticazione Google e credenziali client OAuth 2.0 dell'applicazione web (
accounts.google.comeoauth2.googleapis.com/token) - Voce di catalogo del server MCP di Agent Registry e specifica dello strumento (
toolspec.json) - Estensione dell'autorizzazione Identity-Aware Proxy (IAP) e policy di autorizzazione del gateway per Agent Gateway
- App Gemini Enterprise associata ad Agent Gateway e connessa a un datastore del server MCP personalizzato OAuth 2.0 importato da Agent Registry
Fig. 1 Architettura del codelab
Cosa imparerai
- Come configurare un
AgentConnectivityTemplateconvpcEgress: ALL_TRAFFICper instradare tutto il traffico in uscita di Agent Gateway in una rete VPC - Come prenotare un indirizzo IPv4 esterno statico e associarlo a Cloud NAT in una subnet di collegamento di rete PSC
- Come eseguire il deployment di un server di risorse HTTP MCP esterno trasmissibile in streaming che verifica i token di connessione OAuth 2.0 di Google (
oauth2.googleapis.com/tokeninfo) e limitare il firewall in entrata rigorosamente all'IP statico Cloud NAT (${NAT_EXT_IP}/32) - Come configurare le credenziali client OAuth 2.0 di Google Identity e registrare un server MCP e il relativo schema di strumenti in Agent Registry
- Come connettere un server MCP OAuth 2.0 registrato a Gemini Enterprise e instradare le chiamate di strumenti delegate dall'utente tramite Agent Gateway
- Come convalidare la conversione IP statica, la verifica dell'identità OAuth 2.0 dell'utente finale (
authenticated_user) e l'applicazione dei criteri del gateway utilizzando i comandi CLI e Cloud Logging
Cosa serve
- Un progetto cloud Google Cloud con la fatturazione abilitata
- Una licenza Gemini Enterprise attiva o una prova di 30 giorni
- Autorizzazioni IAM per il provisioning di servizi di rete, policy dell'organizzazione, Gemini Enterprise e risorse Agent Platform
- Una shell compatibile con POSIX (
bashozsh) con Google Cloud CLI (gcloud),curlejqinstallati
Con questo si conclude la parte introduttiva. Passiamo ora alla sezione Concetti.
2. Concetti
Sequenza di deployment
Questo codelab esegue il deployment dell'infrastruttura di networking e governance per prima, in modo che i percorsi di uscita IP statici e i controlli del gateway siano operativi prima di registrare e connettere gli strumenti MCP a Gemini Enterprise:
- Infrastruttura di rete:prenota indirizzi IPv4 esterni statici e esegui il provisioning del VPC di uscita, della subnet di collegamento PSC, del collegamento di rete PSC, di Cloud Router, del gateway Cloud NAT e delle regole firewall di rete MCP esterna.
- Modello di connettività degli agent e Agent Gateway: esegui il deployment di
AgentConnectivityTemplate(vpcEgress: ALL_TRAFFIC) eAgentGatewayregionale in modalità di uscita (AGENT_TO_ANYWHERE) con l'integrazione di Agent Registry (registries). - Policy di autorizzazione:configura l'estensione dell'autorizzazione IAP (
AuthzExtension), la policy di autorizzazione gateway (AuthzPolicy) e la policy di accesso unificata IAM v3 (AccessPolicyePolicyBinding). - Esegui il deployment e registra il server MCP: esegui il deployment del server di risorse OAuth 2.0
mcp-sprocketsesterno dietro Caddy TLS, verifica l'applicazione di Google OAuth 2.0tokeninfo, blocca il firewall in entrata rigorosamente all'IP statico Cloud NAT (${NAT_EXT_IP}/32) e registra le specifiche del servizio e dello strumento (get_sprocketseget_sprocket_by_id) in Agent Registry. - App Gemini Enterprise e client OAuth 2.0:configura il provider Google Identity, la licenza di prova, la schermata per il consenso OAuth 2.0 e le credenziali client dell'applicazione web (
OAUTH_CLIENT_IDeOAUTH_CLIENT_SECRET), crea l'app Gemini Enterprise (Engine) e associa l'uscita in uscita a Agent Gateway (agentGatewaySetting). - Importa connettore dati MCP personalizzato:crea e attiva il connettore dati
REGISTRY_MCP(:setUpDataConnector) configurato conauth_type: "OAUTH"per collegare il datastore di backend del server MCP registrato all'app Gemini Enterprise. - Convalida:completa il flusso di consenso OAuth 2.0 una tantum per l'utente, richiama gli strumenti MCP tramite l'assistente Gemini Enterprise (confermando sia
egress_source_ipcheauthenticated_user) e verifica l'applicazione dei criteri e la conversione NAT IP statica in Cloud Logging.
Architettura del server di risorse MCP protetto da OAuth + IdP centrale
Nelle implementazioni aziendali, la gestione delle identità e l'esecuzione degli strumenti seguono la separazione standard dei ruoli OAuth 2.0 tra un provider di identità centralizzato (server di autorizzazione) e un server di risorse MCP protetto:
Ruolo OAuth 2.0 | Componente in questo codelab | Responsabilità |
Proprietario risorsa | Utente finale ( | Accede all'app web Gemini Enterprise e concede il consenso durante il flusso di autorizzazione OAuth 2.0 a tre passaggi una tantum. |
Client OAuth 2.0 | Connettore dati | Contiene |
Server di autorizzazione | Google Identity OAuth 2.0 ( | Autentica l'utente durante il reindirizzamento del consenso del browser ed emette i token di accesso e aggiornamento OAuth 2.0 per Gemini Enterprise. |
Server di risorse | Server | Applica l'identità di rete di livello 3 utilizzando il firewall VPC ( |
Poiché il reindirizzamento del consenso del browser (accounts.google.com) e lo scambio di token back-channel (oauth2.googleapis.com/token) avvengono rispetto agli endpoint OAuth 2.0 gestiti da Google, il firewall del server MCP esterno riceve solo richieste JSON-RPC MCP di runtime (POST /mcp) da Agent Gateway tramite Cloud NAT, consentendo di bloccare il firewall in entrata rigorosamente su ${NAT_EXT_IP}/32.
Modello di risorse Discovery Engine
Un'app Gemini Enterprise (rappresentata come risorsa Engine nell'API Discovery Engine) è il livello di orchestrazione centrale e l'interfaccia conversazionale per gli utenti finali. Gestisce le sessioni di chat degli utenti, basa i modelli generativi sui dati aziendali e coordina l'esecuzione dinamica degli strumenti.
Le app Gemini Enterprise interagiscono con dati e sistemi tramite i datastore:
- Datastore di conoscenza:acquisisce e indicizza contenuti statici (ad es. Cloud Storage, Google Drive, BigQuery) per la Retrieval-Augmented Generation (RAG).
- Connettori di dati (fornitori di azioni): connettiti ad API dinamiche di terze parti o personalizzate. Un datastore del server MCP personalizzato espone gli strumenti definiti dal Model Context Protocol (MCP), consentendo al modello di chiamare dinamicamente funzioni esterne durante una conversazione.
Egress di Gemini Enterprise
Gemini Enterprise indirizza le richieste di strumenti del server MCP personalizzato ad Agent Gateway quando sono configurati sia agentGatewaySetting su Engine sia use_agent_gateway_egress: true su DataConnector.
Fig. 2. Architettura di uscita di Gemini Enterprise
L'app Gemini Enterprise organizza il routing degli strumenti in quattro aree chiave:
- Widget (
default_search_widget_config):- Fornisce l'interfaccia del client web. Il widget riceve prompt dall'utente, attiva il reindirizzamento del consenso dell'utente OAuth 2.0 una tantum quando uno strumento richiede l'autorizzazione e avvia sessioni di chat con il motore sottostante.
- Core Assistant (
assistants/default_assistant/agents/default/core_assistant):- L'agente di ragionamento conversazionale principale all'interno del motore. Quando valuta una query dell'utente, l'assistente principale esamina gli strumenti disponibili e delega l'esecuzione al sottoagente Agent Gateway sintetizzato.
- Datastore e connettore dati:
DataStore: eseguito il provisioning all'interno di unCollectiondedicato quando viene eseguito:setUpDataConnector, collega (dataStoreIds) gli schemi dello strumento Registro agenti importati (get_sprockets,get_sprocket_by_id), i tipi di argomenti e le istruzioni dell'agente a Gemini EnterpriseEngine.DataConnector: gestisce la connessione dell'azioneREGISTRY_MCP(createBapConnection: true) al server MCP remoto (instance_uri), risolve la risorsa del server MCP di Agent Registry (registry_mcp_server_name), allega il token OAuth 2.0 Bearer protetto dall'utente (Authorization: Bearer [access_token]) e attiva l'uscita di Agent Gateway (use_agent_gateway_egress: true).
- Agent Identity, Agent Registry e Agent Gateway:
- Quando il connettore dati invia la chiamata allo strumento in uscita, indirizza il traffico al gateway specificato in
agentGatewaySetting. Il Centro Assistant crea un token di identità SPIFFE che asserisce la sua identità del workload:principal://agents.global.org-.../agents/default/core_assistant. - Agent Gateway si integra con Agent Registry utilizzando il campo
registriesper risolvere dinamicamente gli endpoint di destinazione e gli schemi degli strumenti registrati, valuta le policy di autorizzazione utilizzando IAP e inoltra le richieste consentite (conservando l'intestazioneAuthorization: Bearerdell'utente) nella rete VPC utilizzandoAgentConnectivityTemplate.
- Quando il connettore dati invia la chiamata allo strumento in uscita, indirizza il traffico al gateway specificato in
Connettività VPC gateway e NAT IP statico
Agent Gateway supporta la connettività di rete VPC utilizzando una risorsa AgentConnectivityTemplate a cui fa riferimento agentConnectivityTemplate sul gateway. Il modello egressNetworkConfig definisce il modo in cui il traffico entra nel VPC tramite un collegamento di rete PSC:
PRIVATE_RANGES_ONLY(impostazione predefinita): instrada solo gli intervalli IP privati RFC 1918, RFC 6598 e Classe E tramite il collegamento di rete PSC. Il traffico diretto a internet bypassa il VPC ed esce direttamente tramite l'uscita internet predefinita di Google.ALL_TRAFFIC(utilizzato in questo codelab): instrada tutto il traffico in uscita da Agent Gateway, inclusi internet pubblico ed endpoint MCP partner esterni, nella tua subnet VPC tramite il collegamento di rete PSC (10.10.10.2).
Quando operi in modalità ALL_TRAFFIC, la subnet di collegamento PSC richiede due configurazioni:
- Accesso Google privato (
--enable-private-ip-google-access): garantisce che le chiamate interne alle API Google Cloud (*.googleapis.com) continuino a essere instradate privatamente all'interno della rete Google. - Cloud Router e Cloud NAT (
MANUAL_ONLY): il traffico diretto a internet che entra nella subnet di collegamento PSC segue la route predefinita (0.0.0.0/0) tramite Cloud NAT, che esegue la Network Address Translation dell'origine (SNAT) al tuo indirizzo IPv4 esterno statico riservato (${NAT_EXT_IP}). I firewall esterni possono quindi limitare l'accesso in entrata rigorosamente a${NAT_EXT_IP}/32.
Limitazioni e requisiti
- Solo StreamableHTTP:il trasporto legacy Server-Sent Events (SSE) non è supportato. I server MCP devono utilizzare StreamableHTTP.
- Override delle norme dell'organizzazione:devi eseguire l'override delle norme dell'organizzazione per gli archivi di dati MCP personalizzati prima di registrare il connettore dati.
- Allineamento regionale:Gemini Enterprise applica l'allineamento regionale tra la posizione dell'app, Agent Gateway e Agent Registry:
Posizione dell'app Gemini Enterprise | Posizione di Agent Gateway e NAT | Posizione di Agent Registry |
|
|
|
|
|
|
|
|
|
Con questo si conclude la parte relativa ai concetti. Passiamo ora alla sezione Configurazione.
3. Configurazione
Ruoli IAM richiesti
Per completare questo codelab sono necessari i seguenti ruoli:
Dominio | Ruoli IAM richiesti |
Progetto e IAM |
|
Networking e gateway |
|
Gemini Enterprise e Registro |
|
Workload |
|
Osservabilità |
|
In alternativa, utilizza un ruolo di base generico come roles/owner combinato con roles/orgpolicy.policyAdmin (dato che roles/owner da solo non può modificare i criteri dell'organizzazione).
Accedere al progetto
Questo codelab utilizza un singolo progetto cloud di Google. I passaggi di configurazione utilizzano i comandi della shell Linux e dell'interfaccia a riga di comando gcloud.
Inizia accedendo alla riga di comando del tuo progetto Google Cloud:
- Cloud Shell all'indirizzo
shell.cloud.google.comoppure - Un terminale locale con l'interfaccia a riga di comando
gcloudinstallata
Impostare l'ID progetto
# set target project id
gcloud config set project SET_YOUR_PROJECT_ID_HERE
Autenticare la sessione
# login to gcloud cli
gcloud auth login
# login for gcloud api
gcloud auth application-default login
Imposta le variabili di ambiente della 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}
Imposta i domini di attendibilità dell'identità dell'agente
L'istruzione if-then-else verifica se il progetto appartiene a un'organizzazione per impostare il dominio di attendibilità corretto per le identità dell'agente principale.
# 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}"
Imposta il progetto di fatturazione e 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}
Crea la directory locale per i file di configurazione
# create config folder
mkdir -p cfg
Aggiorna gcloud cli (consigliato)
Se esegui un'installazione autogestita di Google Cloud SDK (ovvero al di fuori di Cloud Shell), aggiorna i componenti all'ultima versione.
# update gcloud cli
gcloud components update
Abilitare i servizi 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
Policy dell'organizzazione
I vincoli dei criteri dell'organizzazione gestiti e i criteri sandbox predefiniti di Google Cloud possono limitare le funzionalità utilizzate in questo codelab:
compute.vmExternalIpAccess: limita gli indirizzi IPv4 esterni sulle VM Compute Engine nelle organizzazioni sandbox bloccate.discoveryengine.managed.disableCustomMcpServerConnector: limita la creazione di connettori dati che utilizzano un server MCP personalizzato (custom_mcp) come origine dati (applicato per impostazione predefinita).discoveryengine.managed.allowedEgressFqdns: limita i domini di uscita in uscita (FQDNinstance_uri) per i connettori dati quando Controlli di servizio VPC (VPC-SC) è attivo o il progetto è elencato inenforcedProjects.discoveryengine.managed.allowedDataSources: limita i tipi di connettori dati consentiti (dataSource) quando VPC-SC è attivo o il progetto è elencato inenforcedProjects.
Ignora eventuali limitazioni delle policy dell'organizzazione ereditate a livello di progetto.
Disattiva vincolo MCP personalizzato
# 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
Disattiva i vincoli del connettore di dati condizionali
# 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
Disattiva il vincolo della policy di accesso
# 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
Consenti indirizzi IP esterni
# 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
Verifica le policy dell'organizzazione
Verifica che compute.vmExternalIpAccess sia impostato su allowAll: True e che gli altri criteri siano 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
Verifica delle associazioni dell'agente di servizio (misura precauzionale)
In un nuovo progetto, Google Cloud esegue automaticamente il provisioning dell'agente di servizio Agent Gateway e gli concede roles/agentgateway.serviceAgent quando networkservices.googleapis.com viene abilitato per la prima volta. Se riutilizzi un progetto esistente in cui la pulizia precedente potrebbe aver rimosso le associazioni del service agent predefinite, esegui i seguenti comandi come fail-safe per assicurarti che l'identità e l'associazione del ruolo siano intatte:
# 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"
Con questo si conclude la parte di configurazione. Passiamo ora alla sezione Rete.
4. Rete
In questa sezione, prenoti gli indirizzi IPv4 esterni statici, crei la rete VPC di uscita interna e la rete VPC esterna isolata, esegui il provisioning del collegamento di rete PSC, configuri Cloud NAT e crei regole firewall.
Prenota indirizzi IP esterni statici
Prenota due indirizzi IPv4 esterni statici regionali per Cloud NAT e la VM del server MCP esterno:
# 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}
Verifica gli indirizzi IP esterni statici
Gemini Enterprise richiede che gli endpoint MCP remoti utilizzino HTTPS con un certificato TLS considerato attendibile pubblicamente. Anziché registrare un dominio personalizzato per questo lab, utilizzi sslip.io, un servizio DNS con caratteri jolly senza costi che risolve qualsiasi nome host contenente un indirizzo IP (ad esempio mcp.[IP].sslip.io) direttamente a quell'IP. Poiché le autorità di certificazione come Let's Encrypt non emettono certificati per indirizzi IP semplici, questo nome host sslip.io fornisce al proxy inverso Caddy un nome di dominio valido per eseguire automaticamente il provisioning di un certificato TLS attendibile per il server MCP.
Esporta entrambi gli indirizzi IPv4 e crea il nome di dominio e l'URL sslip.io per il server MCP esterno:
# 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}"
Output di esempio:
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
Crea rete interna
Quando il modello di connettività dell'Agent Gateway è configurato per utilizzare un egressNetworkConfig con un networkAttachment, la subnet che ospita il collegamento di rete PSC deve essere almeno un blocco CIDR /28 e avere l'accesso privato Google (--enable-private-ip-google-access) abilitato.
Crea una rete VPC globale per l'uscita di Agent Gateway interno:
# 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
Crea regole firewall interne
Crea una policy del firewall per consentire tutto il traffico in uscita con il logging abilitato. Verrà utilizzato per monitorare il traffico in uscita da Agent Gateway alla rete VPC interna. Cloud NGFW supporta i livelli Essentials e Standard per la sicurezza di rete e il monitoraggio del traffico.
# 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
Crea collegamento di rete PSC
Crea un collegamento di rete Private Service Connect (PSC) configurato per accettare automaticamente le connessioni da Agent Gateway. Il collegamento di rete stabilisce il lato della connessione della rete VPC consumer per il collegamento sicuro con il lato producer di Agent Gateway per il traffico in uscita. Per ulteriori informazioni sui requisiti delle subnet e sulle specifiche dell'intervallo IP, consulta Configurare la connettività VPC.
# create psc network attachment
gcloud compute network-attachments create psc-na-${REGION}-agw \
--region=${REGION} \
--subnets=subnet-${REGION}-agw \
--connection-preference=ACCEPT_AUTOMATIC
Verifica il collegamento di rete PSC
# show psc network attachment details
gcloud compute network-attachments describe psc-na-${REGION}-agw --region=${REGION}
Recupera l'URI della risorsa del collegamento di rete PSC e memorizzalo nella variabile di ambiente PSC_NA_URI. Questo URI verrà utilizzato nella configurazione di Agent Gateway (networkConfig.egress.networkAttachment) per eseguire il provisioning dell'interfaccia PSC per l'uscita di rete nella rete VPC:
# fetch psc network attachment uri
export PSC_NA_URI=$(gcloud compute network-attachments describe psc-na-${REGION}-agw \
--region=${REGION} \
--format="value(selfLink.scope(v1))")
echo ${PSC_NA_URI}
Crea Cloud NAT
Cloud NAT viene utilizzato per convertire l'indirizzo IP di origine del traffico in uscita di Agent Gateway nell'indirizzo IP pubblico riservato per il routing su internet pubblico.
Solo le origini della subnet di collegamento di rete in uscita di Agent Gateway sono definite idonee all'utilizzo di 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
Verifica Cloud NAT
Controlla lo stato di Cloud NAT e che sia configurata l'origine natIP prevista:
# 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)"
Output di esempio:
name: nat-foo-us-central1
natIps:
- https://www.googleapis.com/compute/v1/projects/[PROJ_ID]/regions/us-central1/addresses/ip-foo-nat
Crea rete esterna
Crea una rete VPC separata e isolata per ospitare la VM del server MCP esterno.
# 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
Crea regole firewall esterne
Crea due regole firewall in entrata sulla rete VPC esterna:
2001: consente la porta TCP in entrata80in modo che Let's Encrypt possa completare il challenge di convalida del dominio ACME HTTP-01 per${MCP_DOMAIN}.2002: inizialmente consente la porta TCP in entrata443da0.0.0.0/0per verificare la compatibilità con TLS e l'applicazione di OAuth 2.0tokeninfodalla shell locale prima di bloccarla rigorosamente su${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
Con questo si conclude la parte relativa alla rete. Passiamo ora alla sezione Agent Gateway.
5. Agent Gateway
In questa sezione, esegui il deployment del modello di connettività dell'agente con vpcEgress: ALL_TRAFFIC, esegui il deployment di Agent Gateway regionale, delega l'autorizzazione a Identity-Aware Proxy (IAP) e definisci le regole dei criteri di accesso unificato IAM per gestire le richieste di rete in uscita.
Crea template di connettività
Le specifiche del modello di connettività definiscono:
egressNetworkConfig.networkAttachment: punta al collegamento di rete PSC, connettendo Agent Gateway alla tua rete VPC.egressNetworkConfig.vpcEgress: impostato suALL_TRAFFICin modo che tutte le connessioni in uscita dell'agente (inclusi gli endpoint MCP di internet pubblico) vengano instradate nella rete VPC ed escano utilizzando la conversione dell'indirizzo IP di origine Cloud NAT.
Crea e importa il file di configurazione del modello di connettività:
# 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}
Crea Agent Gateway
La specifica di Agent Gateway definisce:
agentConnectivityTemplate: punta al modello di connettività, in modo che il gateway possa utilizzare il collegamento di rete PSC per la connettività VPC.registries: associa il gateway ad Agent Registry regionale per risolvere gli endpoint MCP e gli schemi degli strumenti catalogati.
Crea e importa il file di configurazione di 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}
Verifica il deployment di Agent Gateway
Conferma la configurazione dell'Agent Registry e del modello di connettività:
# verify agent gateway deployment details
gcloud network-services agent-gateways describe ${AGW_NAME} \
--location=${REGION} \
--format="yaml(name,agentConnectivityTemplate,registries)"
Output di esempio:
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
Ispeziona il collegamento di rete PSC per confermare la connessione del gateway:
# show psc network attachment details
gcloud compute network-attachments describe psc-na-${REGION}-agw \
--region=${REGION} \
--format="yaml(connectionEndpoints)"
Output di esempio:
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
Delega dell'autorizzazione
Agent Gateway protegge e gestisce il traffico degli strumenti in uscita utilizzando le policy di autorizzazione (networksecurity.authzPolicies) integrate con le Unified Access Policies (UAP) di Identity-Aware Proxy (IAP).
Sebbene Agent Gateway supporti le regole di ALLOW e DENY di base in linea, gli ambienti aziendali richiedono una governance centralizzata e incentrata sull'identità. Con le Unified Access Policies IAM (o policy di accesso), gestisci le regole di accesso in uscita utilizzando le policy di accesso IAM v3 standard.
Fig. 3. Architettura di autorizzazione
Il flusso di autorizzazione collega tre componenti:
- Norme di autorizzazione del gateway (
authzPolicy):- Una risorsa di regione di targeting per Agent Gateway.
- Configurato con
policyProfile: REQUEST_AUTHZeaction: CUSTOMper indirizzare tutti i controlli di autorizzazione in uscita all'estensione dell'autorizzazione IAP.
- Estensione del servizio IAP (
authzExtension):- Una risorsa di regione che delega l'autorizzazione delle richieste a Identity-Aware Proxy (
iap.googleapis.com). - Valuta le policy in modalità
ENFORCEutilizzando la versioneV2della policy.
- Una risorsa di regione che delega l'autorizzazione delle richieste a Identity-Aware Proxy (
- Policy e binding di accesso unificato IAM (
accessPolicyepolicyBinding):- Risorse IAM globali v3 contenenti regole di accesso granulari.
- Autentica l'identità principale SPIFFE dell'agente chiamante, verifica l'autorizzazione universale
iap.googleapis.com/resources.egressViaIAPe valuta le condizioni del linguaggio Common Expression Language (CEL) in base agli attributi di destinazione.
Implementare l'estensione dell'autorizzazione
# 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}
Verifica l'estensione dell'autorizzazione
Controlla che l'estensione dell'autorizzazione sia attiva:
# 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
)"
Esegui il deployment della policy di autorizzazione
Crea una configurazione dei criteri di autorizzazione network-security che ha come target Agent Gateway e delega la verifica delle richieste all'estensione dell'autorizzazione per IAP:
# create authz policy config file
cat > cfg/${AGW_NAME}-authz-policy-iap.yaml << EOF
name: ${AGW_NAME}-authz-policy-iap
target:
resources:
- "projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
policyProfile: REQUEST_AUTHZ
action: CUSTOM
customProvider:
authzExtension:
resources:
- "projects/${PROJ_ID}/locations/${REGION}/authzExtensions/${AGW_NAME}-svc-ext-authz-iap"
EOF
# import authz policy config file (create authz policy)
gcloud network-security authz-policies import ${AGW_NAME}-authz-policy-iap \
--source=cfg/${AGW_NAME}-authz-policy-iap.yaml \
--location=${REGION}
Verifica della policy di autorizzazione
Verifica che la policy di autorizzazione sia attiva:
# 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
)"
Crea policy di accesso IAM
Agent Gateway ora delega i controlli di autorizzazione a IAP e risolve i metadati di destinazione da Agent Registry. Successivamente, definisci una regola di policy Unified Access Policies IAM per gestire l'esecuzione dello strumento in uscita.
IAP valuta le espressioni degli attributi CEL in base ai seguenti attributi di destinazione di Agent Registry:
- Stato di registrazione (
destination.is_registered):- Valore booleano (
true/false) che indica se la destinazione è catalogata in Agent Registry.
- Valore booleano (
- Nome server MCP (
destination.agent_registry.mcp_server.name):- Nome risorsa del server MCP canonico registrato in Agent Registry.
- Metodo MCP (
destination.agent_registry.mcp_server.method):- Il metodo MCP richiamato (ad es.
tools/call,tools/list,initialize).
- Il metodo MCP richiamato (ad es.
- Nome strumento (
destination.agent_registry.mcp_server.tool.name):- Il nome dello strumento specifico richiamato (ad es.
get_sprocket_by_idoget_sprockets), che consente un'autorizzazione granulare a livello di strumento sui server MCP registrati.
- Il nome dello strumento specifico richiamato (ad es.
Definisci la regola della policy di accesso IAM
Il manifest della regola di policy IAM specifica:
- Soggetti:l'identità del soggetto SPIFFE che rappresenta l'agente assistente principale di Gemini Enterprise.
- Autorizzazioni:l'autorizzazione universale
iap.googleapis.com/resources.egressViaIAPrichiesta per tutto il traffico in uscita regolato da IAP. - Condizioni:un'espressione CEL (
destination.is_registered == true) che garantisce che l'agente possa richiamare solo gli endpoint catalogati in Agent Registry.
Crea il file manifest della regola della policy:
# 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
Esegui il deployment della policy di accesso IAM
Crea la policy di accesso IAM globale utilizzando le regole definite nel file manifest:
# 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
Verifica la policy di accesso IAM
Controlla che la policy di accesso IAM sia stata creata correttamente ed esamina i dettagli della regola:
# show iam access policy details
gcloud iam access-policies describe uap-policy-${SLUG} \
--project=${PROJ_ID} \
--location=global
Output di esempio:
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
Associa la policy di accesso IAM al progetto
Per attivare l'applicazione in tutti i gateway agent nel tuo progetto, crea un binding dei criteri che colleghi il criterio di accesso IAM alla risorsa progetto:
# 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
Verifica l'associazione della policy di accesso IAM
Controlla che i punti di associazione delle norme attive rimandino alle norme e al target corretti:
# show policy binding details
gcloud iam policy-bindings describe uap-bind-${SLUG} \
--project=${PROJ_ID} \
--location=global
Con questo si conclude la sezione di Agent Gateway. Passiamo ora alla sezione del server MCP.
6. Server MCP
In questa sezione, esegui il deployment di un server risorse OAuth 2.0 (mcp-sprockets) FastMCP esterno che espone gli strumenti get_sprockets e get_sprocket_by_id, verifica che convalidi crittograficamente i token di tipo Bearer Google OAuth 2.0 rispetto a https://oauth2.googleapis.com/tokeninfo. Successivamente, bloccherai la regola firewall esterna rigorosamente all'IP statico Cloud NAT.
Esegui il deployment del server MCP esterno
Uno script di avvio installa Caddy e FastMCP, avvia il server mcp-sprockets su 127.0.0.1:8080 e configura Caddy per erogare HTTPS su ${MCP_DOMAIN}.
Ogni volta che Gemini Enterprise chiama uno strumento MCP (ad es. get_sprockets e get_sprocket_by_id), il server:
- Leggi l'IP di origine del chiamante dall'intestazione
X-Forwarded-For(egress_source_ip). - Estrai l'intestazione
Authorization: Bearer [access_token]e verifica il token rispetto all'endpoint di verifica Google OAuth 2.0 (https://oauth2.googleapis.com/tokeninfo?access_token=[token]). - Restituisci
"authenticated_user"([user_email]) insieme a"egress_source_ip", dimostrando che il server MCP esterno ha verificato sia l'IP statico Cloud NAT sia l'identità Google OAuth 2.0 dell'utente finale.
# 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"
Verifica la preparazione del server MCP e la convalida di OAuth 2.0 tokeninfo
Attendi qualche minuto affinché lo script di avvio installi FastMCP e Caddy e venga eseguito il provisioning del certificato 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
Convalida la risoluzione DNS di sslip.io, il certificato TLS Let's Encrypt fornito da Caddy e la risposta FastMCP tools/list:
# 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:"
Output di esempio:
* 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}}]}}
Prima di bloccare il firewall esterno, esegui un test tools/call passando un token Bearer Google OAuth 2.0 (gcloud auth print-access-token) per verificare che mcp-sprockets convalidi il token rispetto a https://oauth2.googleapis.com/tokeninfo e restituisca l'email "authenticated_user" insieme all'indirizzo IP di origine del chiamante:
# 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'
Output di esempio (che mostra l'IP diretto di Cloud Shell prima del blocco del firewall e la tua email Google OAuth verificata):
{
"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
}
}
Blocca il firewall all'IP statico Cloud NAT
Aggiorna il criterio firewall della rete VPC esterna in modo che la porta TCP 443 accetti il traffico solo dall'IP esterno statico di 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
Verifica che siano presenti le regole della policy del firewall esterno:
# 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
)"
Verifica che le connessioni dirette al di fuori dell'IP statico Cloud NAT siano ora bloccate:
# query mcp server
curl -i --connect-timeout 5 "${MCP_URL}" \
|| echo "Expected: Direct access blocked (not originating from ${NAT_EXT_IP})"
Output di esempio:
curl: (28) Connection timed out after 5001 milliseconds
Expected: Direct access blocked (not originating from 203.0.113.10)
Con questo si conclude la parte relativa al server MCP. Passiamo ora alla sezione Agent Registry.
7. Agent Registry
Agent Registry è un inventario centralizzato di tutti gli agenti, i server MCP e gli endpoint (API) nell'ecosistema dell'AI. È anche un catalogo che può essere utilizzato per elencare, cercare e scoprire altri strumenti e servizi registrati da utilizzare per le applicazioni di AI. Agent Gateway utilizza il modello di dati del registro come framework di governance per applicare il controllo dell'accesso in uscita. Le concessioni di ruoli IAM per gli agenti chiamanti dell'entità vengono controllate in base al criterio associato alla risorsa del registro.
In questa sezione, registrerai il server MCP e il relativo schema degli strumenti (toolspec.json) in Agent Registry. Per supportare l'interazione di Gemini Enterprise con le API e i servizi Google tramite Agent Gateway, creerai anche un singolo servizio endpoint di registro (oauth2-googleapis) che specifica le interfacce API di Google utilizzate da Gemini Enterprise per lo scambio del codice di autorizzazione con i token.
Registra server MCP
Per consentire a Gemini Enterprise di rilevare gli strumenti disponibili sul server MCP, fornisci un file di specifiche degli strumenti (cfg/toolspec.json) durante la registrazione del servizio in Agent Registry.
Crea la specifica dello strumento 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
Crea il servizio server 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}"
Verificare il server MCP in Agent Registry
Verifica che il servizio sia elencato come server MCP registrato nella regione insieme al relativo URL dell'endpoint e agli strumenti disponibili:
# 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
)"
Output di esempio:
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
Visualizza la specifica di configurazione del servizio per vedere che registra le definizioni esatte degli strumenti, gli schemi di input e le annotazioni sul comportamento per ogni strumento:
# describe mcp server tool specs
gcloud agent-registry services describe ${MCP_NAME} \
--location=${REGION} \
--project=${PROJ_ID} \
--format="yaml(mcpServerSpec.content.tools)"
Registra l'endpoint OAuth
Per consentire al backend DataConnector di Gemini Enterprise (che funge da client OAuth nel flusso di autorizzazione) di inviare richieste POST al server di autorizzazione Google OAuth 2.0 (https://oauth2.googleapis.com/token) tramite Agent Gateway, l'endpoint del token deve essere registrato in Agent Registry in modo che IAP valuti destination.is_registered == true.
Crea servizio di endpoint
# 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
Verificare la registrazione dell'endpoint
# 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
)"
Output previsto:
DISPLAY_NAME ENDPOINT_ID URL
oauth2.googleapis.com agentregistry-00000000-0000-0000-0012-3456789abcde https://oauth2.googleapis.com
Policy di accesso IAM
Poiché la policy di accesso IAM definisce una policy di autorizzazione per qualsiasi servizio registrato richiesto dall'identità dell'agente core_assistant dell'app Gemini Enterprise, non sono necessari ulteriori binding delle policy IAM per lo scambio di token OAuth.
- conditions:
iap.googleapis.com:
expression: destination.is_registered == true
description: allow ge assistant to any registered service
effect: ALLOW
Con questo si conclude la sezione di Agent Registry. Passiamo ora alla sezione Gemini Enterprise.
8. Gemini Enterprise
In questa sezione, configura il provider di identità, la licenza di prova e le credenziali client OAuth 2.0 di Google Identity, crea un'app Gemini Enterprise (${GE_APP_ID}), associa l'uscita in uscita al tuo Agent Gateway (${AGW_URI}) e connetti il server MCP sprockets registrato come datastore MCP personalizzato OAuth 2.0.
Crea l'app Gemini Enterprise
Il seguente metodo utilizza l'API discoveryengine.googleapis.com per creare le risorse e la configurazione dell'app Gemini Enterprise. Per la configurazione tramite la UI della console Google Cloud, consulta Creare un'app per istruzioni.
# 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
Verificare la creazione dell'app
# fetch engine (ge app) id
export GE_APP_ID=$(curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines" \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" -H "X-Goog-User-Project: ${PROJ_ID}" \
| jq -r --arg name "${GE_APP_DISPLAY_NAME}" '.engines[] | select(.displayName==$name) | .name | split("/") | last')
echo "engine (ge app) id: ${GE_APP_ID}"
Visualizza i dettagli del motore per vedere la configurazione creata:
# 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}"
Abilita il provider di identità
Abilita Google Identity come provider di identità per l'autenticazione degli utenti finali nella tua app Gemini Enterprise.
Il seguente metodo utilizza l'API discoveryengine.googleapis.com per configurare il provider di identità dell'app Gemini Enterprise. Per la configurazione tramite la UI della console Google Cloud, consulta Configurare il provider di identità per istruzioni.
# 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
Verificare il provider di 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}"
L'output "idpType": "GSUITE" corrisponde al provider Google Identity.
(Facoltativo) Abilita la licenza di prova di Gemini Enterprise
Se utilizzi un progetto a cui sono assegnate licenze Gemini Enterprise, puoi saltare questo passaggio. Se utilizzi un nuovo progetto senza licenza, continua e segui questi passaggi.
Crea una risorsa di configurazione della licenza per assegnare posti utente Gemini Enterprise per 30 giorni. In questo modo, la licenza predefinita verrà impostata sulla nuova prova, quindi a ogni utente che accede verrà automaticamente concesso un posto:
# 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
Verificare che la licenza sia stata applicata
# 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}"
Controlla la presenza di "subscriptionTerm": "SUBSCRIPTION_TERM_ONE_MONTH" e "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}"
Controlla la presenza di ../free_trial_gemini" e "enableLicenseAutoRegister": true.
Configurare il consenso e le credenziali OAuth 2.0
Per consentire a Gemini Enterprise (il client OAuth 2.0) di ottenere un token di autenticazione Google OAuth 2.0 delegato dall'utente e presentarlo al mcp-sprocketsserver delle risorse per tuo conto, configura la schermata di consenso OAuth della piattaforma Google Auth e crea un ID client OAuth 2.0 per l'applicazione web nel tuo progetto.
1. Configurare la schermata per il consenso OAuth
Stampa l'URL diretto della console Google Cloud per la panoramica della piattaforma Google Auth nel tuo progetto:
# print google auth platform consent screen url
echo "https://console.cloud.google.com/auth/overview?project=${PROJ_ID}"
- Apri l'URL nel browser e fai clic su Inizia (se non è già configurato per il tuo progetto).
- Nella sezione Informazioni sull'app, imposta Nome app su
mcp-sprockets-oauthe seleziona il tuo indirizzo email (${USER_IDENTITY}) come Email per assistenza utenti, quindi fai clic su Avanti. - In Pubblico, seleziona Interno (opzione consigliata se il tuo account appartiene a un'organizzazione Google Workspace) o Esterno (se utilizzi un account personale; se selezioni Esterno, aggiungi
${USER_IDENTITY}in **Utenti di test del pubblico**), poi fai clic su Avanti. - Inserisci il tuo indirizzo email nella sezione Dati di contatto, accetta il contratto relativo alle norme e fai clic su Crea.
2. Creare l'ID client OAuth 2.0 per l'applicazione web
Stampa l'URL diretto della console Google Cloud per la pagina Client:
# print google auth platform clients url
echo "https://console.cloud.google.com/auth/clients?project=${PROJ_ID}"
- Apri l'URL e fai clic su + Crea client.
- Seleziona Applicazione web come Tipo di applicazione e imposta Nome su
ge-mcp-sprockets-client. - Seleziona la casella di controllo Questo client verrà utilizzato da un agente basato sull'AI per designare il client OAuth per i flussi di lavoro degli agenti AI che agiscono per conto degli utenti.
- In URI di reindirizzamento autorizzati, fai clic su + Aggiungi URI e aggiungi l'URI di callback OAuth di Gemini Enterprise:
https://vertexaisearch.cloud.google.com/oauth-redirect
- Fai clic su Crea, copia l'ID client e il client secret generati ed esportali nella sessione della shell:
Imposta l'ID client OAuth 2.0 e il client secret generati nel passaggio precedente:
# 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"
Controlla che l'ID client sia impostato:
# print oauth 2.0 client id
echo "oauth client id: ${OAUTH_CLIENT_ID}"
Associazione ad Agent Gateway
L'instradamento del traffico in uscita da Gemini Enterprise tramite Agent Gateway stabilisce un limite di applicazione centralizzato e di routing IP statico per tutte le chiamate dello strumento dell'agente AI:
- Applicazione centralizzata delle policy:Agent Gateway funge da proxy inline che valuta le richieste di strumenti in uscita in base alle policy di autorizzazione prima che il traffico esca dall'ambiente dell'agente.
- Egress VPC e Cloud NAT deterministico:il binding di Gemini Enterprise a un Agent Gateway configurato con
vpcEgress: ALL_TRAFFICgarantisce che le chiamate di strumenti vengano instradate tramite il collegamento di rete PSC ed escono utilizzando l'IP statico Cloud NAT riservato. - Auditabilità unificata: fornisce audit trail e logging delle richieste centralizzati su tutti i server MCP connessi.
Applica una patch al motore agentGatewaySetting per abilitare:
# 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
Verificare il binding di Agent Gateway
Recupera la configurazione dell'app per confermare l'associazione 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}'
Output di esempio:
{
"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"
}
}
}
Crea un datastore del server MCP personalizzato
In questa sezione connetterai il server mcp-sprockets a Gemini Enterprise creando un datastore MCP personalizzato OAuth 2.0 configurato con Google Identity (https://accounts.google.com/o/oauth2/v2/auth e https://oauth2.googleapis.com/token).
Utilizzando l'API Discovery Engine, si tratta di una procedura in due passaggi:
- Crea (
:setUpDataConnector): crea una risorsaCollectiondedicata (${MCP_NAME}-collection-%timestamp), collegaDataConnector(custom_mcp) conauth_type: "OAUTH"e esegue il provisioning del relativoDataStore(..._mcp_data). - Attiva (
PATCH .../dataConnector?updateMask=actionConfig): attiva il runtime dell'azione del connettore (actionState: "ACTIVE") utilizzando la specifica dello strumento di Agent Registry, i parametri Google Identity OAuth 2.0 e associaDataStore(dataStoreIds) a Gemini EnterpriseEngine.
# 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}"
Crea connettore dati
# 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
Verificare la creazione del connettore dati
# 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}"
Controlla che il campo "registry_mcp_server_name" venga compilato con l'UUID di Agent Registry per il server MCP e che "auth_type" sia 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}'
Visualizza la voce del registro del server MCP nella UI della 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}"
Attivare il connettore dati
# 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
Verifica i collegamenti del server MCP personalizzato
# 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}'
Controlla il datastore collegato "dataStoreIds": ["mcp-sprockets-collection-[EPOCH]_mcp_data"].
# show collection details
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections" \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
-H "X-Goog-User-Project: ${PROJ_ID}" \
| jq --arg app "${GE_APP_ID}" '.collections[] | select(.dataConnector.actionConfig.actionParams.agent_gateway_engine // "" | endswith($app)) | .dataConnector | {name: .name, state: .state, actionState: .actionState, connectorModes: .connectorModes, auth_type: .actionConfig.actionParams.auth_type}'
Controlla la presenza di "state": "ACTIVE" e "auth_type": "OAUTH".
Azioni dello strumento
Quando esamini il datastore mcp-sprockets-collection nella dashboard di Gemini Enterprise, noterai che la scheda Azioni non viene utilizzata e il pulsante ↻ Ricarica azioni personalizzate è disattivato. Questo è un comportamento previsto.
Visualizza la pagina dei dettagli del datastore nell'interfaccia utente della 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}"
A seconda di come connetti un server MCP personalizzato a Gemini Enterprise, il rilevamento e la governance degli strumenti vengono gestiti in uno dei due modi seguenti:
- Workflow MCP personalizzato diretto (
BYO_MCP): quando configuri un server MCP personalizzato direttamente in Gemini Enterprise senza Agent Registry, l'archivio dati stesso gestisce il catalogo degli strumenti (connectorModes: ["FEDERATED", "ACTIONS"]). Devi aprire la scheda Azioni, fare clic su ↻ Ricarica azioni personalizzate per recuperare lo schematools/liste attivare o disattivare manualmente i singoli strumenti (addesubtract) nell'interfaccia utente. - Importazione del registro degli agenti (
REGISTRY_MCPflusso di lavoro utilizzato in questo codelab): quando importi un server MCP da Agent Registry, Agent Registry funge da fonte autorevole di verità per l'endpoint MCP, i relativi metadati dell'interfaccia e il catalogo degli strumenti (connectorModes: ["FEDERATED"]). Gemini Enterprise attiva automaticamente gli strumenti MCP registrati in fase di runtime tramite l'impostazione del motore Agent Gateway senza richiedere di ricaricare o attivare/disattivare manualmente le azioni nell'interfaccia utente del datastore.
Con questo si conclude la parte relativa a Gemini Enterprise. Passiamo ora alla sezione Convalida.
9. Convalida
In questa sezione, completi il flusso di consenso dell'utente OAuth 2.0 di Google una tantum, richiami gli strumenti MCP sul server mcp-sprockets esterno da Gemini Enterprise e verifichi che il server MCP esterno abbia convalidato sia l'IP statico Cloud NAT riservato (egress_source_ip) sia l'identità Google OAuth 2.0 (authenticated_user).
Accesso utente
Crea l'URL per l'app 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}"
Completa il consenso OAuth
Prima di eseguire query sull'agente, devi completare un flusso di consenso OAuth 2.0 una tantum che concede a Gemini Enterprise l'autorizzazione per ottenere un token di accesso per la tua identità Google (${USER_IDENTITY}). In questo modo, Gemini Enterprise può autenticare le chiamate di strumenti in uscita tramite Agent Gateway, in modo che il server mcp-sprockets esterno possa verificare la tua identità a ogni richiesta.
- Apri
${GE_APP_USER_URL}nel browser e fai clic su Inizia. - Nella casella di chat, fai clic sull'icona Connettori (l'icona a forma di pezzo di puzzle) e poi su Autorizza accanto a
mcp-sprockets-collection. - Si apre una nuova finestra che ti chiede di Scegliere un account per continuare su
mcp-sprockets-oauth(il nome dell'app della schermata per il consenso OAuth che hai configurato). Seleziona il tuo account utente (${USER_IDENTITY}). - Nella schermata per il consenso OAuth di Google, esamina le autorizzazioni richieste che consentono a Google (il fornitore di identità) di condividere la tua identità utente (
openid,email,profile) conmcp-sprockets-oauth, poi fai clic su Continua. - Fai di nuovo clic sull'icona Connettori e verifica che il pulsante di attivazione/disattivazione per
mcp-sprockets-collectionsia attivo, a conferma che l'autorizzazione è andata a buon fine.
Testare le query dell'agente
Test dell'interfaccia utente della chat dell'assistente
Invia la seguente query di test nella chat:
look up sprocket SPK-105 and confirm the model, material, unit_price, authenticated_user, and egress_source_ip
Prova una seconda query nella chat:
list all sprockets in the inventory catalog and report the authenticated_user and egress_source_ip
Verifica che l'assistente restituisca le risposte corrette e mostri un badge di citazione dell'azione interattivo.
Ad esempio, "Sprocket Lookup SPK-105 (5s)Agent Gateway" sotto ogni risposta conferma che lo strumento è stato eseguito.
Verifica che l'assistente restituisca le specifiche del pignone insieme a "authenticated_user" corrispondenti ${USER_IDENTITY} e "egress_source_ip" corrispondenti alla tua prenotazione ${NAT_EXT_IP}.
Test dell'API Assistant streamAssist
Una volta che il tuo account utente ha autorizzato il connettore OAuth 2.0, puoi anche richiamare l'API default_assistant:streamAssist direttamente dalla CLI e verificare che il server mcp-sprockets esterno restituisca sia l'IP statico Cloud NAT (${NAT_EXT_IP}) sia la tua identità Google OAuth 2.0 verificata (${USER_IDENTITY}):
Invia la seguente query di test:
# 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
Output di esempio:
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
Prova con un'altra query:
# 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
Controlla i log in Cloud Logging
Verifica che Gemini Enterprise abbia instradato le chiamate agli strumenti tramite Agent Gateway, il collegamento di rete PSC e Cloud NAT esaminando i log in Cloud Logging.
Verifica i log di Agent Gateway
Verifica che Agent Gateway abbia intercettato la richiesta, risolto la destinazione in Agent Registry, valutato la policy di autorizzazione e inoltrato la chiamata allo strumento:
# 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
)"
Output di esempio:
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
Verifica che l'output contenga:
STATUS:200(esecuzione riuscita) e202(handshakenotifications/initialized).SERVER_IP: IP e porta del server MCP esterno (${MCP_EXT_IP}:443).MCP_METHODeTOOL: la sequenza del protocollo MCP (initialize,notifications/initialized,tools/listetools/callconget_sprocket_by_id).AUTHZ:ALLOWED(uscita autorizzata da IAP).REGISTRY_MCP: ID risorsa dell'Agent Registry risolto (agentregistry-...).
Verifica i log di Cloud NAT
Verifica che Cloud NAT abbia convertito la connessione in uscita dall'IP di collegamento alla rete PSC di Agent Gateway (10.10.10.2) al tuo indirizzo IPv4 esterno statico riservato (${NAT_EXT_IP}) durante la connessione a ${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
)"
Output di esempio:
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
Verifica i log del firewall
Verifica che la policy del firewall interno (fw-policy-${SLUG}-internal) consenta il traffico in uscita da Agent Gateway alla destinazione 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
)"
Verifica che la policy del firewall esterna (fw-policy-${SLUG}-external) abbia consentito il traffico in entrata al server MCP dall'indirizzo IP NAT pubblico della rete interna:
# 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
)"
Con questo si conclude la parte relativa alla convalida. Passiamo ora alla sezione Pulizia.
10. Esegui la pulizia
Segui questi passaggi per eliminare le risorse e le configurazioni create in questo lab.
Rimuovere i componenti di 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"}}'
Per rimuovere le credenziali client OAuth 2.0 (ge-mcp-sprockets-client), apri la pagina Client della piattaforma Google Auth e fai clic sull'icona Elimina (cestino) accanto a ge-mcp-sprockets-client:
# print google auth platform clients url
echo "https://console.cloud.google.com/auth/clients?project=${PROJ_ID}"
Rimuovi il server MCP e i componenti di 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}
Rimuovere i componenti di 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}
Rimuovere i componenti del firewall
# 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
Rimuovere i componenti di rete
# 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
Rimuovi gli override delle policy dell'organizzazione e i file locali
# 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
Il lavoro di pulizia è terminato. Passiamo alla conclusione.
11. Conclusione
Complimenti! Hai creato un'architettura end-to-end che consente a un'app Gemini Enterprise di rilevare e richiamare in modo sicuro strumenti su un server MCP personalizzato protetto da OAuth 2.0 e con IP consentiti esterni:
- Egress VPC IP statico (
ALL_TRAFFICe Cloud NAT): tutto il traffico in uscita di Agent Gateway è stato instradato tramite un collegamento di rete PSC (10.10.10.2) e le richieste destinate a internet sono state convertite in un indirizzo IPv4 esterno statico riservato (${NAT_EXT_IP}) utilizzando Cloud NAT. - Server di risorse MCP OAuth 2.0 e Agent Registry:è stato implementato un server HTTP FastMCP esterno trasmissibile in streaming (
mcp-sprockets) protetto da un elenco consentito firewall IP di origine rigoroso (${NAT_EXT_IP}/32) e dalla verifica Google OAuth 2.0tokeninfoed è stato registrato il relativo schema di endpoint e strumenti (get_sprocketseget_sprocket_by_id) in Agent Registry. - Integrazione e governance di Gemini Enterprise OAuth 2.0:è stata eseguita il provisioning di un'app Gemini Enterprise, è stato associato il traffico degli strumenti in uscita a Agent Gateway, è stato collegato il server MCP registrato come connettore dati OAuth 2.0
REGISTRY_MCPed è stata verificata siaegress_source_ipsiaauthenticated_userinsieme alla telemetria di Cloud Logging.

Cosmopup pensa che i codelab siano fantastici!
Quali sono i passaggi successivi?
- Consulta la documentazione di Gemini Enterprise Agent Platform per funzionalità avanzate e tutorial.
- Configura le misure di protezione di Model Armor su Agent Gateway per una maggiore sicurezza dell'AI.
- Esplora le policy di governance semantica per applicare le regole aziendali e la conformità alle query in linguaggio naturale.
Non esitare a inviare commenti, domande o correzioni utilizzando questo modulo di feedback.
Grazie.