Comienza a usar MCP y A2A con ADK

1. Descripción general

Los agentes de IA están ganando popularidad rápidamente, ya que revolucionan la automatización de tareas y la toma de decisiones con su capacidad para operar de forma autónoma, aprender y, además, interactuar con su entorno para lograr objetivos.

Este codelab te ayudará a comenzar creando un sistema multiagente de extremo a extremo. Crearás un servidor de MCP de monedas, un agente de monedas que consuma el servidor de MCP y se exponga a través del protocolo Agent2Agent (A2A), un agente de viajes con un subagente de clima en proceso que consuma el agente de monedas a través de A2A y, por último, implementarás todos los servicios en Cloud Run.

Arquitectura

Tecnologías principales

Protocolo de contexto del modelo (MCP)

El Protocolo de contexto del modelo (MCP) es un protocolo abierto que estandariza la forma en que las aplicaciones proporcionan contexto y herramientas a los LLM. Piensa en el MCP como un puerto USB-C para aplicaciones de IA: proporciona una forma estandarizada de conectar modelos de IA a fuentes de datos, APIs y herramientas externas.

En este codelab, el currency_mcp_server expone una herramienta de get_exchange_rate a través de HTTP transmisible (/mcp), respaldada por la API de Frankfurter pública.

Kit de desarrollo de agentes (ADK)

El Kit de desarrollo de agentes (ADK) es un framework de organización flexible para desarrollar y, luego, implementar agentes de IA. El ADK es independiente del modelo y de la implementación, y se creó para ser compatible con otros frameworks. El ADK hace que el desarrollo de agentes se parezca a la ingeniería de software estándar, lo que facilita la creación, prueba y organización de flujos de trabajo de agentes complejos.

El ADK controla las conversaciones de los usuarios, entrega la IU web interactiva, se conecta a las herramientas de MCP a través de McpToolset y administra las comunicaciones de A2A.

Protocolo Agent2Agent (A2A)

El protocolo Agent2Agent (A2A) es un estándar abierto diseñado para permitir la comunicación y la colaboración entre agentes de IA. Así como MCP estandariza las conexiones entre agentes y herramientas, A2A estandariza la colaboración entre agentes. En un mundo en el que los agentes se crean en diversos frameworks, entornos de hosting y organizaciones, A2A proporciona un lenguaje común para el descubrimiento y la delegación de tareas.

El ADK expone currency_agent como un servicio de A2A (to_a2a) y permite que travel_agent lo consuma de forma remota como un AgentTool (RemoteA2aAgent).

Subagentes locales frente a agentes A2A remotos

Esta arquitectura destaca un patrón crucial en el diseño multiagente:

  • Herramienta de agente local (weather_agent): Se ejecuta en proceso dentro del organizador como un AgentTool, sin latencia de red ni sobrecarga de serialización de protocolos.
  • Herramienta de agente remoto (currency_agent): Se ejecuta como un microservicio independiente, al que se llama a través de la red con el protocolo A2A.

Qué aprenderás

  • Cómo crear y probar un servidor de MCP local con FastMCP a través de HTTP transmitible
  • Cómo crear un agente con el ADK que use herramientas de MCP (McpToolset)
  • Cómo exponer un agente del ADK como un servidor A2A (to_a2a)
  • Cómo probar un servidor A2A con el cliente de Python de A2A (a2a.client)
  • Cómo crear un agente de organización que combine herramientas de agentes secundarios locales con agentes A2A remotos
  • Cómo ejecutar y probar el sistema multiagente completo de forma local con la IU web del ADK
  • Cómo alojar en contenedores y, luego, implementar los tres componentes en Google Cloud Run

Requisitos

  • Un navegador, como Chrome
  • Un proyecto de Google Cloud con facturación habilitada.

2. Antes de comenzar

Crea un proyecto

Si no tienes un proyecto de Google Cloud, crea uno.

En la página del selector de proyectos de la consola de Google Cloud, selecciona o crea un proyecto de Google Cloud.

También asegúrate de que la facturación esté habilitada para tu proyecto de Cloud. Obtén información para verificar si la facturación está habilitada en un proyecto.

Activar Cloud Shell

Google Cloud Shell es un entorno de desarrollo interactivo basado en el navegador que se proporciona directamente en la consola de Google Cloud. Es la forma más sencilla de comenzar a usar Google Cloud sin necesidad de instalar herramientas de forma local.

Activa Cloud Shell haciendo clic en este vínculo. Puedes alternar entre la terminal de Cloud Shell (para ejecutar comandos en la nube) y el editor (para ver archivos) haciendo clic en el botón correspondiente en Cloud Shell.

Una vez que te conectes a Cloud Shell, verifica que te hayas autenticado:

gcloud auth list

Confirma que el comando gcloud conozca tu proyecto:

gcloud config list project

Determina tu ID del proyecto:

export PROJECT_ID=<YOUR_GOOGLE_CLOUD_PROJECT_ID>
gcloud config set project $PROJECT_ID

Habilita las API de Cloud

Habilita las APIs necesarias para Cloud Run, Cloud Build, Artifact Registry y Vertex AI:

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

Obtén el código

Clona el repositorio y navega al directorio python:

git clone https://github.com/meteatamel/getting-started-mcp-a2a-adk.git
cd getting-started-mcp-a2a-adk/python

Instala dependencias con uv

uv es un administrador de proyectos y paquetes de Python rápido. Está preinstalada en Cloud Shell. Si se ejecuta de forma local, puedes instalarlo de la siguiente manera:

# macOS and Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows (PowerShell)
# powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

El directorio de Python está estructurado como un uv unificado.

Workspace. Ejecuta el siguiente comando para instalar todas las dependencias de todos los miembros del espacio de trabajo (currency_mcp_server, currency_agent y travel_agent) en un solo entorno virtual:

uv sync

Configure las variables de entorno

Configura las variables de entorno en un archivo .env en el directorio python:

Opción A: Gemini Enterprise (Google Cloud / Cloud Shell)

echo "GOOGLE_GENAI_USE_ENTERPRISE=TRUE" >> .env \
&& echo "GOOGLE_CLOUD_PROJECT=$PROJECT_ID" >> .env \
&& echo "GOOGLE_CLOUD_LOCATION=global" >> .env

Opción B: Google AI Studio (clave de API local)

Si prefieres usar una clave de API de Google AI Studio, sigue estos pasos:

echo "GOOGLE_API_KEY=<your_api_key_here>"<>>/span>  .env \
&& echo "GOOGLE_GENAI_USE_ENTERPRISE=FALSE" >> .env

3. Crea el servidor de MCP de Currency

Antes de crear tus agentes, primero explorarás el servidor de MCP que expone la herramienta de conversión de moneda.

Un servidor de MCP te permite escribir programas ligeros para exponer capacidades como herramientas. Luego, uno o más agentes pueden acceder a estas herramientas con el Protocolo de contexto del modelo estandarizado.

El paquete de Python FastMCP se puede aprovechar para crear un servidor de MCP que exponga una sola herramienta llamada get_exchange_rate. La herramienta get_exchange_rate llama a la API de Frankfurter para obtener el tipo de cambio actual entre dos monedas.

El código del servidor de MCP se encuentra en currency_mcp_server/server.py:

import asyncio
import logging
import os

import httpx
from fastmcp import FastMCP

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

mcp = FastMCP("Currency MCP Server 💵")


@mcp.tool()
def get_exchange_rate(
    currency_from: str = "USD",
    currency_to: str = "EUR",
    currency_date: str = "latest",
):
    """Use this to get current exchange rate.

    Args:
        currency_from: The currency to convert from (e.g., "USD").
        currency_to: The currency to convert to (e.g., "EUR").
        currency_date: The date for the exchange rate or "latest". Defaults to "latest".

    Returns:
        A dictionary containing the exchange rate data, or an error message if the request fails.
    """
    logger.info(
        f"--- 🛠️ Tool: get_exchange_rate called for converting {currency_from} to {currency_to} ---"
    )
    try:
        response = httpx.get(
            f"https://api.frankfurter.dev/v1/{currency_date}",
            params={"from": currency_from, "to": currency_to},
        )
        response.raise_for_status()

        data = response.json()
        if "rates" not in data:
            logger.error(f"❌ rates not found in response: {data}")
            return {"error": "Invalid API response format."}
        logger.info(f"✅ API response: {data}")
        return data
    except httpx.HTTPError as e:
        logger.error(f"❌ API request failed: {e}")
        return {"error": f"API request failed: {e}"}
    except ValueError:
        logger.error("❌ Invalid JSON response from API")
        return {"error": "Invalid JSON response from API."}


if __name__ == "__main__":
    port = int(os.getenv("PORT", 8080))
    logger.info(f"🚀 MCP server started on port {port}")
    # Could also use 'sse' transport, host="0.0.0.0" required for Cloud Run.
    asyncio.run(
        mcp.run_async(
            transport="http",
            host="0.0.0.0",
            port=port,
        )
    )

Inicia el servidor de MCP de forma local

Inicia el servidor de MCP en tu terminal:

uv run python currency_mcp_server/server.py

El servidor se inicia en el puerto 8080 con el extremo HTTP transmisible disponible en /mcp (http://localhost:8080/mcp).

Prueba el servidor de MCP

Abre una segunda ventana de terminal (deja el servidor de MCP en ejecución en la primera), navega a la carpeta python (cd getting-started-mcp-a2a-adk/python) y ejecuta la secuencia de comandos de prueba:

uv run python currency_mcp_server/test_server.py

La secuencia de comandos de prueba se conecta al extremo de MCP con Client de FastMCP, enumera las herramientas y, luego, invoca get_exchange_rate:

Connecting to MCP server at: http://localhost:8080/mcp
--- 🛠️  Tool found: get_exchange_rate ---
--- 🪛  Calling get_exchange_rate tool for USD to EUR ---
--- ✅  Success: {"amount":1.0,"base":"USD","date":"2026-09-29","rates":{"EUR":0.84919}} ---

¡Genial! Tienes un servidor de MCP en funcionamiento que expone una herramienta de conversión de monedas en tiempo real. Mantén esta terminal abierta para los próximos pasos.

4. Crea el agente de monedas con el ADK

Ahora es momento de crear el agente de monedas con el Kit de desarrollo de agentes (ADK).

El ADK proporciona compatibilidad integrada con las herramientas de MCP a través de la clase McpToolset. El agente de monedas se conecta a nuestro servidor de MCP con StreamableHTTPConnectionParams.

Echa un vistazo a la definición del agente de moneda en currency_agent/agent.py:

import logging
import os
from urllib.parse import urlparse

from dotenv import load_dotenv
from google.adk.agents import LlmAgent
from google.adk.a2a.utils.agent_to_a2a import to_a2a
from google.adk.tools.mcp_tool import McpToolset, StreamableHTTPConnectionParams

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

load_dotenv()

SYSTEM_INSTRUCTION = (
    "You are a specialized assistant for currency conversions. "
    "Your sole purpose is to use the 'get_exchange_rate' tool to answer questions about currency exchange rates. "
    "If the user asks about anything other than currency conversion or exchange rates, "
    "politely state that you cannot help with that topic and can only assist with currency-related queries. "
    "Do not attempt to answer unrelated questions or use tools for other purposes."
)

mcp_server_url = os.getenv("MCP_SERVER_URL", "http://localhost:8080/mcp")
if not mcp_server_url.endswith("/mcp"):
    mcp_server_url = f"{mcp_server_url.rstrip('/')}/mcp"

logger.info(f"--- 🔧 Loading MCP tools from MCP Server at {mcp_server_url}... ---")
logger.info("--- 🤖 Creating ADK Currency Agent... ---")

root_agent = LlmAgent(
    model="gemini-3.8-flash",
    name="currency_agent",
    description="An agent that can help with currency conversions",
    instruction=SYSTEM_INSTRUCTION,
    tools=[
        McpToolset(
            connection_params=StreamableHTTPConnectionParams(
                url=mcp_server_url
            )
        )
    ],
)

Observa cómo McpToolset descubre y carga automáticamente la herramienta get_exchange_rate directamente desde el servidor de MCP en ejecución a través de HTTP.

Prueba el agente de monedas con la IU web del ADK

Puedes probar el agente de forma aislada con la interfaz web de desarrollo del ADK. En la segunda terminal, ejecuta lo siguiente:

uv run adk web --allow_origins "*" currency_agent

Abre tu navegador en http://localhost:8000 (o haz clic en Vista previa en la Web en Cloud Shell).

Agente de monedas de ADK Web

Pregúntale al agente:

"¿Cuánto es USD 250 en EUR?"

Verás que el agente invoca la herramienta de MCP get_exchange_rate y devuelve el importe convertido. Detén el proceso adk web con Ctrl+C antes de continuar.

5. Protocolo Agent2Agent (A2A)

El protocolo Agent2Agent (A2A) es un estándar abierto diseñado para permitir la comunicación y la colaboración entre agentes de IA.

En los sistemas multiagente modernos, los agentes suelen crearse con diferentes frameworks (ADK, LangChain, CrewAI, AutoGen) y se implementan en diferentes infraestructuras. La comunicación A2A elimina estos silos definiendo un contrato de comunicación estandarizado.

Protocolo A2A

Conceptos clave de A2A

  • Detección de agentes (tarjeta de agente): Cada agente compatible con A2A anuncia sus capacidades, los modos de E/S admitidos, los requisitos de autenticación y las habilidades a través de un archivo JSON estándar alojado en /.well-known/agent-card.json.
  • Habilidades de agentes (AgentSkill): Son capacidades o herramientas específicas que el agente puede ejecutar. Otros agentes leen estas habilidades para decidir cuándo delegar tareas.
  • Comunicación JSON-RPC: Los agentes intercambian mensajes, tareas y artefactos estructurados a través de transportes estándar, como HTTP JSON-RPC 2.0.

Tarjeta de agente A2A

En el siguiente paso, expondrás nuestro agente de monedas del ADK como un servidor A2A para que otros agentes puedan descubrirlo y delegarle tareas de conversión de monedas.

6. Exponer el agente de monedas como un servidor A2A

El ADK facilita la conversión de cualquier LlmAgent en un servidor compatible con A2A con la función de utilidad to_a2a().

Revisa la parte inferior de currency_agent/agent.py:

# Make the agent A2A-compatible
PORT = int(os.getenv("PORT", 8081))
AGENT_URL = os.getenv("AGENT_URL")

if AGENT_URL:
    parsed = urlparse(AGENT_URL)
    protocol = parsed.scheme or "https"
    host = parsed.hostname
    port = parsed.port or 443
else:
    protocol = "http"
    host = "localhost"
    port = PORT

a2a_app = to_a2a(root_agent, host=host, port=port, protocol=protocol)

if __name__ == "__main__":
    import uvicorn

    logger.info(f"🚀 Starting currency_agent on port {PORT}")
    uvicorn.run(a2a_app, host="0.0.0.0", port=PORT)

El ayudante to_a2a() hace lo siguiente de forma automática:

  1. Inspecciona las herramientas y las instrucciones de LlmAgent.
  2. Genera un AgentCard de A2A que describe sus habilidades (p.ej., currency_agent-get_exchange_rate).
  3. Une el agente en una aplicación de FastAPI (a2a_app) que admite extremos de JSON-RPC.
  4. Configura de forma dinámica el url anunciado en la tarjeta del agente según AGENT_URL (o localhost).

Inicia el servidor A2A del agente de divisas

En la segunda terminal, inicia el agente de moneda:

uv run python currency_agent/agent.py

El servidor se inicia en el puerto 8081:

[INFO]: --- 🔧 Loading MCP tools from MCP Server at http://localhost:8080/mcp... ---
[INFO]: --- 🤖 Creating ADK Currency Agent... ---
[INFO]: 🚀 Starting currency_agent on port 8081
INFO:     Started server process
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8081 (Press CTRL+C to quit)

Inspecciona la tarjeta del agente

En tu navegador, visita el extremo de la tarjeta de agente: http://localhost:8081/.well-known/agent-card.json

Verás los metadatos JSON generados automáticamente:

{
  "name": "currency_agent",
  "description": "An agent that can help with currency conversions",
  "supportedInterfaces": [
    {
      "url": "http://localhost:8081",
      "protocolBinding": "JSONRPC",
      "protocolVersion": "1.0"
    }
  ],
  "version": "0.0.1",
  "capabilities": {
    "streaming": true
  },
  "defaultInputModes": [
    "text/plain"
  ],
  "defaultOutputModes": [
    "text/plain"
  ],
  "skills": [
    {
      "id": "currency_agent",
      "name": "model",
      "description": "An agent that can help with currency conversions",
      "tags": [
        "llm"
      ]
    },
    {
      "id": "currency_agent-get_exchange_rate",
      "name": "get_exchange_rate",
      "description": "Use this to get current exchange rate.",
      "tags": [
        "llm",
        "tools"
      ]
    }
  ]
}

Prueba con el cliente de A2A

Abre una tercera terminal, navega a la carpeta python (cd getting-started-mcp-a2a-adk/python) y prueba el extremo de A2A con la secuencia de comandos dedicada del cliente de prueba de A2A:

uv run python currency_agent/test_a2aclient.py

El cliente resuelve la tarjeta del agente con A2ACardResolver y envía un mensaje JSON-RPC:

🔄 Fetching the agent card at http://localhost:8081
✅ Successfully fetched the agent card
====================================================
                     AgentCard                      
====================================================
Name        : currency_agent
Description : An agent that can help with currency conversions
Interfaces  : [0] http://localhost:8081  (JSONRPC 1.0)
Skills      : currency_agent, currency_agent-get_exchange_rate
====================================================
🔄 Initializing a non-streaming client
Sending request: "how much is 100 USD in GBP?"
Response:
100 USD is currently equal to approximately 73.37 GBP...

El agente de divisas ahora funciona como un servidor A2A completamente operativo.

7. Crea el agente de viajes

Ahora, compilarás el agente de viajes de organización. Este agente muestra cómo un agente del ADK puede combinar sin esfuerzo dos paradigmas de herramientas diferentes:

  1. Herramienta de agente local (weather_agent): Es un subagente del ADK en proceso que se ejecuta en el mismo entorno de ejecución de Python, lo que evita cualquier latencia de red o serialización.
  2. Herramienta de agente remoto (currency_agent): Es un agente externo conectado a través de la red con el protocolo A2A usando RemoteA2aAgent.
                    +-----------------------------+
                    |        travel_agent         |
                    | (Orchestrator with Web UI)  |
                    +--------------+--------------+
                                   |
             +---------------------+---------------------+
             | (In-process call)                         | (A2A Network Hop)
             v                                           v
+-------------------------+                 +-------------------------+
|   weather_agent         |                 |   currency_agent        |
|  (Local AgentTool)      |                 |  (Remote A2A Agent)     |
|  Calls wttr.in API      |                 |  Calls Currency MCP Svc |
+-------------------------+                 +-------------------------+

1. El agente secundario de clima local

Echa un vistazo a travel_agent/subagents/weather_agent.py:

import logging
import httpx
from google.adk.agents import LlmAgent

logger = logging.getLogger(__name__)

SYSTEM_INSTRUCTION = (
    "You are a specialized assistant for providing weather forecasts and conditions for travel destinations. "
    "Your sole purpose is to use the 'get_weather' tool to fetch weather information. "
    "Provide clear, concise summaries of current weather conditions, temperatures, and forecasts to help travelers pack and plan."
)


def get_weather(location: str = "London") -> dict:
    """Gets the current weather and forecast for a given location or city."""
    logger.info(f"--- 🌤️ Tool: get_weather called for {location} ---")
    try:
        response = httpx.get(
            f"https://wttr.in/{location}?format=j1",
            headers={"User-Agent": "curl/7.68.0"},
            timeout=8.0,
        )
        response.raise_for_status()
        data = response.json()
        current = data["current_condition"][0]
        return {
            "location": location,
            "condition": current.get("weatherDesc", [{}])[0].get("value", "Unknown"),
            "temperature_celsius": f"{current.get('temp_C', 'N/A')}°C",
            "temperature_fahrenheit": f"{current.get('temp_F', 'N/A')}°F",
            "humidity": f"{current.get('humidity', 'N/A')}%",
            "wind_speed_kmph": f"{current.get('windspeedKmph', 'N/A')} km/h",
        }
    except Exception as e:
        logger.warning(f"⚠️ Weather lookup failed: {e}. Returning simulated estimate.")
        return {
            "location": location,
            "condition": "Partly Cloudy",
            "temperature_celsius": "20°C",
            "temperature_fahrenheit": "68°F",
            "humidity": "55%",
            "wind_speed_kmph": "10 km/h",
            "note": f"Live data unavailable ({e}); showing estimated conditions.",
        }


weather_agent = LlmAgent(
    model="gemini-3.8-flash",
    name="weather_agent",
    description="A local specialist agent that provides current weather reports and forecasts for travel destinations.",
    instruction=SYSTEM_INSTRUCTION,
    tools=[get_weather],
)

El agente meteorológico es un LlmAgent con una herramienta de función que recupera el clima en tiempo real de wttr.in con un resguardo resiliente.

2. El organizador de agentes de viajes

Ahora, observa travel_agent/agent.py:

import logging
import os
from dotenv import load_dotenv
from google.adk.agents import LlmAgent
from google.adk.tools.agent_tool import AgentTool
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent, AGENT_CARD_WELL_KNOWN_PATH

try:
    from travel_agent.subagents.weather_agent import weather_agent
except ImportError:
    from subagents.weather_agent import weather_agent

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

load_dotenv()

SYSTEM_INSTRUCTION = (
    "You are a helpful travel assistant. You help users plan trips, recommend places, "
    "and answer travel-related questions.\n\n"
    "- Whenever a user asks about currency exchange rates or money conversions, "
    "delegate the request to the 'currency_agent' tool.\n"
    "- Whenever a user asks about the weather, climate, or forecasts for a destination, "
    "delegate the request to the 'weather_agent' tool."
)

CURRENCY_AGENT_URL = os.getenv("CURRENCY_AGENT_URL", "http://localhost:8081").rstrip("/")

logger.info(
    "--- 🔗 Connecting to Remote A2A Currency Agent at %s... ---",
    CURRENCY_AGENT_URL,
)

currency_remote_agent = RemoteA2aAgent(
    name="currency_agent",
    agent_card=f"{CURRENCY_AGENT_URL}{AGENT_CARD_WELL_KNOWN_PATH}",
    description="An agent that can help with currency conversions and exchange rates.",
)

logger.info("--- 🤖 Creating ADK Travel Agent... ---")

root_agent = LlmAgent(
    model="gemini-3.8-flash",
    name="travel_agent",
    description="A travel assistant that can help plan trips, check weather forecasts via the local weather agent, and convert currencies via the remote currency agent.",
    instruction=SYSTEM_INSTRUCTION,
    tools=[
        AgentTool(agent=currency_remote_agent),
        AgentTool(agent=weather_agent),
    ],
)

if __name__ == "__main__":
    import uvicorn
    from google.adk.cli.fast_api import get_fast_api_app

    PORT = int(os.getenv("PORT", 8082))
    logger.info(f"🚀 Starting travel_agent Web UI on port {PORT}")
    app = get_fast_api_app(web=True, allow_origins=["*"], agents_dir=os.path.dirname(__file__) or ".")
    uvicorn.run(app, host="0.0.0.0", port=PORT)

Aspectos destacados:

  • RemoteA2aAgent recupera la tarjeta del agente de monedas de http://localhost:8081/.well-known/agent-card.json.
  • Tanto currency_remote_agent como weather_agent se unen con AgentTool del ADK.
  • Cuando ejecutas travel_agent/agent.py, se inicia directamente la IU web del ADK en el puerto 8082 con get_fast_api_app(web=True).

8. Ejecuta y prueba el sistema multiagente de forma local

Ya tienes listos los tres componentes. Ejecutemos y probemos el sistema completo de forma local.

Ejecuta los tres servicios

Asegúrate de que los servicios se estén ejecutando en tres ventanas de terminal independientes (desde el directorio getting-started-mcp-a2a-adk/python) en el siguiente orden:

Terminal 1 (servidor de MCP de monedas):

uv run python currency_mcp_server/server.py

(Running on port 8080)

Terminal 2 (agente A2A de Currency):

uv run python currency_agent/agent.py

(Se ejecuta en el puerto 8081)

Terminal 3 (agente de viajes con IU web):

uv run python travel_agent/agent.py

(Running on port 8082)

Prueba a través de la IU web del ADK

Abre tu navegador en http://localhost:8082 (o usa la Vista previa en la Web en el puerto 8082 en Cloud Shell).

Hazle al agente de viajes una pregunta compuesta que requiera ambas herramientas:

"Estoy planeando un viaje a Londres. ¿Cómo está el clima y cuánto son EUR 200 en GBP?"

Observa el flujo de ejecución:

  1. El agente de viajes recibe la solicitud en la IU web.
  2. Delega la pregunta sobre el clima en proceso al weather_agent local, que recupera las condiciones actuales de wttr.in.
  3. Delega la conversión de moneda a través del protocolo A2A a currency_agent en el puerto 8081.
  4. El currency_agent llama al currency_mcp_server en el puerto 8080 a través de MCP para recuperar el tipo de cambio.
  5. Todos los resultados se sintetizan y se te devuelven en una respuesta unificada y útil.

Agente de monedas remoto de ADK Web

Realiza pruebas con la línea de comandos

También puedes probar las consultas directamente desde la CLI sin abrir un navegador:

uv run adk run travel_agent "What is the weather in London and how much is 100 USD in EUR?"

Ahora que todo funciona sin problemas en tu máquina local, implementemos todo el sistema en Google Cloud Run.

9. Implementa el sistema multiagente en Cloud Run

Cada componente tiene su propio Dockerfile y pyproject.toml independiente, por lo que se puede compilar e implementar de forma independiente en Cloud Run.

Con gcloud, implementarás cada servicio y conectarás automáticamente sus URLs.

Configura las variables de entorno

Establece el ID del proyecto de Cloud y la región de destino:

export PROJECT_ID=<YOUR_GOOGLE_CLOUD_PROJECT_ID>
export REGION=us-central1

Paso 1: Implementa el servidor de MCP de Currency

Implementa el servidor de MCP directamente desde la fuente:

# 1. Deploy MCP server
gcloud run deploy currency-mcp-server \
  --source currency_mcp_server \
  --region $REGION \
  --allow-unauthenticated

# 2. Capture the deployed MCP server URL
MCP_SERVER_URL=$(gcloud run services describe currency-mcp-server --region $REGION --format='value(status.url)')/mcp
echo "MCP Server URL: $MCP_SERVER_URL"

Paso 2: Implementa el agente de monedas

Dado que la URL pública de currency-agent se asigna en su primera implementación, primero implementa el servicio, captura su URL y actualiza su variable de entorno AGENT_URL para que su tarjeta de agente A2A anuncie la dirección HTTPS pública correcta:

# 1. Deploy Currency Agent connected to the deployed MCP Server
gcloud run deploy currency-agent \
  --source currency_agent \
  --region $REGION \
  --allow-unauthenticated \
  --update-env-vars MCP_SERVER_URL="$MCP_SERVER_URL",GOOGLE_GENAI_USE_ENTERPRISE="true",GOOGLE_CLOUD_PROJECT="$PROJECT_ID",GOOGLE_CLOUD_LOCATION="global"

# 2. Capture its assigned Cloud Run URL
CURRENCY_AGENT_URL=$(gcloud run services describe currency-agent --region $REGION --format='value(status.url)')
echo "Currency Agent URL: $CURRENCY_AGENT_URL"

# 3. Update AGENT_URL so the agent advertises its public HTTPS endpoint in its Agent Card
gcloud run services update currency-agent \
  --region $REGION \
  --update-env-vars AGENT_URL="$CURRENCY_AGENT_URL"

Paso 3: Implementa el agente de viajes

Ahora, implementa el agente de viajes y configúralo con el CURRENCY_AGENT_URL:

# 1. Deploy Travel Agent (with ADK Web UI) connected to Currency Agent
gcloud run deploy travel-agent \
  --source travel_agent \
  --region $REGION \
  --allow-unauthenticated \
  --update-env-vars CURRENCY_AGENT_URL="$CURRENCY_AGENT_URL",GOOGLE_GENAI_USE_ENTERPRISE="true",GOOGLE_CLOUD_PROJECT="$PROJECT_ID",GOOGLE_CLOUD_LOCATION="global"

# 2. Capture its assigned Cloud Run URL
TRAVEL_AGENT_URL=$(gcloud run services describe travel-agent --region $REGION --format='value(status.url)')
echo "Travel Agent URL: $TRAVEL_AGENT_URL"

10. Prueba el sistema multiagente en Cloud Run

Con los tres microservicios implementados, verifiquemos cada capa en Cloud Run.

1. Prueba el servidor de MCP remoto

Prueba el servidor de MCP de Cloud Run implementado desde la línea de comandos:

MCP_SERVER_URL="$MCP_SERVER_URL" uv run python currency_mcp_server/test_server.py

Deberías ver la herramienta en la lista y que se invocó correctamente en Cloud Run.

2. Prueba el agente de monedas con A2A

Prueba el agente de moneda implementado con el cliente de prueba de A2A:

AGENT_URL="$CURRENCY_AGENT_URL" uv run python currency_agent/test_a2aclient.py

El cliente recuperará la tarjeta de agente remota de Cloud Run y, luego, intercambiará mensajes a través de JSON-RPC de HTTPS.

3. Prueba la IU web del agente de viajes en Cloud Run

Abre $TRAVEL_AGENT_URL en tu navegador.

La IU web completa del ADK se entrega directamente desde Cloud Run. Prueba con las siguientes instrucciones:

"Estoy planeando un viaje a Tokio. ¿Cómo está el clima y cuánto son USD 500 en JPY?"

[Browser] 
   │
   ▼ (HTTPS)
[Cloud Run: travel-agent]
   ├──> Local in-process tool: weather_agent (wttr.in)
   └──> A2A JSON-RPC (HTTPS)
           │
           ▼
        [Cloud Run: currency-agent]
           └──> MCP Streamable HTTP (HTTPS)
                   │
                   ▼
                [Cloud Run: currency-mcp-server] (Frankfurter API)

Los tres servicios escalan de forma independiente en la infraestructura sin servidores y se comunican sin problemas a través de protocolos abiertos.

11. Felicitaciones y limpieza

Objetivos logrados

¡Felicitaciones! Creaste e implementaste un sistema multiagente de nivel de producción:

  • Protocolo de contexto del modelo (MCP): Se creó un servidor de FastMCP que expone herramientas de la API de Live a través de HTTP transmitible.
  • Kit de desarrollo de agentes (ADK): Creaste agentes modulares con LlmAgent, conectaste herramientas de MCP con McpToolset y alojaste la IU web del ADK.
  • Protocolo Agent2Agent (A2A): Expusiste un agente como un servicio A2A (to_a2a), publicaste tarjetas de agente (agent-card.json) y consumiste agentes remotos con RemoteA2aAgent.
  • Arquitectura multiagente: Se combinaron subagentes locales en proceso (weather_agent) con agentes remotos distribuidos (currency_agent).
  • Implementación sin servidores de Cloud Run: Se alojaron en contenedores y se implementaron los tres servicios con cableado de configuración automatizado.

Para obtener el código completo (incluidas las implementaciones de Python y Java) y las actualizaciones futuras, visita el repositorio getting-started-mcp-a2a-adk.

Limpia

Para evitar que se apliquen cargos a tu cuenta de Google Cloud por los servicios de Cloud Run que creaste en este codelab, sigue estos pasos:

Borra los servicios de Cloud Run implementados:

gcloud run services delete currency-mcp-server --region $REGION --quiet
gcloud run services delete currency-agent --region $REGION --quiet
gcloud run services delete travel-agent --region $REGION --quiet

Como alternativa, si creaste un proyecto dedicado para este codelab, puedes cerrarlo por completo:

gcloud projects delete $PROJECT_ID