1. Introdução
Este codelab mostra a conectividade de saída de IP estático para o Gemini Enterprise usando o Gateway de Agente no modo agente-para-qualquer-lugar (saída). Você vai configurar um app Gemini Enterprise para invocar um servidor do Protocolo de Contexto de Modelo (MCP) personalizado, protegido por uma lista de permissão de IP de origem estrita e autenticação OAuth 2.0, roteando todo o tráfego de saída pelo Gateway de Agente usando uma configuração de modelo de conectividade. Um anexo de rede do Private Service Connect (PSC) conecta o Gateway de Agente à rede VPC, e o Cloud NAT fornece um endereço IP externo estável para o tráfego de saída da Internet.
Por padrão, as conexões de saída do Gemini Enterprise para endpoints da Internet pública se originam de pools de endereços IP dinâmicos e compartilhados do Google, que não podem ser fixados em uma única regra de lista de permissões de IP de propriedade do cliente. Ao parear o Gateway de Agente com um AgentConnectivityTemplate no modo ALL_TRAFFIC, todo o tráfego de saída do agente é roteado para a rede VPC, em que o Cloud NAT traduz as conexões vinculadas à Internet para um endereço IPv4 externo estático reservado sob seu controle, preservando a governança centralizada da ferramenta MCP pelo Agent Registry e o Identity-Aware Proxy (IAP).
O que você vai criar
- Modelo de conectividade do agente (
vpcEgress: ALL_TRAFFIC) e Gateway de Agente operando no modo de saída (agent-to-anywhere) com verificação de endpoint do Agent Registry - Rede VPC, anexo de rede PSC, Cloud Router e gateway do Cloud NAT vinculados a um endereço IPv4 externo estático reservado
- Servidor de recursos HTTP MCP externo com capacidade de streaming (
mcp-sprockets) protegido pelo Caddy TLS, restrito por regras de firewall estritamente ao IP estático do Cloud NAT e que verifica os tokens de acesso do OAuth 2.0 do Google delegados pelo usuário em relação ahttps://oauth2.googleapis.com/tokeninfo. - Tela de permissão do OAuth 2.0 da plataforma de autenticação do Google e credenciais do cliente OAuth 2.0 do aplicativo da Web (
accounts.google.comeoauth2.googleapis.com/token) - Entrada do catálogo de servidores MCP do Agent Registry e especificação da ferramenta (
toolspec.json) - Extensão de autorização do Identity-Aware Proxy (IAP) e política de autorização do gateway para o Gateway de Agente
- app Gemini Enterprise vinculado ao Gateway de Agente e conectado a um repositório de dados de servidor MCP personalizado OAuth 2.0 importado do Agent Registry
Fig. 1. Arquitetura do codelab
Conteúdo do laboratório
- Como configurar um
AgentConnectivityTemplatecomvpcEgress: ALL_TRAFFICpara rotear todo o tráfego de saída do Gateway de agente para uma rede VPC - Como reservar um endereço IPv4 externo estático e vinculá-lo ao Cloud NAT em uma sub-rede de anexo de rede do PSC
- Como implantar um servidor de recursos MCP HTTP transmissível externo que verifica tokens do portador do OAuth 2.0 do Google (
oauth2.googleapis.com/tokeninfo) e restringe o firewall de entrada estritamente ao IP estático do Cloud NAT (${NAT_EXT_IP}/32) - Como configurar credenciais de cliente do OAuth 2.0 do Google Identity e registrar um servidor MCP e o esquema de ferramentas dele no Agent Registry
- Como conectar um servidor MCP OAuth 2.0 registrado ao Gemini Enterprise e rotear chamadas de ferramentas delegadas pelo usuário pelo Gateway de Agente
- Como validar a tradução de IP estático, a verificação de identidade OAuth 2.0 do usuário final (
authenticated_user) e a aplicação da política de gateway usando comandos da CLI e o Cloud Logging
O que é necessário
- Tenha um projeto do Google Cloud com o faturamento ativado.
- Uma licença ativa do Gemini Enterprise ou um teste de 30 dias
- Permissões do IAM para provisionar serviços de rede, políticas da organização, recursos do Gemini Enterprise e da Agent Platform
- Um shell compatível com POSIX (
bashouzsh) com a CLI do Google Cloud (gcloud),curlejqinstalados
Isso conclui a parte de introdução. Em seguida, vamos para a seção Conceitos.
2. Conceitos
Sequência de implantação
Este codelab implanta primeiro a infraestrutura de rede e governança para que os caminhos de saída de IP estático e os controles de gateway estejam operacionais antes de registrar e conectar as ferramentas do MCP ao Gemini Enterprise:
- Infraestrutura de rede:reserve endereços IPv4 externos estáticos e provisione a VPC de saída, a sub-rede de vinculação do PSC, a vinculação de rede do PSC, o Cloud Router, o gateway do Cloud NAT e as regras de firewall de rede MCP externa.
- Modelo de conectividade do agente e Gateway de Agente:implante o
AgentConnectivityTemplate(vpcEgress: ALL_TRAFFIC) e oAgentGatewayregional no modo de saída (AGENT_TO_ANYWHERE) com a integração do Agent Registry (registries). - Políticas de autorização:configure a extensão de autorização do IAP (
AuthzExtension), a política de autorização do gateway (AuthzPolicy) e a política de acesso unificado do IAM v3 (AccessPolicyePolicyBinding). - Implante e registre o servidor MCP:implante o servidor de recursos OAuth 2.0
mcp-sprocketsexterno por trás do Caddy TLS, verifique a aplicação do OAuth 2.0 do Googletokeninfo, bloqueie o firewall de entrada estritamente para o IP estático do Cloud NAT (${NAT_EXT_IP}/32) e registre as especificações de serviço e ferramenta (get_sprocketseget_sprocket_by_id) no Agent Registry. - App Gemini Enterprise e cliente OAuth 2.0:configure o provedor de identidade do Google, a licença de teste e a tela de permissão do OAuth 2.0 e as credenciais do cliente do aplicativo da Web (
OAUTH_CLIENT_IDeOAUTH_CLIENT_SECRET), crie o app Gemini Enterprise (Engine) e vincule a saída de saída ao Agent Gateway (agentGatewaySetting). - Importar conector de dados MCP personalizado:crie e ative o conector de dados
REGISTRY_MCP(:setUpDataConnector) configurado comauth_type: "OAUTH"para vincular o repositório de dados de suporte do servidor MCP registrado ao app Gemini Enterprise. - Validar:conclua o fluxo de consentimento único do usuário do OAuth 2.0, invoque as ferramentas do MCP pelo assistente do Gemini Enterprise (confirmando
egress_source_ipeauthenticated_user) e verifique a aplicação da política e a tradução NAT de IP estático no Cloud Logging.
Arquitetura central de IdP + servidor de recursos MCP protegido por OAuth
Em implantações empresariais, o gerenciamento de identidade e a execução de ferramentas seguem a separação padrão de funções do OAuth 2.0 entre um provedor de identidade centralizado (servidor de autorização) e um servidor de recursos MCP protegido:
Função do OAuth 2.0 | Componente neste codelab | Responsabilidade |
Proprietário do recurso | Usuário final ( | Faz login no web app Gemini Enterprise e concede consentimento durante o fluxo de autorização única do OAuth 2.0 de três partes. |
Cliente OAuth 2.0 | Conector de dados do | Contém |
Servidor de autorização | OAuth 2.0 do Google Identity ( | Autentica o usuário durante o redirecionamento de consentimento do navegador e emite os tokens de acesso e atualização do OAuth 2.0 para o Gemini Enterprise. |
Servidor de recursos | Servidor | Impõe a identidade de rede da camada 3 usando o firewall da VPC ( |
Como o redirecionamento de consentimento do navegador (accounts.google.com) e a troca de token de back-channel (oauth2.googleapis.com/token) ocorrem em relação aos endpoints OAuth 2.0 gerenciados pelo Google, o firewall do servidor MCP externo só recebe solicitações JSON-RPC do MCP de tempo de execução (POST /mcp) do Gateway de Agente pelo Cloud NAT, permitindo que o firewall de entrada seja bloqueado estritamente para ${NAT_EXT_IP}/32.
Modelo de recurso do Discovery Engine
Um app do Gemini Enterprise (representado como um recurso Engine na API Discovery Engine) é a camada central de orquestração e a interface de conversa para usuários finais. Ele gerencia sessões de chat do usuário, fundamenta modelos generativos em dados corporativos e coordena a execução dinâmica de ferramentas.
Os apps do Gemini Enterprise interagem com dados e sistemas usando repositórios de dados:
- Repositórios de dados de conhecimento:ingerir e indexar conteúdo estático (por exemplo, Cloud Storage, Google Drive, BigQuery) para geração aumentada por recuperação (RAG).
- Conectores de dados (provedores de ações): conecte-se a APIs dinâmicas de terceiros ou personalizadas. Um repositório de dados de servidor MCP personalizado expõe ferramentas definidas pelo Protocolo de Contexto de Modelo (MCP), permitindo que o modelo chame funções externas de forma dinâmica durante uma conversa.
Saída do Gemini Enterprise
O Gemini Enterprise encaminha solicitações de ferramentas do servidor MCP personalizado para o Gateway de Agente quando agentGatewaySetting no Engine e use_agent_gateway_egress: true no DataConnector estão configurados.
Fig. 2. Arquitetura de saída do Gemini Enterprise
O app Gemini Enterprise organiza o roteamento de ferramentas em quatro áreas principais:
- Widget (
default_search_widget_config):- Serve a interface do cliente da Web. O widget recebe comandos do usuário, aciona o redirecionamento único de consentimento do usuário do OAuth 2.0 quando uma ferramenta exige autorização e inicia sessões de chat com o mecanismo subjacente.
- Assistente principal (
assistants/default_assistant/agents/default/core_assistant):- O agente de raciocínio conversacional raiz no mecanismo. Ao avaliar uma consulta do usuário, o Core Assistant inspeciona as ferramentas disponíveis e delega a execução ao subagente do Gateway de Agente sintetizado.
- Data Store e conector de dados:
DataStore:provisionado em umCollectiondedicado quando:setUpDataConnectoré executado, ele vincula (dataStoreIds) os esquemas de ferramentas importados do Agent Registry (get_sprockets,get_sprocket_by_id), os tipos de argumentos e as instruções do agente aoEnginedo Gemini Enterprise.DataConnector:gerencia a conexão de açãoREGISTRY_MCP(createBapConnection: true) com o servidor MCP remoto (instance_uri), resolve o recurso do servidor MCP do registro do agente (registry_mcp_server_name), anexa o token de portador do OAuth 2.0 armazenado em vault do usuário (Authorization: Bearer [access_token]) e ativa a saída do gateway do agente (use_agent_gateway_egress: true).
- Identidade do agente, Agent Registry e Gateway de Agente:
- Quando o conector de dados envia a chamada de ferramenta de saída, ele roteia o tráfego para o gateway especificado em
agentGatewaySetting. O Núcleo Assistant gera um token de identidade SPIFFE que declara a identidade da carga de trabalho:principal://agents.global.org-.../agents/default/core_assistant. - O Gateway de Agente se integra ao Agent Registry usando o campo
registriespara resolver dinamicamente endpoints de destino e esquemas de ferramentas registradas, avalia políticas de autorização usando o IAP e encaminha solicitações permitidas (preservando o cabeçalhoAuthorization: Bearerdo usuário) para a rede VPC usandoAgentConnectivityTemplate.
- Quando o conector de dados envia a chamada de ferramenta de saída, ele roteia o tráfego para o gateway especificado em
Conectividade VPC do gateway e NAT de IP estático
O Gateway de Agente oferece suporte à conectividade de rede VPC usando um recurso AgentConnectivityTemplate referenciado por agentConnectivityTemplate no gateway. O modelo egressNetworkConfig define como o tráfego entra na sua VPC por um anexo de rede do PSC:
PRIVATE_RANGES_ONLY(padrão): roteia apenas intervalos de IP privados RFC 1918, RFC 6598 e classe E pelo anexo de rede do PSC. O tráfego vinculado à Internet ignora a VPC e sai diretamente pelo egress padrão da Internet do Google.ALL_TRAFFIC(usado neste codelab): roteia todo o tráfego de saída do Gateway de Agente, incluindo a Internet pública e endpoints MCP de parceiros externos, para sua sub-rede VPC pelo anexo de rede do PSC (10.10.10.2).
Ao operar no modo ALL_TRAFFIC, a sub-rede de vinculação do PSC exige duas configurações:
- Acesso privado do Google (
--enable-private-ip-google-access): garante que as chamadas internas para APIs do Google Cloud (*.googleapis.com) continuem sendo roteadas de forma privada na rede do Google. - Cloud Router e Cloud NAT (
MANUAL_ONLY): o tráfego vinculado à Internet que entra na sub-rede de anexação do PSC segue a rota padrão (0.0.0.0/0) pelo Cloud NAT, que realiza a conversão de endereços de rede de origem (SNAT) para seu endereço IPv4 externo estático reservado (${NAT_EXT_IP}). Portanto, os firewalls externos podem restringir o acesso de entrada estritamente a${NAT_EXT_IP}/32.
Limitações e requisitos
- Somente StreamableHTTP:o transporte legado de eventos enviados pelo servidor (SSE) não é compatível. Os servidores MCP precisam usar StreamableHTTP.
- Substituição da política da organização:você precisa substituir explicitamente a política da organização para repositórios de dados do MCP personalizado antes de registrar o conector de dados.
- Alinhamento regional:o Gemini Enterprise impõe o alinhamento regional entre o local do app, o Gateway de Agente e o Agent Registry:
Local do app Gemini Enterprise | Localização do gateway de agente e do NAT | Local do Agent Registry |
|
|
|
|
|
|
|
|
|
Isso conclui a parte de conceitos. Em seguida, vamos para a seção Configuração.
3. Configuração
Papéis do IAM obrigatórios
As seguintes funções são necessárias para concluir este codelab:
Domínio | Papéis do IAM obrigatórios |
Projeto e IAM |
|
Rede e gateway |
|
Gemini Enterprise e Registry |
|
Cargas de trabalho |
|
Observabilidade |
|
Ou use um papel básico amplo, como roles/owner, combinado com roles/orgpolicy.policyAdmin, já que roles/owner sozinho não pode modificar as políticas da organização.
Acessar seu projeto
Este codelab usa um único projeto na nuvem do Google Cloud. As etapas de configuração usam a CLI gcloud e comandos do shell do Linux.
Comece acessando a linha de comando do seu projeto na nuvem do Google Cloud:
- Cloud Shell em
shell.cloud.google.comou - Um terminal local com a CLI
gcloudinstalada
Definir o ID do projeto
# set target project id
gcloud config set project SET_YOUR_PROJECT_ID_HERE
Autenticar sessão
# login to gcloud cli
gcloud auth login
# login for gcloud api
gcloud auth application-default login
Definir variáveis de ambiente 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}
Definir domínios de confiança da identidade do agente
A instrução if-then-else verifica se o projeto pertence a uma organização para definir o domínio de confiança correto para as identidades do agente principal.
# set var for trust domain
if [[ -n "${ORG_ID}" ]]; then
export TRUST_DOMAIN="agents.global.org-${ORG_ID}.system.id.goog"
else
export TRUST_DOMAIN="agents.global.proj-${PROJ_NO}.system.id.goog"
fi
echo "trust domain: ${TRUST_DOMAIN}"
Definir o projeto de faturamento e cota
# 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}
Criar diretório local para arquivos de configuração
# create config folder
mkdir -p cfg
Atualize o gcloud cli (recomendado)
Se você estiver executando uma instalação autogerenciada do SDK Google Cloud (ou seja, fora do Cloud Shell), atualize os componentes para a versão mais recente.
# update gcloud cli
gcloud components update
Ativar serviços de 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
Políticas da organização
As restrições de política da organização gerenciadas padrão do Google Cloud e as políticas de sandbox podem restringir os recursos usados neste codelab:
compute.vmExternalIpAccess: restringe endereços IPv4 externos em VMs do Compute Engine em organizações sandbox bloqueadas.discoveryengine.managed.disableCustomMcpServerConnector: restringe a criação de conectores de dados que usam um servidor MCP personalizado (custom_mcp) como fonte de dados (aplicado por padrão).discoveryengine.managed.allowedEgressFqdns: restringe os domínios de saída (FQDNsinstance_uri) para conectores de dados quando o VPC Service Controls (VPC-SC) está ativo ou o projeto está listado emenforcedProjects.discoveryengine.managed.allowedDataSources: restringe os tipos de conectores de dados permitidos (dataSource) quando o VPC-SC está ativo ou o projeto está listado emenforcedProjects.
Substitua as restrições de política da organização herdadas no nível do projeto.
Desativar restrição personalizada do MCP
# 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
Desativar restrições de conector de dados condicionais
# 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
Desativar a restrição de política de acesso
# 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
Permitir endereços IP externos
# 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
Verificar as políticas da organização
Verifique se compute.vmExternalIpAccess está definido como allowAll: True e se as outras políticas são 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
Verificar vinculações do agente de serviço (precaução)
Em um novo projeto, o Google Cloud provisiona automaticamente o agente de serviço do Gateway de Agente e concede a ele roles/agentgateway.serviceAgent quando o networkservices.googleapis.com é ativado pela primeira vez. Se você estiver reutilizando um projeto em que a limpeza anterior pode ter removido as vinculações padrão do agente de serviço, execute os comandos a seguir como uma proteção contra falhas para garantir que a identidade e a vinculação de função estejam intactas:
# ensure network services service account has been created
gcloud beta services identity create \
--service=networkservices.googleapis.com \
--project="${PROJ_ID}"
# ensure network services service account has service agent roles applied
gcloud projects add-iam-policy-binding "${PROJ_ID}" \
--member="serviceAccount:service-${PROJ_NO}@gcp-sa-agentgateway.iam.gserviceaccount.com" \
--role="roles/agentgateway.serviceAgent"
Isso conclui a parte de configuração. Em seguida, vamos para a seção Rede.
4. Rede
Nesta seção, você vai reservar os endereços IPv4 externos estáticos, criar a rede VPC de saída interna e a rede VPC externa isolada, provisionar o anexo de rede do PSC, configurar o Cloud NAT e criar regras de firewall.
Reservar endereços IP externos estáticos
Reserve dois endereços IPv4 externos estáticos regionais para o Cloud NAT e a VM do servidor MCP externo:
# 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}
Verificar endereços IP externos estáticos
O Gemini Enterprise exige que os endpoints MCP remotos usem HTTPS com um certificado TLS confiável publicamente. Em vez de registrar um domínio personalizado para este laboratório, você vai usar sslip.io, um serviço DNS curinga sem custo financeiro que resolve qualquer nome de host que contenha um endereço IP (como mcp.[IP].sslip.io) diretamente para esse IP. Como as autoridades de certificação, como Let's Encrypt, não emitem certificados para endereços IP simples, esse nome de host sslip.io oferece ao proxy reverso Caddy um nome de domínio válido para provisionar automaticamente um certificado TLS confiável para o servidor MCP.
Exporte os dois endereços IPv4 e crie o nome de domínio sslip.io e o URL do servidor MCP externo:
# 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}"
Exemplo de saída:
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
Criar rede interna
Quando o modelo de conectividade do Gateway de Agente é configurado para usar um egressNetworkConfig com um networkAttachment, a sub-rede que hospeda o anexo de rede do PSC precisa ser pelo menos um bloco CIDR /28 e ter o Acesso Privado do Google (--enable-private-ip-google-access) ativado.
Crie uma rede VPC global para saída do Gateway de Agente 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
Criar regras de firewall internas
Crie uma política de firewall para permitir todo o tráfego de saída com a geração de registros ativada. Isso será usado para monitorar o tráfego de saída do Gateway de Agente para a rede VPC interna. O Cloud NGFW é compatível com os níveis Essentials e Standard para segurança de rede e monitoramento de tráfego.
# 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
Criar anexo de rede do PSC
Crie um anexo de rede do Private Service Connect (PSC) configurado para aceitar automaticamente conexões do Gateway de Agente. O anexo de rede estabelece o lado da rede VPC do consumidor da conexão para vincular com segurança o lado do produtor do Gateway de Agente para o tráfego de saída. Para mais informações sobre requisitos de sub-rede e especificações de intervalo de IP, consulte Configurar a conectividade VPC.
# create psc network attachment
gcloud compute network-attachments create psc-na-${REGION}-agw \
--region=${REGION} \
--subnets=subnet-${REGION}-agw \
--connection-preference=ACCEPT_AUTOMATIC
Verificar o anexo de rede do PSC
# show psc network attachment details
gcloud compute network-attachments describe psc-na-${REGION}-agw --region=${REGION}
Recupere o URI do recurso do anexo de rede do PSC e armazene-o na variável de ambiente PSC_NA_URI. Esse URI será referenciado na configuração do Gateway de Agente (networkConfig.egress.networkAttachment) para provisionar a interface do PSC para saída de rede na rede 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}
Criar Cloud NAT
O Cloud NAT é usado para converter o endereço IP de origem do tráfego de saída do Gateway de Agente no endereço IP público reservado para roteamento pela Internet pública.
Somente as fontes da sub-rede de anexo de rede de saída do Gateway de Agente são definidas como qualificadas para usar o 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
Verificar o Cloud NAT
Verifique o status do Cloud NAT e se a origem natIP esperada está configurada:
# 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)"
Exemplo de saída:
name: nat-foo-us-central1
natIps:
- https://www.googleapis.com/compute/v1/projects/[PROJ_ID]/regions/us-central1/addresses/ip-foo-nat
Criar rede externa
Crie uma rede VPC separada e isolada para hospedar a VM do servidor MCP externo.
# 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
Criar regras de firewall externas
Crie duas regras de firewall de entrada na rede VPC externa:
2001: permite a porta TCP de entrada80para que o Let's Encrypt possa concluir o desafio de validação de domínio HTTP-01 do ACME para${MCP_DOMAIN}.2002: inicialmente permite a porta TCP de entrada443de0.0.0.0/0para verificar a prontidão do TLS e a aplicação do OAuth 2.0tokeninfodo shell local antes de restringir estritamente a${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
Isso conclui a parte da rede. Em seguida, vamos para a seção Gateway de Agente.
5. Gateway de Agente
Nesta seção, você vai implantar o modelo de conectividade do agente com vpcEgress: ALL_TRAFFIC, o Gateway de agente regional, delegar a autorização ao Identity-Aware Proxy (IAP) e definir regras de política de acesso unificado do IAM para governar solicitações de rede de saída.
Criar modelo de conectividade
A especificação do modelo de conectividade define:
egressNetworkConfig.networkAttachment:aponta para o anexo de rede do PSC, conectando o Gateway de Agente à sua rede VPC.egressNetworkConfig.vpcEgress:defina comoALL_TRAFFICpara que todas as conexões de saída do agente (incluindo endpoints MCP da Internet pública) sejam roteadas para a rede VPC e saiam usando a tradução de endereço IP de origem do Cloud NAT.
Crie e importe o arquivo de configuração do modelo de conectividade:
# 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}
Criar gateway de agente
A especificação do Gateway de Agente define:
agentConnectivityTemplate:aponta para o modelo de conectividade para que o gateway possa usar o anexo de rede do PSC para conectividade da VPC.registries:associa o gateway ao Agent Registry regional para resolver endpoints do MCP catalogados e esquemas de ferramentas.
Crie e importe o arquivo de configuração do gateway de agente:
# 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}
Verificar a implantação do gateway de agente
Confirme a configuração do Agent Registry e do modelo de conectividade:
# verify agent gateway deployment details
gcloud network-services agent-gateways describe ${AGW_NAME} \
--location=${REGION} \
--format="yaml(name,agentConnectivityTemplate,registries)"
Exemplo de saída:
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
Inspecione o anexo de rede do PSC para confirmar a conexão do gateway:
# show psc network attachment details
gcloud compute network-attachments describe psc-na-${REGION}-agw \
--region=${REGION} \
--format="yaml(connectionEndpoints)"
Exemplo de saída:
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
Delegar autorização
O Gateway de Agente protege e controla o tráfego de ferramentas de saída usando políticas de autorização (networksecurity.authzPolicies) integradas às políticas de acesso unificado (UAP) do Identity-Aware Proxy (IAP).
Embora o Gateway de Agente ofereça suporte a regras básicas de ALLOW e DENY inline, os ambientes corporativos exigem uma governança centralizada e focada na identidade. Com as políticas de acesso unificado do IAM (ou políticas de acesso), você gerencia regras de acesso de saída usando políticas de acesso padrão do IAM v3.
Figura 3. Arquitetura de autorização
O fluxo de autorização conecta três componentes:
- Política de autorização de gateway (
authzPolicy):- Um recurso regional que segmenta o Gateway de Agente.
- Configurado com
policyProfile: REQUEST_AUTHZeaction: CUSTOMpara encaminhar todas as verificações de autorização de saída para a extensão de autorização do IAP.
- Extensão do serviço IAP (
authzExtension):- Um recurso regional que delega a autorização de solicitação ao Identity-Aware Proxy (
iap.googleapis.com). - Avalia políticas no modo
ENFORCEusando a versãoV2da política.
- Um recurso regional que delega a autorização de solicitação ao Identity-Aware Proxy (
- Política e vinculação de acesso unificado do IAM (
accessPolicyepolicyBinding):- Recursos globais do IAM v3 que contêm regras de acesso refinado.
- Autentica a identidade principal SPIFFE do agente de chamada, verifica a permissão universal
iap.googleapis.com/resources.egressViaIAPe avalia as condições da Common Expression Language (CEL) em relação aos atributos de destino.
Implantar a extensão de autorização
# 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}
Verificar extensão de autorização
Verifique se a extensão de autorização está ativa:
# 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
)"
Implantar a política de autorização
Crie uma configuração de política de autorização network-security que tenha como destino o Gateway de Agente e delegue a verificação de solicitações à extensão de autorização do 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}
Verificar a política de autorização
Verifique se a política de autorização está ativa:
# 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
)"
Criar políticas de acesso do IAM
O Gateway de Agente agora delega as verificações de autorização ao IAP e resolve os metadados de destino do Agent Registry. Em seguida, defina uma regra de política de acesso unificado do IAM para controlar a execução de ferramentas de saída.
A IAP avalia expressões de atributos CEL em relação aos seguintes atributos de destino do Agent Registry:
- Status registrado (
destination.is_registered):- Booleano (
true/false) que indica se o destino está catalogado no Agent Registry.
- Booleano (
- Nome do servidor MCP (
destination.agent_registry.mcp_server.name):- Nome canônico do recurso do servidor MCP registrado no Agent Registry.
- Método de MCP (
destination.agent_registry.mcp_server.method):- O método do MCP que está sendo invocado (por exemplo,
tools/call,tools/list,initialize).
- O método do MCP que está sendo invocado (por exemplo,
- Nome da ferramenta (
destination.agent_registry.mcp_server.tool.name):- O nome da ferramenta específica invocada (por exemplo,
get_sprocket_by_idouget_sprockets), permitindo autorização refinada no nível da ferramenta em servidores MCP registrados.
- O nome da ferramenta específica invocada (por exemplo,
Definir regra de política de acesso do IAM
O manifesto da regra de política do IAM especifica:
- Principais:a identidade principal do SPIFFE que representa o agente assistente principal do Gemini Enterprise.
- Permissões:a permissão universal
iap.googleapis.com/resources.egressViaIAPnecessária para todo o tráfego de saída controlado pelo IAP. - Condições:uma expressão CEL (
destination.is_registered == true) que garante que o agente só possa invocar endpoints catalogados no Agent Registry.
Crie o arquivo de manifesto da regra de política:
# 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
Implantar política de acesso do IAM
Crie a política de acesso global do IAM usando as regras definidas no arquivo de manifesto:
# 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
Verificar a política de acesso do IAM
Verifique se a política de acesso do IAM foi criada corretamente e inspecione os detalhes da regra:
# show iam access policy details
gcloud iam access-policies describe uap-policy-${SLUG} \
--project=${PROJ_ID} \
--location=global
Exemplo de saída:
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
Vincular a política de acesso do IAM ao projeto
Para ativar a aplicação em todos os gateways de agente no seu projeto, crie uma vinculação de política que anexe a política de acesso do IAM ao recurso do projeto:
# 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
Verificar a vinculação da política de acesso do IAM
Verifique se a vinculação de política ativa aponta para a política e o destino corretos:
# show policy binding details
gcloud iam policy-bindings describe uap-bind-${SLUG} \
--project=${PROJ_ID} \
--location=global
Isso conclui a parte do Gateway de Agente. Em seguida, vamos para a seção do servidor MCP.
6. Servidor MCP
Nesta seção, você vai implantar um servidor de recursos OAuth 2.0 FastMCP (mcp-sprockets) externo que expõe as ferramentas get_sprockets e get_sprocket_by_id e verificar se ele valida criptograficamente os tokens de portador do OAuth 2.0 do Google em relação a https://oauth2.googleapis.com/tokeninfo. Em seguida, você vai bloquear a regra de firewall externa estritamente para o IP estático do Cloud NAT.
Implantar servidor MCP externo
Um script de inicialização instala o Caddy e o FastMCP, inicia o servidor mcp-sprockets em 127.0.0.1:8080 e configura o Caddy para veicular HTTPS em ${MCP_DOMAIN}.
Sempre que o Gemini Enterprise chamar uma ferramenta do MCP (por exemplo, get_sprockets e get_sprocket_by_id), o servidor vai:
- Lê o IP de origem do autor da chamada no cabeçalho
X-Forwarded-For(egress_source_ip). - Extraia o cabeçalho
Authorization: Bearer [access_token]e verifique o token no endpoint de verificação do OAuth 2.0 do Google (https://oauth2.googleapis.com/tokeninfo?access_token=[token]). - Retorne
"authenticated_user"([user_email]) junto com"egress_source_ip", provando que o servidor MCP externo verificou o IP estático do Cloud NAT e a identidade do usuário final do OAuth 2.0 do Google.
# 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"
Verificar a prontidão do servidor MCP e a validação do OAuth 2.0 tokeninfo
Aguarde alguns minutos para que o script de inicialização instale o FastMCP e o Caddy e provisione o certificado TLS do 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
Valide a resolução de DNS sslip.io, o certificado TLS Let's Encrypt veiculado pelo Caddy e a resposta tools/list do FastMCP:
# query mcp server for tools list
curl -v -X POST "${MCP_URL}" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}' \
2>&1 | grep -E "Connected to|subject:|issuer:|SSL certificate|HTTP/|event:|data:"
Exemplo de saída:
* 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}}]}}
Antes de bloquear o firewall externo, execute um teste tools/call transmitindo um token do portador do OAuth 2.0 do Google (gcloud auth print-access-token) para verificar se mcp-sprockets valida o token em relação a https://oauth2.googleapis.com/tokeninfo e retorna seu e-mail "authenticated_user" junto com o endereço IP de origem do autor da chamada:
# 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'
Exemplo de saída (mostrando seu IP direto do Cloud Shell antes do bloqueio do firewall e seu e-mail verificado do Google OAuth):
{
"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
}
}
Bloquear o firewall para o IP estático do Cloud NAT
Atualize a política de firewall da rede VPC externa para que a porta TCP 443 aceite tráfego apenas do IP externo estático do 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
Verifique se as regras da política de firewall externa estão em vigor:
# 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
)"
Verifique se as conexões diretas fora do IP estático do Cloud NAT estão bloqueadas:
# query mcp server
curl -i --connect-timeout 5 "${MCP_URL}" \
|| echo "Expected: Direct access blocked (not originating from ${NAT_EXT_IP})"
Exemplo de saída:
curl: (28) Connection timed out after 5001 milliseconds
Expected: Direct access blocked (not originating from 203.0.113.10)
Isso conclui a parte do servidor MCP. Em seguida, vamos para a seção Agent Registry.
7. Agent Registry
O Agent Registry é um inventário centralizado de todos os agentes, servidores MCP e endpoints (APIs) no ecossistema de IA. Ele também é um catálogo que pode ser usado para listar, pesquisar e descobrir outras ferramentas e serviços registrados para uso por aplicativos de IA. O Gateway de Agente usa o modelo de dados do registro como framework de governança para aplicar o controle de acesso de saída. As concessões de papéis do IAM para agentes de chamada principais são verificadas em relação à política vinculada ao recurso do registro.
Nesta seção, você vai registrar o servidor MCP e o esquema de ferramentas dele (toolspec.json) no Agent Registry. Para permitir que o Gemini Enterprise interaja com as APIs e os serviços do Google pelo Gateway de Agente, você também vai criar um único serviço de endpoint de registro (oauth2-googleapis) que especifica as interfaces de API do Google usadas pelo Gemini Enterprise para trocar o código de autorização por tokens.
Registrar servidor MCP
Para permitir que o Gemini Enterprise descubra as ferramentas disponíveis no servidor MCP, forneça um arquivo de especificações de ferramentas (cfg/toolspec.json) ao registrar o serviço no Agent Registry.
Criar especificação de ferramenta do 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
Criar serviço de servidor 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}"
Verificar o servidor MCP no Agent Registry
Verifique se o serviço está listado como um servidor MCP registrado na região, junto com o URL do endpoint e as ferramentas disponíveis:
# 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
)"
Exemplo de saída:
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
Confira a especificação de configurações de serviço para ver se ela registra as definições de ferramentas, os esquemas de entrada e as anotações de comportamento exatos para cada ferramenta:
# describe mcp server tool specs
gcloud agent-registry services describe ${MCP_NAME} \
--location=${REGION} \
--project=${PROJ_ID} \
--format="yaml(mcpServerSpec.content.tools)"
Registrar endpoint OAuth
Para permitir que o back-end do Gemini Enterprise DataConnector (que atua como o cliente OAuth no fluxo de autorização) envie solicitações POST ao servidor de autorização do OAuth 2.0 do Google (https://oauth2.googleapis.com/token) pelo Gateway de Agente, o endpoint de token precisa ser registrado no Agent Registry para que a IAP avalie destination.is_registered == true.
Criar serviço de 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
Verificar o registro do 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
)"
Resposta esperada:
DISPLAY_NAME ENDPOINT_ID URL
oauth2.googleapis.com agentregistry-00000000-0000-0000-0012-3456789abcde https://oauth2.googleapis.com
Política de acesso do IAM
Como a política de acesso do IAM define uma política de permissão para qualquer serviço registrado solicitado pela identidade do agente core_assistant do app Gemini Enterprise, não são necessárias vinculações de política do IAM adicionais para a troca de tokens do OAuth.
- conditions:
iap.googleapis.com:
expression: destination.is_registered == true
description: allow ge assistant to any registered service
effect: ALLOW
Isso conclui a parte do Agent Registry. Em seguida, vamos para a seção do Gemini Enterprise.
8. Gemini Enterprise
Nesta seção, você vai configurar o provedor de identidade, a licença de teste e as credenciais do cliente OAuth 2.0 do Google Identity, criar um app Gemini Enterprise (${GE_APP_ID}), vincular a saída de saída ao Gateway de Agente (${AGW_URI}) e conectar o servidor MCP do sprockets registrado como um repositório de dados MCP personalizado do OAuth 2.0.
Criar app Gemini Enterprise
O método a seguir usa a API discoveryengine.googleapis.com para criar os recursos e a configuração do app Gemini Enterprise. Para configurar usando a interface do console do Google Cloud, consulte Criar um app para instruções.
# 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
Verificar a criação do 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}"
Confira os detalhes do mecanismo para ver a configuração criada:
# 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}"
Ativar o provedor de identidade
Ative o Google Identity como provedor de identidade para autenticação de usuários finais no seu app Gemini Enterprise.
O método a seguir usa a API discoveryengine.googleapis.com para configurar o provedor de identidade do app Gemini Enterprise. Para configurar usando a interface do console do Google Cloud, consulte Configurar provedor de identidade para instruções.
# 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
Verificar provedor de identidade
# 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}"
A saída "idpType": "GSUITE" corresponde ao provedor de identidade do Google.
(Opcional) Ativar a licença de teste do Gemini Enterprise
Se você estiver usando um projeto com licenças do Gemini Enterprise atribuídas, pule esta etapa. Se você estiver usando um novo projeto sem uma licença, continue e siga estas etapas.
Crie um recurso de configuração de licença para dar direito a licenças de usuário do Gemini Enterprise por 30 dias. Isso vai definir a licença padrão para o novo teste. Assim, qualquer usuário que fizer login vai receber automaticamente uma vaga:
# 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
Verificar se a licença foi aplicada
# 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}"
Verifique se há "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}"
Verifique se há ../free_trial_gemini" e "enableLicenseAutoRegister": true.
Configurar credenciais e consentimento do OAuth 2.0
Para permitir que o Gemini Enterprise (o cliente OAuth 2.0) receba um token do portador do OAuth 2.0 do Google delegado pelo usuário e o apresente ao mcp-sprocketsservidor de recursos em seu nome, configure a tela de permissão do OAuth da plataforma de autenticação do Google e crie um ID do cliente OAuth 2.0 de aplicativo da Web no seu projeto.
1. Configurar a tela de permissão OAuth
Imprima o URL direto do console do Google Cloud para a Visão geral da plataforma de autenticação do Google no seu projeto:
# print google auth platform consent screen url
echo "https://console.cloud.google.com/auth/overview?project=${PROJ_ID}"
- Abra o URL no navegador e clique em Começar (se ainda não estiver configurado para seu projeto).
- Em Informações do app, defina Nome do app como
mcp-sprockets-oauthe selecione seu endereço de e-mail (${USER_IDENTITY}) como o E-mail de suporte ao usuário. Em seguida, clique em Próxima. - Em Público-alvo, selecione Interno (recomendado se sua conta pertencer a uma organização do Google Workspace) ou Externo (se você estiver usando uma conta pessoal. Se selecionar Externo, adicione
${USER_IDENTITY}em **Usuários de teste do público-alvo**). Em seguida, clique em Próxima. - Insira seu endereço de e-mail em Informações de contato, aceite o contrato de política e clique em Criar.
2. Criar o ID do cliente OAuth 2.0 do aplicativo da Web
Imprima o URL direto do console do Google Cloud para a página Clientes:
# print google auth platform clients url
echo "https://console.cloud.google.com/auth/clients?project=${PROJ_ID}"
- Abra o URL e clique em + Criar cliente.
- Selecione Aplicativo da Web como o Tipo de aplicativo e defina o Nome como
ge-mcp-sprockets-client. - Marque a caixa de seleção Este cliente será usado por um agente com tecnologia de IA para designar o cliente OAuth para fluxos de trabalho de agentes de IA que agem em nome dos usuários.
- Em URIs de redirecionamento autorizados, clique em + Adicionar URI e adicione o URI de retorno de chamada do OAuth do Gemini Enterprise:
https://vertexaisearch.cloud.google.com/oauth-redirect
- Clique em Criar, copie o ID do cliente e a chave secreta do cliente gerados e exporte-os na sua sessão do shell:
Defina o ID e a chave secreta do cliente OAuth 2.0 gerados na etapa anterior:
# 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"
Verifique se o ID do cliente está definido:
# print oauth 2.0 client id
echo "oauth client id: ${OAUTH_CLIENT_ID}"
Vincular ao Gateway de Agente
O roteamento do tráfego de saída do Gemini Enterprise pelo Agent Gateway estabelece um limite centralizado de aplicação e roteamento de IP estático para todas as invocações de ferramentas de agente de IA:
- Aplicação centralizada de políticas:o gateway de agentes atua como um proxy inline que avalia as solicitações de ferramentas de saída em relação às políticas de autorização antes que o tráfego saia do ambiente do agente.
- Saída determinística da VPC e do Cloud NAT:vincular o Gemini Enterprise a um gateway de agente configurado com
vpcEgress: ALL_TRAFFICgarante que as chamadas de ferramentas sejam roteadas pelo anexo de rede do PSC e saiam usando seu IP estático reservado do Cloud NAT. - Capacidade de auditoria unificada:fornece geração de registros de solicitações centralizada e trilhas de auditoria em todos os servidores MCP conectados.
Adicione um patch ao mecanismo agentGatewaySetting para ativar:
# 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
Verificar a vinculação do Gateway de Agente
Recupere a configuração do app para confirmar a vinculação 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}'
Exemplo de saída:
{
"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"
}
}
}
Criar um repositório de dados de servidor MCP personalizado
Nesta seção, você vai conectar o servidor mcp-sprockets ao Gemini Enterprise criando um repositório de dados personalizado do MCP OAuth 2.0 configurado com o Google Identity (https://accounts.google.com/o/oauth2/v2/auth e https://oauth2.googleapis.com/token).
Usando a API Discovery Engine, esse é um processo de duas etapas:
- Criar (
:setUpDataConnector): cria um recursoCollectiondedicado (${MCP_NAME}-collection-%timestamp), anexa oDataConnector(custom_mcp) comauth_type: "OAUTH"e provisiona oDataStore(..._mcp_data) de apoio. - Ativar (
PATCH .../dataConnector?updateMask=actionConfig): ativa o tempo de execução da ação do conector (actionState: "ACTIVE") usando a especificação da ferramenta do Agent Registry, os parâmetros do OAuth 2.0 do Google Identity e vincula oDataStore(dataStoreIds) ao seuEnginedo Gemini Enterprise.
# fetch mcp server agent registry resource name
export MCP_REGISTRY_URI=$(gcloud agent-registry mcp-servers list \
--location=${REGION} \
--project=${PROJ_ID} \
--filter="displayName:${MCP_DOMAIN}" \
--format="value(name)")
echo "mcp registry name: ${MCP_REGISTRY_URI}"
echo "mcp url: ${MCP_URL}"
Criar conector de dados
# 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
Verificar a criação do conector de dados
# 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}"
Verifique se o campo "registry_mcp_server_name" é preenchido com o UUID do Agent Registry para o servidor MCP e se "auth_type" é 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}'
Confira a entrada do registro do servidor MCP na interface do console do 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}"
Ativar conector de dados
# 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
Verificar vinculações personalizadas do servidor MCP
# show engine (ge app) details
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}" \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
-H "X-Goog-User-Project: ${PROJ_ID}" \
| jq '{name: .name, dataStoreIds: .dataStoreIds, agentGatewaySetting: .agentGatewaySetting}'
Verifique o repositório de dados vinculado "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}'
Verifique se há "state": "ACTIVE" e "auth_type": "OAUTH".
Ações da ferramenta
Ao inspecionar o repositório de dados mcp-sprockets-collection no painel do Gemini Enterprise, você vai notar que a guia Ações não é usada e o botão ↻ Recarregar ações personalizadas está desativado. Esse é o comportamento esperado.
Acesse a página de detalhes do repositório de dados na interface do console do 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}"
Dependendo de como você conecta um servidor MCP personalizado ao Gemini Enterprise, a descoberta e a governança de ferramentas são processadas de uma das duas maneiras:
- MCP personalizado direto (fluxo de trabalho
BYO_MCP): quando você configura um servidor MCP personalizado diretamente no Gemini Enterprise sem o Agent Registry, o repositório de dados gerencia o catálogo de ferramentas (connectorModes: ["FEDERATED", "ACTIONS"]). Abra a guia Ações, clique em ↻ Recarregar ações personalizadas para buscar o esquematools/liste ative ou desative manualmente as ferramentas individuais (addesubtract) na interface. - Importação do Agent Registry (fluxo de trabalho
REGISTRY_MCPusado neste codelab): quando você importa um servidor MCP do Agent Registry, o Agent Registry serve como a fonte de verdade autorizada para o endpoint do MCP, os metadados da interface e o catálogo de ferramentas (connectorModes: ["FEDERATED"]). O Gemini Enterprise ativa automaticamente as ferramentas do MCP registradas no tempo de execução usando a configuração Gateway de Agente do mecanismo, sem exigir que você recarregue ou alterne manualmente as ações na interface do repositório de dados.
Isso conclui a parte do Gemini Enterprise. Em seguida, vamos para a seção Validar.
9. Validar
Nesta seção, você conclui o fluxo único de consentimento do usuário do OAuth 2.0 do Google, invoca ferramentas do MCP no servidor mcp-sprockets externo do Gemini Enterprise e verifica se o servidor MCP externo validou ambos o IP estático reservado do Cloud NAT (egress_source_ip) e sua identidade do OAuth 2.0 do Google (authenticated_user).
Acesso do usuário
Construa o URL do web app 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}"
Concluir a permissão do OAuth
Antes de consultar o agente, você precisa concluir um fluxo de consentimento único do OAuth 2.0 que concede ao Gemini Enterprise permissão para receber um token de acesso para sua identidade do Google (${USER_IDENTITY}). Isso permite que o Gemini Enterprise autentique chamadas de ferramentas de saída pelo Gateway de Agente para que o servidor mcp-sprockets externo possa verificar sua identidade em todas as solicitações.
- Abra
${GE_APP_USER_URL}no navegador e clique em Começar. - Na caixa de conversa, clique no ícone Conectores (a peça de quebra-cabeça) e em Autorizar ao lado de
mcp-sprockets-collection. - Uma nova janela vai aparecer pedindo para você Escolher uma conta para continuar com
mcp-sprockets-oauth(o nome do app da tela de permissão do OAuth que você configurou). Selecione sua conta de usuário (${USER_IDENTITY}). - Na tela de permissão do OAuth do Google, revise as permissões solicitadas que permitem que o Google (o provedor de identidade) compartilhe sua identidade de usuário (
openid,email,profile) commcp-sprockets-oauthe clique em Continuar. - Clique no ícone Conectores novamente e verifique se a opção
mcp-sprockets-collectionestá ativada, confirmando que a autorização foi concluída.
Testar consultas do agente
Testes de interface do usuário do chat do Google Assistente
Envie a seguinte consulta de teste no chat:
look up sprocket SPK-105 and confirm the model, material, unit_price, authenticated_user, and egress_source_ip
Tente fazer uma segunda consulta na conversa:
list all sprockets in the inventory catalog and report the authenticated_user and egress_source_ip
Verifique se o assistente retorna as respostas corretas e mostra um selo de citação de ação interativo.
Por exemplo, "Sprocket Lookup SPK-105 (5s)Agent Gateway" abaixo de cada resposta confirma que a ferramenta foi executada.
Confira se o Google Assistente retorna as especificações da engrenagem com "authenticated_user" correspondendo a ${USER_IDENTITY} e "egress_source_ip" correspondendo ao seu ${NAT_EXT_IP} reservado.
Testes da API streamAssist do Google Assistente
Depois que sua conta de usuário autorizar o conector OAuth 2.0, você também poderá invocar a API default_assistant:streamAssist diretamente da CLI e verificar se o servidor mcp-sprockets externo retorna ambos seu IP estático do Cloud NAT (${NAT_EXT_IP}) e sua identidade verificada do OAuth 2.0 do Google (${USER_IDENTITY}):
Envie a seguinte consulta de teste:
# 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
Exemplo de saída:
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
Tente outra consulta:
# 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
Inspecionar registros no Cloud Logging
Verifique se o Gemini Enterprise roteou as chamadas de ferramentas pelo Gateway de Agente, o anexo de rede do PSC e o Cloud NAT inspecionando os registros no Cloud Logging.
Verificar os registros do Gateway de Agente
Confirme se o Gateway de Agente interceptou a solicitação, resolveu o destino no Agent Registry, avaliou a política de autorização e encaminhou a chamada de ferramenta:
# 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
)"
Exemplo de saída:
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
Verifique se a saída contém:
STATUS:200(execução bem-sucedida) e202(handshakenotifications/initialized).SERVER_IP:IP e porta do servidor MCP externo (${MCP_EXT_IP}:443).MCP_METHODeTOOL:a sequência de protocolo do MCP (initialize,notifications/initialized,tools/listetools/callcomget_sprocket_by_id).AUTHZ:ALLOWED(saída permitida de autorização do IAP).REGISTRY_MCP:ID do recurso do Agent Registry resolvido (agentregistry-...).
Verificar os registros do Cloud NAT
Confirme se o Cloud NAT traduziu a conexão de saída do IP de anexo de rede do PSC do Gateway de Agente (10.10.10.2) para o endereço IPv4 externo estático reservado (${NAT_EXT_IP}) ao se conectar 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
)"
Exemplo de saída:
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
Verificar registros de firewall
Confirme se a política de firewall interna (fw-policy-${SLUG}-internal) permitiu o tráfego de saída do Gateway de Agente para o destino na 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
)"
Confirme se a política de firewall externa (fw-policy-${SLUG}-external) permitiu o tráfego de entrada para o servidor MCP do endereço IP NAT público da rede 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
)"
Isso conclui a parte de validação. Em seguida, vamos para a seção Limpeza.
10. Limpeza
Siga estas etapas para excluir os recursos e as configurações criados neste laboratório.
Remover componentes do 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"}}'
Para remover as credenciais do cliente OAuth 2.0 (ge-mcp-sprockets-client), abra a página "Clientes da plataforma de autenticação do Google" e clique no ícone Excluir (lixeira) ao lado de ge-mcp-sprockets-client:
# print google auth platform clients url
echo "https://console.cloud.google.com/auth/clients?project=${PROJ_ID}"
Remover componentes do servidor MCP e do 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}
Remover componentes do Gateway de Agente
# 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}
Remover componentes de 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
Remover componentes de rede
# 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
Remover substituições de políticas da organização e arquivos locais
# 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
Isso conclui a revisão dos dados. Em seguida, vamos para a Conclusão.
11. Conclusão
Parabéns! Você criou uma arquitetura de ponta a ponta que permite que um app Gemini Enterprise descubra e invoque ferramentas com segurança em um servidor MCP personalizado externo com lista de permissões de IP e proteção OAuth 2.0:
- Saída VPC de IP estático (
ALL_TRAFFICe Cloud NAT): roteou todo o tráfego de saída do Gateway de Agente por um anexo de rede PSC (10.10.10.2) e traduziu as solicitações vinculadas à Internet para um endereço IPv4 externo estático reservado (${NAT_EXT_IP}) usando o Cloud NAT. - Servidor de recursos do MCP OAuth 2.0 e Agent Registry:implantamos um servidor HTTP FastMCP externo transmitível (
mcp-sprockets) protegido por uma lista de permissões estrita de firewall de IP de origem (${NAT_EXT_IP}/32) e verificação do OAuth 2.0 do Googletokeninfo, além de registrar o endpoint e o esquema de ferramentas (get_sprocketseget_sprocket_by_id) no Agent Registry. - Integração e governança do OAuth 2.0 do Gemini Enterprise:provisionamos um app Gemini Enterprise, vinculamos o tráfego de ferramentas de saída ao Gateway de Agente, anexamos o servidor MCP registrado como um conector de dados OAuth 2.0
REGISTRY_MCPe verificamosegress_source_ipeauthenticated_userjunto com a telemetria do Cloud Logging.

O Cosmopup acha que os codelabs são incríveis!
O que vem em seguida?
- Confira a documentação da Gemini Enterprise Agent Platform para conhecer recursos e tutoriais avançados.
- Configure proteções do Model Armor no Gateway de Agente para mais segurança da IA.
- Conheça as Políticas de Governança Semântica para aplicar regras de negócios e conformidade a consultas em linguagem natural.
Envie comentários, dúvidas ou correções usando este formulário de feedback.
Valeu!