Saída do Gemini Enterprise com o Gateway de Agente para um servidor MCP personalizado particular usando o Agent Registry

1. Introdução

Este codelab explora a conectividade de saída privada e gerenciada para o Gemini Enterprise usando o Gateway de Agente no modo agent-to-anywhere (saída). Você vai configurar um app Gemini Enterprise para invocar com segurança um servidor do Protocolo de Contexto de Modelo (MCP) personalizado hospedado no Cloud Run roteando o tráfego pelo Gateway de Agente usando interfaces do Private Service Connect (PSC) para se conectar a um endpoint do PSC para APIs do Google em uma rede VPC.

Em ambientes corporativos, conceder acesso direto à rede a agentes autônomos coloca em risco a exfiltração de dados e a execução de ferramentas não testadas. O Agent Gateway oferece um ponto de aplicação de confiança zero centralizado no nível da plataforma que inspeciona dinamicamente payloads de ferramentas MCP HTTP transmissíveis. As solicitações de saída são autenticadas com uma identidade do agente criptograficamente verificável e autorizadas pelo Identity-Aware Proxy (IAP) usando políticas de acesso unificado (UAP) do IAM com regras da Common Expression Language (CEL). Isso permite um controle de acesso granular a ferramentas e métodos específicos do MCP sem expor as cargas de trabalho de back-end à Internet pública.

O que você vai criar

  • O Gateway de Agente operando no modo de saída (agente para qualquer lugar) com verificação de endpoint do Agent Registry
  • Serviço do Cloud Run que hospeda um servidor MCP HTTP transmissível particular (--ingress=internal) registrado com as especificações da ferramenta no Agent Registry.
  • Extensão de autorização do Identity-Aware Proxy (IAP) para o Gateway de Agente
  • Políticas de acesso unificado (UAP) do IAM com condições da CEL para autorização da ferramenta MCP
  • App Gemini Enterprise vinculado ao Gateway de Agente e conectado a um repositório de dados de servidor MCP personalizado importado do Agent Registry
  • Recursos de rede VPC, zona do Cloud DNS e endpoint do PSC para APIs do Google
  • Anexo de rede do PSC para saída VPC privada do Gateway de Agente
  • Regras de política do Cloud Next Generation Firewall (NGFW) para proteger o tráfego da VPC

figure1

Figura 1. Arquitetura do codelab

Conteúdo do laboratório

  • Como implantar um servidor MCP HTTP particular e transmitível da origem no Cloud Run e registrar o endpoint e o esquema de ferramenta no Agent Registry
  • Como configurar o Gateway de Agente com entradas de registro em conformidade e rotear as chamadas de ferramentas do app Gemini Enterprise pelo gateway
  • Como estabelecer uma saída de VPC particular usando anexos e interfaces de rede PSC
  • Como delegar a autorização do Gateway de Agente ao Identity-Aware Proxy (IAP)
  • Como criar e vincular políticas de acesso unificado (UAP, na sigla em inglês) do IAM usando atributos destination.agent_registry.* e destination.is_registered da CEL para restringir a execução da ferramenta MCP
  • Como validar a aplicação de políticas e a saída de rede usando 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, recursos do Gemini Enterprise e da Agent Platform
  • Um shell compatível com POSIX (bash ou zsh) com a CLI do Google Cloud (gcloud), curl e jq instalados

Esta é a parte introdutória. Agora vamos para a seção Conceitos.

2. Conceitos

Sequência de implantação

Este codelab implanta primeiro a infraestrutura para que os caminhos de rede privada e os controles de governança estejam operacionais antes de registrar e conectar as ferramentas do MCP ao Gemini Enterprise:

  1. Infraestrutura de rede:provisione sub-redes VPC, um endpoint do PSC, um anexo de rede do PSC, regras de política do Cloud NGFW e zonas privadas do Cloud DNS.
  2. Gateway de Agente:implante o Gateway de Agente no modo de saída com integração do Agent Registry (registries) e saída de VPC particular (networkAttachment).
  3. Políticas de autorização:configure a extensão de autorização do IAP, a política de autorização do gateway e a política de acesso unificado (UAP) do IAM usando condições destination.is_registered e destination.agent_registry.* da CEL.
  4. Implante e registre o servidor MCP:implante o servidor MCP de matemática da origem para o Cloud Run (--ingress=internal) e registre as especificações de serviço e ferramenta (add e subtract) no Agent Registry.
  5. App Gemini Enterprise:crie o app Gemini Enterprise (Engine), configure as definições de identidade e observabilidade e vincule o egress de saída ao Gateway de Agente (agentGatewaySetting).
  6. Importar conector de dados MCP personalizado:crie e ative o conector de dados REGISTRY_MCP (:setUpDataConnector) para vincular o repositório de dados de suporte do servidor MCP registrado ao app Gemini Enterprise.
  7. Validar:teste as execuções de ferramentas permitidas e negadas no chat e verifique a aplicação da política nos registros do Gateway de Agente, DNS, firewall e Cloud Run.

Saída do Gemini Enterprise

O Gemini Enterprise encaminha solicitações de ferramentas do servidor MCP personalizado para o Gateway de Agente quando agentGatewaySetting em Engine e use_agent_gateway_egress: true em DataConnector estão configurados.

figure2

Fig. 2. Arquitetura de saída do Gemini Enterprise

O app Gemini Enterprise organiza o roteamento de ferramentas em quatro áreas principais:

  1. Widget (default_search_widget_config):
    • Serve a interface do cliente da Web. O widget recebe comandos do usuário e inicia sessões de chat com o mecanismo subjacente.
  2. 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 determina se é necessário fazer um cálculo aritmético, inspeciona as ferramentas disponíveis e delega a execução ao subagente do Gateway de Agente sintetizado.
  3. Data Store e Data Connector:
    • DataStore: provisionado em um Collection dedicado quando o :setUpDataConnector é executado, ele vincula (dataStoreIds) os esquemas de ferramentas importados do Agent Registry (add, subtract), os tipos de argumentos e as instruções do agente ao Engine do Gemini Enterprise.
    • DataConnector: gerencia a conexão de ação REGISTRY_MCP (createBapConnection: true) com o servidor MCP remoto (instance_uri), resolve o recurso do servidor MCP do Agent Registry (registry_mcp_server_name) e ativa a saída do Agent Gateway (use_agent_gateway_egress: true).
  4. Identidade do agente, Agent Registry e Gateway de Agente:
    • Quando o conector de dados envia a chamada de ferramenta de saída, ele encaminha o tráfego para o gateway especificado em agentGatewaySetting. O Núcleo Assistant gera um token de identidade SPIFFE que declara sua identidade: principal://agents.global.org-.../agents/default/core_assistant.
    • O Gateway de Agente se integra ao Agent Registry usando o campo registries para resolver dinamicamente endpoints de destino e esquemas de ferramentas registrados. Ele preenche os atributos destination.is_registered e destination.agent_registry.* e os transmite para o IAP v2 para avaliação em relação às regras CEL da política de acesso unificado (UAP) do IAM antes de permitir o trânsito para a rede VPC.

Conectividade da VPC do gateway

O Gateway de Agente permite a conectividade privada de rede VPC usando dois campos YAML:

  • networkConfig.egress.networkAttachment:direciona o tráfego de IP particular para ser roteado pela vinculação de rede do PSC na rede VPC.
  • dnsPeeringConfig.domains:faz peering da resolução de DNS com a zona de DNS do Cloud DNS da rede VPC para que os nomes de host de destino (*.run.app) sejam resolvidos para o endereço IP do endpoint PSC particular definido na rede VPC.

Limitações e requisitos

Isso conclui a parte de conceitos. Em seguida, vamos para a seção Configuração.

3. Configuração

Papéis do IAM obrigatórios

Os seguintes papéis são necessários para concluir o codelab:

Domínio

Papéis do IAM obrigatórios

Projeto e IAM

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

Rede e gateway

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

Gemini Enterprise e Registry

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

Cargas de trabalho e criação

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

Observabilidade

roles/logging.viewer
roles/logging.logWriter

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 projeto na nuvem do Google Cloud:

Definir o ID do projeto

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"

echo ${SLUG}
echo ${REGION}
# create project vars (automatic)
export PROJ_ID=$(gcloud config list --format="value(core.project)")
export PROJ_NO=$(gcloud projects describe ${PROJ_ID} --format="value(projectNumber)")
export ORG_ID=$(gcloud projects get-ancestors ${PROJ_ID} --format="value(id)" | tail -n 1)
export USER_IDENTITY=$(gcloud config get-value account)

echo ${PROJ_ID}
echo ${PROJ_NO}
echo ${ORG_ID}
echo ${USER_IDENTITY}
# create resource vars for agent platform (automatic)
export AGW_NAME="agw-${SLUG}-${REGION}-ata"
export AGW_URI="projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
export UAP_POLICY_NAME="uap-policy-${SLUG}"
export UAP_BINDING_NAME="uap-binding-${SLUG}"
export MCP_NAME="math-wizard"
export MCP_URL="https://${MCP_NAME}-${PROJ_NO}.${REGION}.run.app/mcp"

echo ${AGW_NAME}
echo ${AGW_URI}
echo ${UAP_POLICY_NAME}
echo ${UAP_BINDING_NAME}
echo ${MCP_NAME}
echo ${MCP_URL}
# create resource vars for gemini enterprise (automatic)
export GE_APP_DISPLAY_NAME="Codelab app"
export GE_APP_ORG_NAME="${SLUG}, Inc."
export GE_LOCATION="global"
export GE_APP_NAME="app-${SLUG}-${GE_LOCATION}"
export GE_APP_INIT="${GE_APP_NAME}_$(date +%s)"

echo ${GE_APP_DISPLAY_NAME}
echo ${GE_APP_ORG_NAME}
echo ${GE_LOCATION}
echo ${GE_APP_NAME}
echo ${GE_APP_INIT}

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

Se você estiver executando uma instalação autogerenciada do SDK do 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 apis (part 1)
gcloud services enable \
  agentregistry.googleapis.com \
  agentidentity.googleapis.com \
  aiplatform.googleapis.com \
  apphub.googleapis.com \
  apptopology.googleapis.com \
  cloudapiregistry.googleapis.com \
  cloudtrace.googleapis.com \
  compute.googleapis.com \
  dataform.googleapis.com \
  iam.googleapis.com \
  iap.googleapis.com \
  logging.googleapis.com \
  modelarmor.googleapis.com \
  monitoring.googleapis.com \
  networksecurity.googleapis.com \
  networkservices.googleapis.com \
  notebooks.googleapis.com \
  observability.googleapis.com
# enable google apis (part 2)
gcloud services enable \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com \
  discoveryengine.googleapis.com \
  dns.googleapis.com \
  orgpolicy.googleapis.com \
  run.googleapis.com \
  saasservicemgmt.googleapis.com \
  securitycenter.googleapis.com \
  storage.googleapis.com \
  telemetry.googleapis.com \
  texttospeech.googleapis.com

Políticas da organização

As restrições gerenciadas da política da organização padrão do Google Cloud restringem os recursos usados neste codelab:

Substitua as restrições de política da organização herdadas no nível do projeto definindo explicitamente enforce: false.

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_NO}/policies/discoveryengine.managed.disableCustomMcpServerConnector
spec:
  rules:
  - enforce: false
EOF
# verify org policy constraint on project
gcloud org-policies describe discoveryengine.managed.disableCustomMcpServerConnector \
  --project=${PROJ_ID} --effective

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
# verify org policy constraint on project
gcloud org-policies describe iam.managed.disableAccessPolicyBinding \
  --project=${PROJ_ID} --effective

Verificar e desativar restrições de conector de dados condicionais

Por padrão, discoveryengine.managed.allowedEgressFqdns e discoveryengine.managed.allowedDataSources só bloqueiam a criação de conectores se o projeto estiver dentro de um perímetro do VPC Service Controls (VPC SC) ou se um administrador da organização tiver adicionado o projeto a enforcedProjects.

Primeiro, inspecione as políticas vigentes no seu projeto:

# check effective egress fqdn constraint on project
gcloud org-policies describe discoveryengine.managed.allowedEgressFqdns \
  --project=${PROJ_ID} --effective
# check effective data source constraint on project
gcloud org-policies describe discoveryengine.managed.allowedDataSources \
  --project=${PROJ_ID} --effective

~~IF~~ essas restrições forem aplicadas, para garantir que elas não bloqueiem a configuração do conector custom_mcp em uma VPC SC ou organização restrita por política, defina enforce: false nas duas políticas do projeto:

# disable egress fqdn constraint on project
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJ_NO}/policies/discoveryengine.managed.allowedEgressFqdns
spec:
  rules:
  - enforce: false
EOF
# disable allowed data sources constraint on project
gcloud org-policies set-policy /dev/stdin << EOF
name: projects/${PROJ_NO}/policies/discoveryengine.managed.allowedDataSources
spec:
  rules:
  - enforce: false
EOF
# verify both constraints are disabled on project
gcloud org-policies describe discoveryengine.managed.allowedEgressFqdns \
  --project=${PROJ_ID} --effective

gcloud org-policies describe discoveryengine.managed.allowedDataSources \
  --project=${PROJ_ID} --effective

Permissões do IAM

Conceda os papéis do IAM necessários à sua conta de usuário e à conta de serviço padrão do Compute Engine usada pelo Cloud Build:

  • Conta de usuário (${USER_IDENTITY}):
    • Exige permissões para implantar e invocar serviços do Cloud Run (roles/run.admin, roles/run.invoker, roles/iam.serviceAccountUser), criar imagens de contêiner (roles/cloudbuild.builds.editor), gerenciar o Gemini Enterprise (roles/discoveryengine.admin) e criar políticas de acesso unificado (roles/iam.accessPolicyAdmin).
  • Conta de serviço padrão do Compute Engine(${PROJ_NO}-compute@developer.gserviceaccount.com):
    • Usado pelo Cloud Build para preparar o código-fonte no Cloud Storage (roles/storage.admin), enviar imagens para o Artifact Registry (roles/artifactregistry.writer) e gravar registros de build (roles/logging.logWriter).

Execute os comandos a seguir para atribuir as vinculações de função:

# grant roles to user account
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/run.admin"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/iam.serviceAccountUser"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/run.invoker"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/discoveryengine.admin"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/iam.accessPolicyAdmin"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="user:${USER_IDENTITY}" \
  --role="roles/cloudbuild.builds.editor"
# grant roles to default compute (cloud build) service account
gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --role="roles/storage.admin"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --role="roles/artifactregistry.writer"

gcloud projects add-iam-policy-binding ${PROJ_ID} \
  --member="serviceAccount:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --role="roles/logging.logWriter"

Verificar permissões do IAM

Verifique as seis vinculações de papéis (6) na conta de usuário.

# show iam policy on project for user account
gcloud projects get-iam-policy ${PROJ_ID} \
  --flatten="bindings[].members" \
  --filter="bindings.members:${USER_IDENTITY}" \
  --format="table(bindings.role:label=ROLE, bindings.members:label=PRINCIPAL_IDENTITY)"

Verifique as três vinculações de função (3) na conta de serviço padrão do Compute.

# show iam policy on project for default compute service account
gcloud projects get-iam-policy ${PROJ_ID} \
  --flatten="bindings[].members" \
  --filter="bindings.members:${PROJ_NO}-compute@developer.gserviceaccount.com" \
  --format="table(bindings.role:label=ROLE, bindings.members:label=PRINCIPAL_IDENTITY)"

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 implantar uma rede VPC usando o modo personalizado com uma sub-rede /28 dedicada (192.168.10.0/28) que oferece suporte ao anexo de rede do PSC para saída de rede do Gateway de Agente na rede VPC.

O endpoint do PSC para APIs do Google é implantado usando um único /32endereço IPv4 interno global (172.16.20.20) para oferecer suporte ao acesso interno privado a APIs e serviços do Google. Neste codelab, o Gateway de Agente tem como destino o Cloud Run usando o endpoint da PSC ao resolver o domínio run.app. pelo peering do Cloud DNS.

criar redes

Crie uma rede VPC global.

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

Crie sub-redes para o anexo de rede PSC do Gateway de Agente:

# create subnet for agent gateway psc na
gcloud compute networks subnets create subnet-${REGION}-agw \
  --network=vnet-${SLUG} \
  --range=192.168.10.0/28 \
  --region=${REGION} \
  --enable-private-ip-google-access

Crie regras de firewall

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. 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} --global
# create fw policy rule
gcloud compute network-firewall-policies rules create 1001 \
  --description="allow all out and log" \
  --firewall-policy=fw-policy-${SLUG} \
  --global-firewall-policy \
  --action=allow \
  --direction=EGRESS \
  --layer4-configs=all \
  --dest-ip-ranges=0.0.0.0/0 \
  --enable-logging
# bind fw policy to network
gcloud compute network-firewall-policies associations create \
  --name=fw-policy-bind-${SLUG} \
  --firewall-policy=fw-policy-${SLUG} \
  --network=vnet-${SLUG} \
  --global-firewall-policy

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 consumidora da conexão para vincular com segurança o lado produtor do Gateway de Agente para 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 endpoint do PSC

Um endpoint do Private Service Connect (PSC) para APIs do Google é usado pelo Gateway de Agente para estabelecer conectividade privada com o servidor MCP do Cloud Run por um caminho de rede interna sem expor o tráfego à Internet pública. As chamadas de função de saída que saem do Gateway de Agente para a rede VPC resolvem o URL do serviço de destino do Cloud Run (*.run.app) para esse endereço IP de endpoint particular.

Reserve um endereço IPv4 interno global para o endpoint do PSC. O endereço IP escolhido precisa ser um endereço /32 que não se sobreponha a nenhuma sub-rede na sua rede VPC:

# set env var for psc ep ip address
export PSC_EP_IP="172.16.20.20"
echo ${PSC_EP_IP}
# reserve internal global ipv4 address
gcloud compute addresses create ip-psc2gapis \
  --global \
  --purpose=PRIVATE_SERVICE_CONNECT \
  --addresses=${PSC_EP_IP} \
  --network=vnet-${SLUG}

Crie um endpoint do PSC para APIs do Google usando o pacote all-apis, que inclui o Cloud Run (run.app).

# create psc endpoint for google apis
gcloud compute forwarding-rules create psc2gapis \
  --global \
  --network=vnet-${SLUG} \
  --address=ip-psc2gapis \
  --target-google-apis-bundle=all-apis

Verificar o endpoint do PSC

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

Criar zona de DNS e registros

O Cloud DNS é usado para permitir que o Gateway de Agente se comunique de maneira particular com o servidor MCP hospedado no Cloud Run. Quando o Gateway de Agente avalia solicitações de ferramentas de saída destinadas ao Cloud Run, ele usa o peering de DNS (dnsPeeringConfig.domains) para resolver consultas de DNS para *.run.app usando sua zona privada do Cloud DNS associada à rede VPC. O registro DNS particular retorna a consulta com o endereço IP do endpoint PSC interno (172.16.20.20), permitindo que as solicitações da ferramenta MCP sejam encaminhadas por um caminho de rede particular.

Crie uma zona gerenciada particular do Cloud DNS para o domínio run.app.:

# create private dns zone
gcloud dns managed-zones create priv-zone-run \
  --description="private zone for run.app" \
  --dns-name="run.app." \
  --visibility=private \
  --networks=vnet-${SLUG}

Crie um registro DNS curinga A para *.run.app. apontando para o endereço IP do endpoint do PSC:

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

Crie uma política do Cloud DNS para ativar a geração de registros de consultas DNS. A geração de registros de DNS captura solicitações de resolução de domínio originadas do Gateway de Agente na sua rede VPC, oferecendo capacidade de auditoria e permitindo verificar se as solicitações da ferramenta *.run.app são resolvidas corretamente para o endpoint PSC interno:

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

Isso conclui a parte da rede. Em seguida, vamos para a seção Gateway de Agente.

5. Gateway de Agente

O Gateway de Agente especifica registries para instâncias do Agent Registry, além dos campos networkConfig que configuram o anexo de rede do PSC e as configurações de peering de DNS para conectividade VPC privada:

  • registries:associa o gateway a até duas instâncias do Agent Registry: uma regional (../locations/${REGION}) e uma global (../locations/global). Isso integra o Agent Gateway ao Agent Registry para resolver implantações regionais (como servidores MCP do Cloud Run em ${REGION}) e recursos globais (como agentes do Gemini Enterprise e endpoints globais) para aplicação refinada da política do IAP v2. As entradas regionais têm precedência sobre as globais ao resolver URLs de destino.
  • networkAttachment:aponta para o anexo de rede do PSC (psc-na-${REGION}-agw), conectando o Gateway de Agente à sua rede VPC para saída particular.
  • dnsPeeringConfig.domains:configura run.app. para que as consultas DNS originadas do Gateway de Agente para serviços do Cloud Run usem o peering de DNS para resolver nomes de host no endereço IP do endpoint PSC das APIs privadas do Google (172.16.20.20) configurado na sua zona particular do Cloud DNS.

Implantar o gateway de agente

Crie e importe o arquivo de configuração do Gateway de Agente.

# create agent gateway config file
cat > cfg/${AGW_NAME}-networkConfig.yaml << EOF
name: ${AGW_NAME}
protocols:
  - MCP
googleManaged:
  governedAccessPath: AGENT_TO_ANYWHERE
registries:
  - "//agentregistry.googleapis.com/projects/${PROJ_ID}/locations/${REGION}"
networkConfig:
  egress:
    networkAttachment: ${PSC_NA_URI}
  dnsPeeringConfig:
    domains:
      - run.app.
    targetProject: ${PROJ_ID}
    targetNetwork: projects/${PROJ_ID}/global/networks/vnet-${SLUG}
EOF
# import agent gateway config file (create gateway)
gcloud network-services agent-gateways import ${AGW_NAME} \
  --source="cfg/${AGW_NAME}-networkConfig.yaml" \
  --location=${REGION}

Verificar a implantação do gateway de agente

Confirme o Agent Registry e a configuração de rede:

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

Resposta esperada:

networkConfig:
  dnsPeeringConfig:
    domains:
    - run.app.
    targetNetwork: projects/${PROJ_ID}/global/networks/vnet-${SLUG}
    targetProject: ${PROJ_ID}
  egress:
    networkAttachment: projects/${PROJ_ID}/regions/${REGION}/networkAttachments/psc-na-${REGION}-agw
registries:
- //agentregistry.googleapis.com/projects/${PROJ_ID}/locations/${REGION}

Verifique se a saída mostra os detalhes de configuração necessários:

  • registries:lista o URI regional (${REGION}) do Agent Registry associado ao gateway.
  • egress.networkAttachment:especifica o URI de anexo de rede do PSC para saída da VPC.
  • dnsPeeringConfig.domains:contém run.app. apontando para targetNetwork para resolução de domínio privado.

Inspecione a conexão 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)"

Verifique se há um endpoint de conexão aceito:

connectionEndpoints:
- ipAddress: 192.168.10.2
  projectIdOrNum: '<AGW_TENANT_PROJ_NO>'
  status: ACCEPTED
  subnetwork: https://www.googleapis.com/compute/v1/projects/${PROJ_ID}/regions/${REGION}/subnetworks/subnet-${REGION}-agw

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

figure3

Fig. 3. Arquitetura de autorização

O fluxo de autorização conecta três componentes:

  1. Política de autorização de gateway (authzPolicy):
    • Um recurso regional que segmenta o Gateway de Agente.
    • Configurado com policyProfile: REQUEST_AUTHZ e action: CUSTOM para encaminhar todas as verificações de autorização de saída para a extensão Authz do IAP.
  2. Extensão de serviço do 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 ENFORCE usando a versão V2 da política.
  3. Política e vinculação de acesso unificado do IAM (accessPolicy e policyBinding):
    • Recursos globais do IAM v3 que contêm regras de acesso refinadas.
    • Autentica a identidade principal do SPIFFE do agente de chamada, verifica a permissão universal iap.googleapis.com/resources.egressViaIAP e avalia as condições da Common Expression Language (CEL) em relação aos atributos de destino.

Implantar a extensão de autorização

Crie uma configuração de extensão de autorização service-extensions que delega decisões de autorização ao serviço IAP:

# create authz extension config file
cat > cfg/${AGW_NAME}-svc-ext-authz-iap.yaml << EOF
name: ${AGW_NAME}-svc-ext-authz-iap
service: iap.googleapis.com
failOpen: false
timeout: 1s
metadata:
  iapPolicyVersion: "V2"
EOF
# import iap authz extension (create authz extension)
gcloud service-extensions authz-extensions import ${AGW_NAME}-svc-ext-authz-iap \
  --source=cfg/${AGW_NAME}-svc-ext-authz-iap.yaml \
  --location=${REGION}

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,
    updateTime.date(tz=LOCAL):label=MODIFIED,
    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,
    customProvider.list().sub('\W.*', ''):label=CUSTOM_PROVIDER_TYPE,
    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.
  • 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).
  • Nome da ferramenta (destination.agent_registry.mcp_server.tool.name):
    • O nome da ferramenta específica invocada (por exemplo, subtract ou add), permitindo autorização refinada no nível da ferramenta em servidores MCP registrados.

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.egressViaIAP necessá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_NAME}-rules.json << EOF
[
  {
    "description": "allow ge assistant to any registered service",
    "effect": "ALLOW",
    "principals": [
      "principal://${TRUST_DOMAIN}/resources/discoveryengine/projects/${PROJ_NO}/locations/global/engines/${GE_APP_INIT}/assistants/default_assistant/agents/default/core_assistant"
    ],
    "operation": {
      "permissions": [
        "iap.googleapis.com/resources.egressViaIAP"
      ]
    },
    "conditions": {
      "iap.googleapis.com": {
        "expression": \
        "destination.is_registered == true"
      }
    }
  }
]
EOF

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_NAME} \
  --details-rules=cfg/${UAP_POLICY_NAME}-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_NAME} \
  --project=${PROJ_ID} \
  --location=global

Resposta esperada:

details:
  rules:
  - conditions:
      iap.googleapis.com:
        expression: destination.is_registered == true
    description: allow ge assistant to any registered service
    effect: ALLOW
    operation:
      permissions:
      - iap.googleapis.com/resources.egressViaIAP
    principals:
    - principal://agents.global.org-${ORG_ID}.system.id.goog/resources/discoveryengine/projects/${PROJ_NO}/locations/global/engines/${GE_APP_INIT}/assistants/default_assistant/agents/default/core_assistant
name: projects/${PROJ_ID}/locations/global/accessPolicies/${UAP_POLICY_NAME}

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_BINDING_NAME} \
  --policy="projects/${PROJ_ID}/locations/global/accessPolicies/${UAP_POLICY_NAME}" \
  --target-resource="//cloudresourcemanager.googleapis.com/projects/${PROJ_ID}" \
  --project=${PROJ_ID} \
  --location=global

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_BINDING_NAME} \
  --project=${PROJ_ID} \
  --location=global

Resposta esperada:

name: projects/${PROJ_ID}/locations/global/policyBindings/${UAP_BINDING_NAME}
policy: projects/${PROJ_ID}/locations/global/accessPolicies/${UAP_POLICY_NAME}
policyKind: ACCESS
target:
  resource: //cloudresourcemanager.googleapis.com/projects/${PROJ_ID}

Isso conclui a parte do Gateway de Agente. Em seguida, vamos para a seção servidor MCP.

6. Servidor MCP

Nesta seção, você vai criar um servidor FastMCP personalizado que expõe as ferramentas add e subtract e implantá-lo no Cloud Run diretamente da origem. Durante a implantação da origem (--source), o Cloud Build empacota a imagem do contêiner usando o Dockerfile e o uv incluídos, que instala as dependências definidas em pyproject.toml e inicia server.py.

Depois que o serviço do Cloud Run for implantado, registre o servidor MCP no Agent Registry com a especificação da ferramenta (toolspec.json) para que o Gemini Enterprise possa descobrir e invocar as ferramentas.

Criar aplicativo de servidor MCP

Crie um diretório de projeto math-wizard para o código do aplicativo:

# create directory for code
mkdir -p math-wizard

Escreva o arquivo de manifesto do projeto Python:

# create python project manifest file
cat > math-wizard/pyproject.toml << 'EOF'
[project]
name = "math-wizard"
version = "0.1.0"
description = "math wizard mcp server"
requires-python = ">=3.12"
dependencies = [
    "fastmcp==2.13.1",
]
EOF

Algumas funções de instrumentação adicionais estão incluídas no código para capturar cabeçalhos HTTP de entrada (mcp-session-id, x-forwarded-for, user-agent e x-cloud-trace-context) para validação do Cloud Logging e do Cloud Trace.

Escreva o arquivo de código do aplicativo:

# create mcp server application code
cat > math-wizard/server.py << 'EOF'
import asyncio
import json
import logging
import os
from fastmcp import FastMCP
from fastmcp.server.dependencies import get_http_headers
from mcp.types import ToolAnnotations

logger = logging.getLogger(__name__)
logging.basicConfig(format="[%(levelname)s]: %(message)s", level=logging.INFO)

mcp = FastMCP("math wizard mcp server")

def log_network_context(tool_name: str, a: int, b: int) -> None:
    headers = get_http_headers()
    print(json.dumps({
        "severity": "INFO",
        "message": f">>> 🛠️ Tool: '{tool_name}' called with numbers '{a}' and '{b}'",
        "tool": tool_name,
        "mcp_session_id": headers.get("mcp-session-id"),
        "x_forwarded_for": headers.get("x-forwarded-for"),
        "user_agent": headers.get("user-agent"),
        "trace_header": headers.get("x-cloud-trace-context"),
    }), flush=True)

@mcp.tool(
    annotations=ToolAnnotations(
        readOnlyHint=True,
    )
)
def add(a: int, b: int) -> int:
    """Use this to add two numbers together.

    Args:
        a: The first number.
        b: The second number.

    Returns:
        The sum of the two numbers.
    """
    logger.info(f">>> 🛠️ Tool: 'add' called with numbers '{a}' and '{b}'")
    log_network_context("add", a, b)
    return a + b

@mcp.tool(
    annotations=ToolAnnotations(
        readOnlyHint=True,
    )
)
def subtract(a: int, b: int) -> int:
    """Use this to subtract two numbers.

    Args:
        a: The first number.
        b: The second number.

    Returns:
        The difference of the two numbers.
    """
    logger.info(f">>> 🛠️ Tool: 'subtract' called with numbers '{a}' and '{b}'")
    log_network_context("subtract", a, b)
    return a - b

if __name__ == "__main__":
    logger.info(f"🚀 MCP server started on port {os.getenv('PORT', 8080)}")
    asyncio.run(
        mcp.run_async(
            transport="streamable-http",
            host="0.0.0.0",
            port=int(os.getenv("PORT", 8080)),
        )
    )
EOF

Escreva o Dockerfile para definir instruções de build de imagens de contêiner e comandos de inicialização:

# create dockerfile
cat > math-wizard/Dockerfile << 'EOF'
# use official python 3.12 image
FROM python:3.12-slim

# install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

# install the project into /app
COPY . /app
WORKDIR /app

# allow statements and log messages to immediately appear in the logs
ENV PYTHONUNBUFFERED=1

# install dependencies
RUN uv sync

EXPOSE 8080

# run the mcp server
CMD ["uv", "run", "server.py"]
EOF

Implantar o serviço no Cloud Run

Implante o servidor MCP da origem usando o Cloud Build, que usa a conta de serviço de computação padrão do projeto ${PROJ_NO}-compute@developer.gserviceaccount.com:

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

Verificar a implantação do Cloud Run

Verifique os detalhes do serviço do Cloud Run para conferir a configuração ativa:

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

Resposta esperada:

<snip>
✔ Service math-wizard in region ${REGION}

URL:     https://math-wizard-${PROJ_NO}.${REGION}.run.app
Ingress: internal
Traffic:
  100% LATEST (currently math-wizard-00001-<id>)
</snip>

Registrar o servidor MCP no Agent Registry

Para permitir que o Gemini Enterprise descubra as ferramentas exatas disponíveis no servidor MCP, um arquivo de especificações de ferramentas (toolspec.json) precisa ser fornecido durante o registro no Agent Registry.

Criar especificação de ferramenta do MCP

# create tool spec file
cat > cfg/toolspec.json << 'EOF'
{
  "tools": [
    {
      "name": "add",
      "description": "Use this to add two numbers together.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "a": { "type": "integer", "description": "The first number." },
          "b": { "type": "integer", "description": "The second number." }
        },
        "required": ["a", "b"]
      },
      "isReadOnly": true,
      "isDestructive": false,
      "isIdempotent": true,
      "isOpenWorld": false
    },
    {
      "name": "subtract",
      "description": "Use this to subtract two numbers.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "a": { "type": "integer", "description": "The first number." },
          "b": { "type": "integer", "description": "The second number." }
        },
        "required": ["a", "b"]
      },
      "isReadOnly": true,
      "isDestructive": false,
      "isIdempotent": true,
      "isOpenWorld": false
    }
  ]
}
EOF

Registrar o servidor MCP no Agent Registry

# register mcp server in agent registry
gcloud agent-registry services create ${MCP_NAME} \
  --project=${PROJ_ID} \
  --location=${REGION} \
  --display-name="${MCP_NAME}-${PROJ_NO}.${REGION}.run.app" \
  --description="MANDATORY MATH & ARITHMETIC AGENT: You MUST ALWAYS invoke \
this tool for ANY mathematical calculation, addition (+), subtraction (-), \
sum, difference, or arithmetic question (including simple questions like \
'what is 67 + 345?'). NEVER compute arithmetic yourself and NEVER transfer \
math queries to file_and_coding_agent / code interpreter. Always delegate \
every math question to this tool." \
  --mcp-server-spec-type=tool-spec \
  --mcp-server-spec-content=cfg/toolspec.json \
  --interfaces=protocolBinding=JSONRPC,url="${MCP_URL}"

Verificar o servidor MCP no Agent Registry

Verifique se o serviço do Cloud Run implantado está listado como um servidor MCP registrado na região, junto com o URL do endpoint e as ferramentas disponíveis:

# list registered mcp servers in agent registry
gcloud agent-registry mcp-servers list \
  --location=${REGION} \
  --project=${PROJ_ID} \
  --format="table(
    name.basename():label=REGISTRY_ID,
    displayName:label=DISPLAY_NAME,
    interfaces[0].url:label=ENDPOINT_URL,
    tools[].name.list():label=TOOLS
  )"

Resposta esperada:

REGISTRY_ID                                         DISPLAY_NAME                                  ENDPOINT_URL                                              TOOLS
agentregistry-00000000-0000-0000-0012-3456789abcde  math-wizard-${PROJ_NO}.${REGION}.run.app      https://math-wizard-${PROJ_NO}.${REGION}.run.app/mcp      add,subtract

Confira a especificação de configurações de serviço para ver se ela registra as definições exatas de ferramentas, os esquemas de entrada e as anotações de comportamento de cada ferramenta:

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

Isso conclui a parte do servidor MCP. Em seguida, vamos para a seção Gemini Enterprise.

7. Gemini Enterprise

Nesta seção, você vai criar e configurar um app do Gemini Enterprise e um recurso vinculado de repositório de dados do servidor MCP personalizado.

Modelo de recurso do Discovery Engine

Um app 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:ingerem e indexam 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.

Roteamento de saída pelo Gateway de Agente

Por padrão, o Gemini Enterprise encaminha o tráfego de execução de conectores e ferramentas por redes públicas. No entanto, para cargas de trabalho de VPC particulares e governança de confiança zero, o mecanismo pode ser configurado para rotear a saída pelo Gateway de Agente:

  • Ao criar o repositório de dados do servidor MCP personalizado mais adiante neste laboratório, ative a opção Fazer o roteamento de saída pelo Gateway de Agente nas configurações do repositório de dados.
  • Isso vincula as chamadas de ferramentas de saída do mecanismo ao seu gateway de agente regional, garantindo que todas as solicitações do MCP tenham o Agent Identity do app, passem por autorização de tempo de execução usando o IAP e as políticas de acesso unificado (UAP) do IAM e atravessem o anexo de rede do PSC até sua VPC particular.

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

Observe as seguintes propriedades preenchidas pelo servidor na resposta JSON:

  • name: caminho do recurso canônico (projects/${PROJ_NO}/locations/global/collections/default_collection/engines/${GE_APP_ID}).
  • sessionConfig.sessionManagementPolicy: o padrão é "VERTEX_AI_MANAGED", que mantém o estado de conversa multiturno e de chamada de ferramenta na Agent Platform (antiga Vertex AI).
  • observabilityConfig.observabilityEnabled: o padrão é true para métricas de referência. O registro detalhado de comandos e payloads de ferramentas é ativado em uma etapa posterior.

Ativar o provedor de identidade

Ative o Google Identity como o 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 o 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 o 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 assentos 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.

Ativar as configurações de observabilidade

Ao ativar a observabilidade no nível do app Gemini Enterprise (mecanismo), é possível conferir as interações do assistente principal com dados de métricas no Metrics Explorer e correlacionar traces de ponta a ponta no Cloud Trace.

# set observability on engine (ge app)
curl -s -X PATCH "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}?updateMask=observabilityConfig" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "observabilityConfig": {
    "observabilityEnabled": true,
    "sensitiveLoggingEnabled": true
  }
}
EOF

Verificar as configurações de observabilidade

# verify observability is enabled on engine (ge app)
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq '{observabilityConfig: .observabilityConfig}'

Verifique se há "sensitiveLoggingEnabled": true.

Vincular ao gateway de agente

O roteamento do tráfego de saída do Gemini Enterprise pelo Gateway de Agente estabelece uma governança centralizada de confiança zero e um limite de aplicação de segurança para todas as invocações de ferramentas de agentes de IA:

  • Aplicação centralizada de políticas:o Gateway de Agente atua como um proxy inline que avalia solicitações de ferramentas de saída em relação a políticas de autorização e controles de governança antes que o tráfego saia do ambiente do agente.
  • Saída de rede particular:ao vincular o Gemini Enterprise ao Gateway de Agente, as chamadas de ferramentas direcionadas a servidores MCP particulares no Cloud Run são roteadas com segurança pelo Private Service Connect (PSC), ignorando a Internet pública.
  • Capacidade de auditoria unificada:fornece registro de solicitações, telemetria e trilhas de auditoria centralizados em todos os servidores MCP conectados e ferramentas externas.

Ao configurar agentGatewaySetting no app Gemini Enterprise, as chamadas de ferramentas e agentes de saída iniciadas por consultas do usuário final (como chamadas para servidores MCP personalizados importados do Agent Registry e agentes A2A) são encaminhadas automaticamente pelo Gateway de Agente.

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": "projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
    }
  }
}
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 application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq '{name: .name, displayName: .displayName, agentGatewaySetting: .agentGatewaySetting}'

Resposta esperada:

{
  "name": "projects/${PROJ_NO}/locations/${GE_LOCATION}/collections/default_collection/engines/${GE_APP_ID}",
  "displayName": "${GE_APP_DISPLAY_NAME}",
  "agentGatewaySetting": {
    "defaultEgressAgentGateway": {
      "name": "projects/${PROJ_ID}/locations/${REGION}/agentGateways/${AGW_NAME}"
    }
  }
}

Criar repositório de dados do servidor MCP personalizado

Nesta seção, você vai conectar o servidor MCP ao Gemini Enterprise criando um repositório de dados personalizado do MCP.

Usando a API Discovery Engine, esse é um processo de duas etapas:

  1. Criar (:setUpDataConnector): cria um recurso Collection dedicado (${MCP_NAME}-%timestamp-collection), anexa o DataConnector (custom_mcp) e provisiona o DataStore de apoio (..._mcp_data).
  2. 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 e vincula o DataStore (dataStoreIds) ao seu Engine do Gemini Enterprise.
# fetch mcp server agent registry resource name
export MCP_REGISTRY_URI=$(gcloud agent-registry mcp-servers list \
  --location=${REGION} \
  --project=${PROJ_ID} \
  --filter="displayName:${MCP_NAME}" \
  --format="value(name)")

echo "mcp registry name: ${MCP_REGISTRY_URI}"
echo "mcp url: ${MCP_URL}"

Criar conector de dados

# create custom mcp data connector from agent registry and link to engine
curl -s -X POST "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}:setUpDataConnector" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "collectionId": "${MCP_NAME}-$(date +%s)-collection",
  "collectionDisplayName": "${MCP_NAME}-collection",
  "dataConnector": {
    "dataSource": "custom_mcp",
    "dataSourceVersion": 1,
    "params": {
      "oauth_access_token": "unused"
    },
    "refreshInterval": "86400s",
    "entities": [
      {
        "entityName": "mcp_data"
      }
    ],
    "connectorModes": [
      "FEDERATED"
    ],
    "actionConfig": {
      "isActionConfigured": true,
      "createBapConnection": true,
      "actionParams": {
        "auth_type": "NO_AUTH",
        "instance_uri": "${MCP_URL}",
        "mcp_server_source": "REGISTRY_MCP",
        "registry_mcp_server_name": "${MCP_REGISTRY_URI}",
        "mcp_agent_instructions": "MANDATORY MATH & ARITHMETIC AGENT: Always invoke this tool for any mathematical calculation, addition (+), subtraction (-), sum, or difference.",
        "use_agent_gateway_egress": true,
        "agent_gateway_engine": "projects/${PROJ_ID}/locations/global/collections/default_collection/engines/${GE_APP_ID}"
      }
    }
  }
}
EOF

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:

# show data connector details
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections/${GE_COLLECTION_ID}/dataConnector" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq '{name, state, actionState, connectorModes, bapConfig, registry_mcp_server_name: .actionConfig.actionParams.registry_mcp_server_name}'

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
curl -s -X PATCH "https://discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/global/collections/${GE_COLLECTION_ID}/dataConnector?updateMask=actionConfig" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "name": "projects/${PROJ_ID}/locations/global/collections/${GE_COLLECTION_ID}/dataConnector",
  "actionConfig": {
    "isActionConfigured": true,
    "createBapConnection": true,
    "actionParams": {
      "auth_type": "NO_AUTH",
      "instance_uri": "${MCP_URL}",
      "mcp_server_source": "REGISTRY_MCP",
      "registry_mcp_server_name": "${MCP_REGISTRY_URI}",
      "mcp_agent_instructions": "MANDATORY MATH & ARITHMETIC AGENT: Always invoke this tool for any mathematical calculation, addition (+), subtraction (-), sum, or difference.",
      "use_agent_gateway_egress": true,
      "agent_gateway_engine": "projects/${PROJ_ID}/locations/global/collections/default_collection/engines/${GE_APP_ID}"
    }
  }
}
EOF

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": "collection-math-wizard-_mcp_data".

# show collection details
curl -s "https://${GE_LOCATION}-discoveryengine.googleapis.com/v1alpha/projects/${PROJ_ID}/locations/${GE_LOCATION}/collections" \
  -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  | jq --arg app "${GE_APP_ID}" '.collections[] | select(.dataConnector.actionConfig.actionParams.agent_gateway_engine // "" | endswith($app)) | .dataConnector | {name: .name, state: .state, actionState: .actionState, connectorModes: .connectorModes, actionParams: .actionConfig.actionParams}'

Verifique se há "state": "ACTIVE" com todos os parâmetros preenchidos.

Ações da ferramenta

Ao inspecionar o repositório de dados math-wizard-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 esquema tools/list e ative ou desative manualmente as ferramentas individuais (add e subtract) na interface.
  • Importação do Agent Registry (fluxo de trabalho REGISTRY_MCP usado neste codelab): quando você importa um servidor MCP do Agent Registry, ele serve como a fonte oficial de verdade 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 durante o tempo de execução pelo 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 app Gemini Enterprise. Em seguida, vamos para a seção Validar.

8. Validar

Nesta seção, você vai acionar chamadas de ferramentas MCP ativas no web app do Gemini Enterprise e rastrear o fluxo de solicitações no Gateway de Agente, no Cloud DNS, no firewall da VPC e nos registros do Cloud Run. Em seguida, restrinja a política de acesso unificado do IAM para permitir subtract e bloquear add, verificando a aplicação de confiança zero no gateway.

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 application-default print-access-token)" \
  -H "X-Goog-User-Project: ${PROJ_ID}" \
  -H "Content-Type: application/json" \
  | jq -r '.configId')

export GE_APP_USER_URL="https://vertexaisearch.cloud.google.com/home/cid/${GE_WIDGET_ID}"

echo "app user url: ${GE_APP_USER_URL}"

Siga o link para abrir a interface de chat do app da Web do Gemini Enterprise no navegador e clique em Começar.

Testar consultas do agente no chat

Na interface de chat, clique no ícone de peça de quebra-cabeça em Conectores na parte de baixo da caixa de chat para confirmar se o conector de dados math-wizard-collection está ativado. Um botão de alternância vai aparecer (colorido).

Teste as seguintes consultas:

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

Verifique se o assistente retorna as respostas corretas e mostra um selo de citação de ação interativo (como Math Calculation (8s) 🤖 Agentgateway Agent) abaixo de cada resposta, confirmando que a ferramenta foi executada.

Inspecionar registros no Cloud Logging

Verifique se o Gemini Enterprise roteou as chamadas de função pelo Gateway de Agente e pela rede VPC privada inspecionando os registros no Cloud Logging.

1. Verificar a autorização do Gateway de Agente e do IAP

Confirme se o Gateway de Agente interceptou a solicitação, resolveu o destino no Agent Registry, delegou a autorização ao IAP e permitiu a chamada de ferramenta:

# show agent gateway logs
gcloud logging read 'resource.type="networkservices.googleapis.com/Gateway"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="table( \
    timestamp.date(tz=LOCAL):label=TIMESTAMP, \
    httpRequest.status:label=STATUS, \
    httpRequest.serverIp:label=SERVER_IP, \
    jsonPayload.agentGatewayInfo.mcpInfo.method:label=MCP_METHOD, \
    jsonPayload.agentGatewayInfo.mcpInfo.parameter:label=TOOL, \
    jsonPayload.authzPolicyInfo.result:label=AUTHZ, \
    jsonPayload.agentGatewayInfo.agentRegistryResource.basename():label=REGISTRY_MCP
  )"

Verifique se a saída contém:

  • STATUS: 200 (execução bem-sucedida) e 202 (handshake notifications/initialized).
  • SERVER_IP: IP do endpoint PSC das APIs do Google (172.16.20.20:443).
  • MCP_METHOD e TOOL: a sequência de protocolo do MCP (notifications/initialized, tools/list e tools/call com add ou subtract).
  • AUTHZ: ALLOWED (saída permitida de autorização do IAP).
  • REGISTRY_MCP: ID do recurso do Agent Registry resolvido (agentregistry-...).

2. Verificar o trânsito de DNS e firewall

Confirme se o Cloud DNS resolveu o nome do host para o endpoint do PSC e se o firewall permitiu o tráfego da interface do Gateway de Agente:

# show dns logs
gcloud logging read 'resource.type="dns_query"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="table( \
    timestamp.date(tz=LOCAL):label=TIMESTAMP, \
    jsonPayload.queryName:label=QUERY_NAME, \
    jsonPayload.queryType:label=TYPE, \
    jsonPayload.responseCode:label=RCODE, \
    jsonPayload.rdata:label=RDATA
  )"
# show firewall logs
gcloud logging read 'logName:"compute.googleapis.com%2Ffirewall"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="table( \
    timestamp.date(tz=LOCAL):label=TIMESTAMP, \
    jsonPayload.connection.src_ip:label=SRC_IP, \
    jsonPayload.connection.dest_ip:label=DEST_IP, \
    jsonPayload.connection.dest_port:label=PORT, \
    jsonPayload.rule_details.reference.basename():label=RULE, \
    jsonPayload.disposition:label=DISPOSITION
  )"

Verifique os seguintes valores:

  • DNS QUERY_NAME e RDATA: resolve math-wizard-...run.app. (registro A, NOERROR) para 172.16.20.20.
  • Firewall SRC_IP e DEST_IP: 192.168.10.2 (IP da interface do PSC do Gateway de Agente) para 172.16.20.20:443.
  • Firewall RULE e DISPOSITION: firewallPolicy:fw-policy-... corresponde a ALLOWED.

3. Verificar a execução da ferramenta do Cloud Run

Confirme se o contêiner do Cloud Run recebeu e processou a chamada de função:

# show cloud run logs
gcloud logging read 'resource.type="cloud_run_revision"
  AND textPayload:"Tool:"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="value(timestamp.date(tz=LOCAL), textPayload)"

Verifique se textPayload mostra entradas de execução de ferramentas (por exemplo, >>> 🛠️ Tool: 'subtract' called with numbers '[x]' and '[y]').

Testar a aplicação da política de privilégio mínimo

Na política inicial de acesso do IAM, qualquer método ou ferramenta era permitido, desde que o destino estivesse registrado (destination.is_registered == true). Nesta etapa, atualize a política para aplicar o princípio de menor privilégio, permitindo apenas a ferramenta subtract e bloqueando add.

Atualizar política de acesso do IAM

Ao restringir a execução de ferramentas do MCP, use um padrão de duas regras:

  1. Regra 1 (descoberta e handshake do MCP): permite métodos de ciclo de vida do MCP que não são de chamada de ferramenta (destination.is_registered == true e destination.agent_registry.mcp_server.method != 'tools/call'). Como o Gemini Enterprise negocia a configuração e a descoberta de fluxos (initialize, notifications/initialized, tools/list) antes de invocar uma ferramenta, e destination.agent_registry.mcp_server.tool.name só é preenchido durante tools/call, a Regra 1 é necessária para manter a inicialização da sessão e a descoberta do catálogo funcionando.
  2. Regra 2 (restrição no nível da ferramenta): restringe a execução de tools/call para que apenas a ferramenta subtract seja permitida (destination.is_registered == true, destination.agent_registry.mcp_server.method == 'tools/call' e destination.agent_registry.mcp_server.tool.name == 'subtract').

Atualize o arquivo de manifesto da regra da política de acesso com as duas regras:

# create access policy rule file (update: allow subtract only)
cat > cfg/${UAP_POLICY_NAME}-rule-update.json << EOF
[
  {
    "description": "allow ge assistant to any registered endpoint to perform mcp discovery and handshake",
    "effect": "ALLOW",
    "principals": [
      "principal://${TRUST_DOMAIN}/resources/discoveryengine/projects/${PROJ_NO}/locations/global/engines/${GE_APP_ID}/assistants/default_assistant/agents/default/core_assistant"
    ],
    "operation": {
      "permissions": [
        "iap.googleapis.com/resources.egressViaIAP"
      ]
    },
    "conditions": {
      "iap.googleapis.com": {
        "expression": \
        "destination.is_registered == true && \
         destination.agent_registry.mcp_server.method != 'tools/call'"
      }
    }
  },
  {
    "description": "allow ge assistant to any registered mcp server with tool call subtract",
    "effect": "ALLOW",
    "principals": [
      "principal://${TRUST_DOMAIN}/resources/discoveryengine/projects/${PROJ_NO}/locations/global/engines/${GE_APP_ID}/assistants/default_assistant/agents/default/core_assistant"
    ],
    "operation": {
      "permissions": [
        "iap.googleapis.com/resources.egressViaIAP"
      ]
    },
    "conditions": {
      "iap.googleapis.com": {
        "expression": \
        "destination.is_registered == true && \
         destination.agent_registry.mcp_server.method == 'tools/call' && \
         destination.agent_registry.mcp_server.tool.name == 'subtract'"
      }
    }
  }
]
EOF

Aplique as regras atualizadas à política de acesso do IAM:

# update iam access policy
gcloud iam access-policies update ${UAP_POLICY_NAME} \
  --details-rules=cfg/${UAP_POLICY_NAME}-rule-update.json \
  --project=${PROJ_ID} \
  --location=global

Verificar a política de acesso do IAM

Verifique se a nova política de acesso do IAM foi aplicada e se apenas a ferramenta de subtração está permitida:

# show iam access policy details
gcloud iam access-policies describe ${UAP_POLICY_NAME} \
  --project=${PROJ_ID} \
  --location=global \
  --flatten="details.rules[]" \
  --format="table( \
    details.rules.principals[0].scope(engines).sub('assistants/default_assistant/agents/default', '...'):label=PRINCIPAL, \
    details.rules.effect:label=EFFECT, \
    details.rules.conditions.'iap.googleapis.com'.expression.sub('\s*&&\s*', '\n&& ').sub('\s*\|\|\s*', '\n|| '):label=EXPRESSION
  )"

Testar uma chamada de ferramenta proibida

Volte para a interface de chat do web app Gemini Enterprise e tente outra consulta de teste:

what is 100 plus 20?

O assistente tenta invocar add, mas o Gateway de Agente e o IAP avaliam a condição da política do IAM como false e negam a solicitação de saída com HTTP 403 Forbidden. Na interface do chat, você vai notar que o assistente mostra Calculate Sum e gira em 🤖 Agentgateway Agent ... Working on it. enquanto tenta novamente a chamada de ferramenta bloqueada. Esse é o comportamento esperado. Ele confirma que o Gateway de Agente e o IAP estão interceptando e negando ativamente a execução de ferramentas não permitidas no nível da rede.

Reinspecionar registros no Cloud Logging

Confira as entradas de registro do Gateway de Agente e observe as novas entradas 403 correspondentes à chamada de ferramenta add não permitida:

# show agent gateway logs
gcloud logging read 'resource.type="networkservices.googleapis.com/Gateway"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="table( \
    timestamp.date(tz=LOCAL):label=TIMESTAMP, \
    httpRequest.status:label=STATUS, \
    httpRequest.serverIp:label=SERVER_IP, \
    jsonPayload.agentGatewayInfo.mcpInfo.method:label=MCP_METHOD, \
    jsonPayload.agentGatewayInfo.mcpInfo.parameter:label=TOOL, \
    jsonPayload.authzPolicyInfo.result:label=AUTHZ, \
    jsonPayload.agentGatewayInfo.agentRegistryResource.basename():label=REGISTRY_MCP
  )"

Resposta esperada:

TIMESTAMP            STATUS  SERVER_IP         MCP_METHOD                 TOOL  AUTHZ    REGISTRY_MCP
YYYY-MM-DDTHH:MM:SS  403                       tools/call                 add   DENIED   agentregistry-00000000-0000-0000-0012-3456789abcde
YYYY-MM-DDTHH:MM:SS  403
YYYY-MM-DDTHH:MM:SS  202     172.16.20.20:443  notifications/initialized        ALLOWED  agentregistry-00000000-0000-0000-0012-3456789abcde
YYYY-MM-DDTHH:MM:SS          172.16.20.20:443                                   ALLOWED  agentregistry-00000000-0000-0000-0012-3456789abcde
YYYY-MM-DDTHH:MM:SS  200     172.16.20.20:443  initialize                       ALLOWED  agentregistry-00000000-0000-0000-0012-3456789abcde

Verifique se a solicitação adicional nunca chegou ao back-end do Cloud Run:

# show cloud run logs
gcloud logging read 'resource.type="cloud_run_revision"
  AND textPayload:"Tool:"' \
  --project=${PROJ_ID} \
  --limit=5 \
  --format="value(timestamp.date(tz=LOCAL), textPayload)"

O comando não retorna novas entradas, confirmando que o Gateway de Agente aplicou a política de acesso do IAM.

Isso conclui a parte de validação. Em seguida, vamos para a seção Limpeza.

9. 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"}}'

Remover componentes do servidor MCP

# delete agent registry service
gcloud -q agent-registry services delete ${MCP_NAME} \
  --location=${REGION} \
  --project=${PROJ_ID}

# delete cloud run service, source-deploy artifact registry repo, and staging bucket
gcloud -q run services delete ${MCP_NAME} \
  --region=${REGION} \
  --project=${PROJ_ID}

gcloud -q artifacts repositories delete cloud-run-source-deploy \
  --location=${REGION} \
  --project=${PROJ_ID}

gcloud -q storage rm --recursive gs://run-sources-${PROJ_ID}-${REGION} \
  --project=${PROJ_ID}

Remover o Gateway de Agente e as políticas de acesso do IAM

# delete gateway authorization policy, iap extension, and agent gateway
gcloud -q network-security authz-policies delete ${AGW_NAME}-authz-policy-iap \
  --location=${REGION} \
  --project=${PROJ_ID}

gcloud -q service-extensions authz-extensions delete ${AGW_NAME}-svc-ext-authz-iap \
  --location=${REGION} \
  --project=${PROJ_ID}

gcloud -q network-services agent-gateways delete ${AGW_NAME} \
  --location=${REGION} \
  --project=${PROJ_ID}
# delete iam policy binding and access policy
gcloud -q iam policy-bindings delete ${UAP_BINDING_NAME} \
  --location=global \
  --project=${PROJ_ID}

gcloud -q iam access-policies delete ${UAP_POLICY_NAME} \
  --location=global \
  --project=${PROJ_ID}

Remover componentes de DNS e firewall

# delete dns record set, managed zone, and policy
gcloud -q dns record-sets delete "*.run.app." \
  --type=A \
  --zone=priv-zone-run \
  --project=${PROJ_ID}

gcloud -q dns managed-zones delete priv-zone-run \
  --project=${PROJ_ID}

gcloud -q dns policies update dns-policy-${SLUG} \
  --networks="" \
  --project=${PROJ_ID}

gcloud -q dns policies delete dns-policy-${SLUG} \
  --project=${PROJ_ID}
# delete firewall policy association, rule, and policy
gcloud -q compute network-firewall-policies associations delete \
  --name=fw-policy-bind-${SLUG} \
  --firewall-policy=fw-policy-${SLUG} \
  --global-firewall-policy \
  --project=${PROJ_ID}

gcloud -q compute network-firewall-policies rules delete 1001 \
  --firewall-policy=fw-policy-${SLUG} \
  --global-firewall-policy \
  --project=${PROJ_ID}

gcloud -q compute network-firewall-policies delete fw-policy-${SLUG} \
  --global \
  --project=${PROJ_ID}

Remover componentes de rede VPC e PSC

# delete psc forwarding rule and internal ip address
gcloud -q compute forwarding-rules delete psc2gapis \
  --global \
  --project=${PROJ_ID}

gcloud -q compute addresses delete ip-psc2gapis \
  --global \
  --project=${PROJ_ID}
# delete psc network attachment, subnet, and vpc network
gcloud -q compute network-attachments delete psc-na-${REGION}-agw \
  --region=${REGION} \
  --project=${PROJ_ID}

gcloud -q compute networks subnets delete subnet-${REGION}-agw \
  --region=${REGION} \
  --project=${PROJ_ID}

gcloud -q compute networks delete vnet-${SLUG} \
  --project=${PROJ_ID}

Remover substituições de políticas da organização e arquivos locais

# delete project-level organization policy overrides
gcloud -q org-policies delete discoveryengine.managed.disableCustomMcpServerConnector --project=${PROJ_ID}
gcloud -q org-policies delete iam.managed.disableAccessPolicyBinding --project=${PROJ_ID}
# remove local project files
rm -rf cfg math-wizard

Isso conclui a revisão dos dados. Em seguida, vamos para a Conclusão.

10. 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 privado:

  • Servidor MCP personalizado e Agent Registry:implantei um serviço FastMCP particular no Cloud Run (--ingress=internal) e registrei o endpoint e o esquema de ferramentas (add e subtract) no Agent Registry.
  • Integração do Gemini Enterprise:provisionamos um app Gemini Enterprise, vinculamos o tráfego de ferramentas de saída ao Gateway de Agente e anexamos o servidor MCP registrado como um REGISTRY_MCP conector de dados.
  • Saída de VPC privada e governança de confiança zero:execução de ferramentas roteadas de maneira privada pelo PSC (172.16.20.20) e privilégio mínimo no nível da ferramenta usando o IAP e as políticas de acesso unificado do IAM (destination.agent_registry.*).

cosmopup

O Cosmpup acha que os codelabs são incríveis!

O que vem em seguida?

Use este formulário de feedback para enviar comentários, dúvidas ou correções.

Valeu!