Criar e implantar um agente de passaporte de animais de estimação no Cloud Run

1. Visão geral

Neste codelab, você vai aprender a implantar o app Pet Passport, um agente de IA que usa o Protocolo de Contexto de Modelo (MCP) para combinar análise de dados e serviços de localização.

O app ajuda os usuários a planejar um dia perfeito com o cachorro com base na popularidade da raça na cidade de Nova York. O agente usa uma cadeia de raciocínio "Macro-to-Micro":

  1. Descoberta estratégica (BigQuery): identifica o CEP de Nova York com a maior população de uma raça específica.
  2. Execução local (Maps): usa esse CEP como uma tendência de local para encontrar "cafés que aceitam animais de estimação" e "parques para cachorros".
  3. Geração de itinerários:combina os dados para criar um itinerário de "Passaporte do animal de estimação" com links e imagens clicáveis.

O agente é criado usando o framework google-adk e com tecnologia do Gemini.

Observação: o código completo do projeto, incluindo a interface do usuário do front-end, está disponível no GitHub. Neste codelab, vamos nos concentrar na lógica principal do agente e na configuração da infraestrutura.

2. Configuração e requisitos

Primeiro, verifique se o ambiente de desenvolvimento está configurado corretamente.

1. Autenticar com o Google Cloud

Defina seu projeto na nuvem ativo do Google Cloud e faça a autenticação. Isso é necessário para que o agente acesse o BigQuery e outros serviços.

gcloud config set project [YOUR-PROJECT-ID]
gcloud auth application-default login --project [YOUR-PROJECT-ID]

Observação: se você encontrar erros sobre um projeto diferente durante a autenticação, desative o projeto de cota e defina-o manualmente para contornar o problema:

gcloud auth application-default login --disable-quota-project
gcloud auth application-default set-quota-project [YOUR-PROJECT-ID]

2. Requisitos de software

Você precisa ter o seguinte software instalado na sua máquina local:

  • Python (é necessário ter a versão 3.13 ou mais recente)
  • Git (para fazer o download do repositório)

Baixar o repositório

O código deste projeto está disponível no repositório do Google MCP. Clone o repositório e acesse a pasta do projeto:

git clone https://github.com/google/mcp.git
cd examples/petpassport

3. Instalação

Agora que você tem os arquivos, vamos configurar o ambiente Python.

  1. Crie um ambiente virtual:isso mantém as dependências isoladas.
    python3 -m venv .venv
    
  2. Ative o ambiente virtual:
    • No Linux/macOS:
      source .venv/bin/activate
      
    • No Windows:
      .venv\Scripts\activate
      
  3. Instale as dependências:
    pip install google-adk==1.28.0 python-dotenv google-genai pillow uvicorn
    

Ativar as APIs do Cloud

Ativar as APIs a seguir no projeto:

gcloud services enable \
  bigquery.googleapis.com \
  aiplatform.googleapis.com \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com \
  run.googleapis.com \
  storage.googleapis.com

Escolha uma região

Defina a região como uma variável de ambiente no shell:

export REGION=us-central1

4. Adquirir chaves de API

Para usar os serviços do Maps e do Gemini, você precisa adquirir chaves de API e armazená-las em um arquivo .env na raiz do projeto.

1. Chave da API Google Maps

  1. Acesse o Console do Google Cloud.
  2. Acesse APIs e serviços > Credenciais.
  3. Clique em Criar credenciais > Chave de API.
  4. Copie a chave gerada e adicione-a ao arquivo .env como MAPS_API_KEY=[YOUR_KEY].
  5. (Recomendado) Restrinja a chave para permitir apenas as APIs Maps usadas pelo servidor MCP.

2. Chave da API Gemini (AI Studio)

  1. Acesse o Google AI Studio.
  2. Clique em Receber chave de API ou navegue até a seção "Chaves de API".
  3. Clique em Criar chave de API.
  4. Copie a chave e adicione-a ao arquivo .env como GEMINI_API_KEY=[YOUR_KEY].

5. Instalar dependências

Crie um arquivo requirements.txt na pasta petpassport/:

google-adk==1.28.0
python-dotenv
google-genai
pillow

6. Autenticar servidores MCP

Esse aplicativo depende de servidores do Protocolo de Contexto de Modelo (MCP) para interagir com o Google Maps e o BigQuery. Para autenticar esses servidores, configure as variáveis de ambiente e os cabeçalhos adequados.

  1. MCP do Google Maps:exige uma chave de API Maps válida transmitida no cabeçalho X-Goog-Api-Key.
  2. MCP do BigQuery:exige credenciais do OAuth com acesso ao serviço do BigQuery. O agente usa a conta de serviço de computação padrão ao ser executado no Cloud Run ou suas credenciais locais ao ser executado localmente.

Fornecemos um script de configuração setup/setup_env.sh no repositório que ajuda a configurar essas variáveis no arquivo .env.

7. Como criar a tabela do BigQuery

Antes que o agente possa consultar os dados de licenças de cachorros, precisamos criar o conjunto de dados e a tabela no BigQuery e carregar os dados.

Fornecemos um script de configuração setup/setup_bigquery.sh que executa as seguintes etapas:

  1. Cria um bucket do Cloud Storage chamado pet-passport-data-[PROJECT_ID] para armazenar os dados brutos.
  2. Faz o download do conjunto de dados público de licenciamento de cães de Nova York (CSV).
  3. Faz upload do CSV para o bucket.
  4. Cria um conjunto de dados do BigQuery chamado nyc_dogs.
  5. Carrega os dados do bucket em uma tabela chamada licenses no conjunto de dados.

Para executar o script de configuração, execute o seguinte comando no terminal:

bash setup/setup_bigquery.sh

8. Conectar-se a servidores MCP

Uma parte fundamental desse app é usar o MCP para se conectar a dados e serviços. Nesta seção, você vai configurar os conjuntos de ferramentas do MCP para o BigQuery e o Google Maps em um arquivo chamado petpassport/tools.py.

Preencher o código de tools.py

Confira a implementação completa de tools.py, incluindo conjuntos de ferramentas MCP e ferramentas personalizadas para persistência de imagens e dados. Otimizamos esse código para reduzir redundâncias movendo a resolução de intervalos para o nível do módulo:

import os
import dotenv
import google.auth
import time
import datetime
from google.cloud import storage
from PIL import Image
from google import genai
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams 

MAPS_MCP_URL = "https://mapstools.googleapis.com/mcp" 
BIGQUERY_MCP_URL = "https://bigquery.googleapis.com/mcp" 

PROJECT_ID = os.getenv('GOOGLE_CLOUD_PROJECT', 'project_not_set')
BUCKET_NAME = f"pet-passport-data-{PROJECT_ID}" 

def get_maps_mcp_toolset():
    dotenv.load_dotenv()
    maps_api_key = os.getenv('MAPS_API_KEY', 'no_api_found')
    
    tools = MCPToolset(
        connection_params=StreamableHTTPConnectionParams(
            url=MAPS_MCP_URL,
            headers={    
                "X-Goog-Api-Key": maps_api_key
            },
            timeout=30.0,          
            sse_read_timeout=300.0
        )
    )
    print("Maps MCP Toolset configured.")
    return tools


def get_bigquery_mcp_toolset():   
    credentials, project_id = google.auth.default(
            scopes=["https://www.googleapis.com/auth/bigquery"]
    )

    credentials.refresh(google.auth.transport.requests.Request())
    oauth_token = credentials.token
        
    HEADERS_WITH_OAUTH = {
        "Authorization": f"Bearer {oauth_token}",
        "x-goog-user-project": project_id
    }

    tools = MCPToolset(
        connection_params=StreamableHTTPConnectionParams(
            url=BIGQUERY_MCP_URL,
            headers=HEADERS_WITH_OAUTH,
            timeout=30.0,          
            sse_read_timeout=300.0
        )
    )
    print("BigQuery MCP Toolset configured.")
    return tools

def generate_pet_passport_photo(prompt: str, image_path: str = None) -> str:
    """Generates an image using gemini-3.1-flash-image-preview based on a prompt and a reference image."""
    client = genai.Client()
    output_path = f"/tmp/pet_passport_{int(time.time())}.png"
    
    try:
        image = Image.open(image_path)
        response = client.models.generate_content(
            model="gemini-3.1-flash-image-preview",
            contents=[prompt, image],
        )
        
        for part in response.parts:
            if part.inline_data is not None:
                generated_image = part.as_image()
                generated_image.save(output_path)
                
                # Upload to GCS and generate signed URL
                try:
                    storage_client = storage.Client()
                    bucket = storage_client.bucket(BUCKET_NAME)
                    blob_name = os.path.basename(output_path)
                    blob = bucket.blob(blob_name)
                    
                    blob.upload_from_filename(output_path)
                    
                    url = blob.generate_signed_url(
                        version="v4",
                        expiration=datetime.timedelta(hours=24),
                        method="GET",
                    )
                    return url
                except Exception as e:
                    print(f"Error uploading image to GCS: {e}")
                    return output_path
                
        raise ValueError("No image was returned by the model.")
    except Exception as e:
        print(f"Error generating image: {e}")
        raise

def save_pet_passport(user_id: str, breed: str, postal_code: str, route_details: str, image_paths: list[str] = None) -> str:
    """Appends the generated itinerary to the user's history in GCS."""
    try:
        storage_client = storage.Client()
        bucket = storage_client.bucket(BUCKET_NAME)
        blob = bucket.blob(f"user-{user_id}.json")
        
        # Download existing or start fresh
        # ... (Implementation details hidden for brevity) ...
        return "Success"
    except Exception as e:
        print(f"Error saving path: {e}")
        raise

Explicação do código: tools.py

  • get_maps_mcp_toolset e get_bigquery_mcp_toolset configuram os clientes do MCP com endpoints e cabeçalhos de autenticação corretos.
  • O generate_pet_passport_photo usa o Gemini para criar uma cena e faz upload do resultado para o Google Cloud Storage, retornando um URL assinado para o front-end para sobreviver a reinicializações do servidor.

9. Como criar o agente

Com as ferramentas configuradas, é hora de criar o "cérebro" do agente. Você vai usar o Kit de Desenvolvimento de Agente (ADK) para criar um agente em um arquivo chamado petpassport/agent.py.

Preencher o código de agent.py

Confira a implementação completa de agent.py, em que definimos o agente e as instruções dele:

import os
import dotenv
import tools
from google.adk.agents import LlmAgent

dotenv.load_dotenv()

PROJECT_ID = os.getenv('GOOGLE_CLOUD_PROJECT', 'project_not_set')

maps_toolset = tools.get_maps_mcp_toolset()
bigquery_toolset = tools.get_bigquery_mcp_toolset()

root_agent = LlmAgent(
    model='gemini-2.5-pro',
    name='root_agent',
    instruction=f"""
        You are the Pet Passport Agent. Your goal is to help users find a fun walking route for their dog in NYC.
        
        When given a breed and a postal code, follow this flow:
        1. **Strategic Discovery:** Use BigQuery to find the most popular neighborhood for that breed in NYC.
        2. **Local Execution:** Use Maps to build a walking route with specific places (parks, cafes) in that area.
        
        **NO DIRECTIONS LINKS:** You must NOT include a Google Maps directions link (e.g., `https://www.google.com/maps/dir/...`) in your final response. Only provide links to individual places.
        
        After generating the itinerary, you MUST call the `save_pet_passport` tool to save this path to the user's profile. Pass a clean summary of the itinerary as `route_details`. The summary should include details (like rating, description from maps).
    """,
    tools=[maps_toolset, bigquery_toolset, tools.generate_pet_passport_photo, tools.save_pet_passport]
)

Explicação do código: agent.py

  • Importamos tools diretamente (estrutura simplificada) para oferecer suporte ao ambiente de contêiner.
  • O agente é inicializado com gemini-2.5-pro.
  • As instruções definem uma cadeia de raciocínio estrita de várias etapas (primeiro o BigQuery e depois o Maps) e proíbem estritamente a alucinação ou a renderização de rotas a pé que levam a confusão.

10. Como executar o aplicativo localmente

Antes de implantar no Cloud Run, é recomendável testar o aplicativo localmente.

  1. Verifique se você está no diretório do projeto:
    cd examples/petpassport
    
  2. Inicie o servidor FastAPI:usamos uvicorn para executar o app. O ponto de entrada é main.py na pasta petpassport.
    uvicorn petpassport.main:app --reload
    
  3. Abra a interface:acesse http://127.0.0.1:8000/ui/ no navegador para interagir com a interface do Pet Passport.

11. Como implantar no Cloud Run

Com o agente pronto, é hora de implantá-lo no Cloud Run. Usamos o comando gcloud padrão diretamente para manter o controle estrito sobre o ambiente do contêiner.

No diretório do projeto, execute o seguinte comando:

gcloud run deploy petpassport \
  --source petpassport \
  --region $REGION \
  --allow-unauthenticated \
  --labels dev-tutorial=google-mcp

Configurar variáveis de ambiente

Após a implantação, acesse o serviço do Cloud Run no console do Google Cloud e defina as seguintes variáveis de ambiente na guia Variáveis e secrets:

  • MAPS_API_KEY: sua chave de API Google Maps.
  • GOOGLE_CLOUD_PROJECT: o ID do projeto.
  • PROJECT_ID: seu ID do projeto (redundância compatível com módulos legados).

12. Exemplos de comandos

Tente interagir com o agente implantado usando estes comandos:

  1. Padrão: "Quero passear com meu Golden Retriever em Nova York perto de 10021. Encontre um trajeto para nós que tenha um café."
  2. Raça diferente: "Tenho um buldogue francês e moramos no Upper West Side (perto de 10024). Sugira uma caminhada curta que pare em um parque para cachorros famoso."
  3. Com imagem: (faça upload de uma foto do seu cachorro) "Aqui está uma foto do meu Corgi! Estamos perto de 10013. Planeje um dia perfeito para nós."

13. Limpar

Para evitar cobranças pelos recursos usados neste tutorial:

  • Exclua o serviço do Cloud Run: gcloud run services delete petpassport --region=$REGION
  • Exclua o bucket do GCS: gcloud storage rm -r gs://pet-passport-data-$PROJECT_ID