Начало работы с MCP и A2A с помощью ADK

1. Обзор

ИИ-агенты быстро набирают популярность, революционизируя автоматизацию задач и принятие решений благодаря своей способности работать автономно, учиться и взаимодействовать с окружающей средой для достижения целей.

Эта практическая работа поможет вам начать работу с мультиагентными системами. Вы создадите сервер MCP для валют, агента для валют, который использует сервер MCP и доступен по протоколу Agent2Agent (A2A), агента для путешествий с внутрипроцессным субагентом для погоды, который использует агента для валют по протоколу A2A, и развернете все сервисы в Cloud Run.

Архитектура

Базовые технологии

Model Context Protocol (MCP)

Model Context Protocol (MCP) – это открытый протокол, который стандартизирует то, как приложения предоставляют контекст и инструменты большим языковым моделям. MCP можно сравнить с портом USB-C для ИИ-приложений: он предоставляет стандартизированный способ подключения ИИ-моделей к внешним источникам данных, API и инструментам.

В этой практической работе currency_mcp_server предоставляет инструмент get_exchange_rate через Streamable HTTP (/mcp) на основе общедоступного Frankfurter API.

Agent Development Kit (ADK)

Agent Development Kit (ADK) – это гибкий фреймворк оркестрации для разработки и развертывания ИИ-агентов. ADK не зависит от модели и развертывания и совместим с другими фреймворками. С ADK разработка агентов похожа на стандартную разработку ПО, что упрощает создание, тестирование и оркестрацию сложных агентных рабочих процессов.

ADK обрабатывает разговоры пользователей, обслуживает интерактивный веб-интерфейс, подключается к инструментам MCP через McpToolset и управляет взаимодействием между агентами.

Протокол Agent2Agent (A2A)

Протокол Agent2Agent (A2A) – это открытый стандарт, разработанный для обеспечения связи и взаимодействия между ИИ-агентами. Подобно тому, как MCP стандартизирует связи между агентами и инструментами, A2A стандартизирует взаимодействие между агентами. В мире, где агенты создаются на основе разных фреймворков, в разных средах хостинга и разными организациями, A2A предоставляет общий язык для обнаружения и делегирования задач.

ADK предоставляет currency_agent как сервис A2A (to_a2a) и позволяет travel_agent использовать его удаленно как AgentTool (RemoteA2aAgent).

Локальные субагенты и удаленные A2A-агенты

Эта архитектура подчеркивает важный паттерн в проектировании мультиагентных систем:

  • Инструмент Local Agent (weather_agent). Выполняется в процессе в оркестраторе как AgentTool, без задержки сети или накладных расходов на сериализацию протокола.
  • Инструмент удаленного агента (currency_agent). Работает как независимый микросервис, вызываемый по сети через протокол A2A.

Что вы узнаете

  • Как создать и протестировать локальный MCP-сервер с помощью FastMCP через Streamable HTTP
  • Как создать агента с помощью ADK, который использует инструменты MCP (McpToolset)
  • Как сделать агент ADK сервером A2A (to_a2a)
  • Как протестировать сервер A2A с помощью клиента A2A Python (a2a.client)
  • Как создать агента-оркестратора, который объединяет локальные инструменты субагентов с удаленными A2A-агентами.
  • Как запустить и протестировать мультиагентную систему локально с помощью веб-интерфейса ADK.
  • Как контейнеризовать и развернуть все три компонента в Google Cloud Run

Что вам понадобится

  • Браузер, например Chrome.
  • Проект Google Cloud с включенными платежными функциями.

2. Подготовка

Как создать проект

Если у вас нет проекта Google Cloud, создайте его.

В консоли Google Cloud на странице выбора проекта выберите или создайте проект Google Cloud.

Также убедитесь, что для вашего облачного проекта включены платежные функции. Подробнее о том, как проверить, включены ли платежные функции для проекта…

Активировать Cloud Shell

Google Cloud Shell – это интерактивная среда разработки на основе браузера, доступная непосредственно в консоли Google Cloud. Это самый простой способ начать работу с Google Cloud без необходимости устанавливать инструменты локально.

Активируйте Cloud Shell, нажав на эту ссылку. Вы можете переключаться между терминалом Cloud Shell (для выполнения облачных команд) и редактором (для просмотра файлов), нажимая соответствующую кнопку в Cloud Shell.

После подключения к Cloud Shell убедитесь, что вы прошли аутентификацию:

gcloud auth list

Убедитесь, что команда gcloud знает о вашем проекте:

gcloud config list project

Укажите идентификатор проекта:

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

Как включить Cloud API

Включите необходимые API для Cloud Run, Cloud Build, Artifact Registry и Vertex AI:

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

Как получить код

Клонируйте хранилище и перейдите в каталог python:

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

Установите зависимости с помощью uv

uv – это быстрый менеджер пакетов и проектов Python. Он предустановлен в Cloud Shell. Если вы запускаете его локально, установите его следующим образом:

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

Каталог Python структурирован как единый uv.

Workspace. Установите все зависимости для всех участников рабочей области (currency_mcp_server, currency_agent и travel_agent) в единую виртуальную среду, выполнив следующую команду:

uv sync

Настройте переменные среды

Настройте переменные среды в файле .env в каталоге python:

Вариант А. 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

Вариант Б. Google AI Studio (локальный ключ API)

Если вы хотите использовать ключ API из Google AI Studio:

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

3. Создайте MCP-сервер для конвертации валют

Прежде чем создавать агентов, вы изучите MCP-сервер, который предоставляет инструмент конвертации валют.

MCP-сервер позволяет создавать простые программы, чтобы использовать их возможности как инструменты. Один или несколько агентов могут получить доступ к этим инструментам с помощью стандартизированного протокола Model Context Protocol.

Пакет Python FastMCP можно использовать для создания MCP-сервера, который предоставляет один инструмент под названием get_exchange_rate. Инструмент get_exchange_rate вызывает Frankfurter API, чтобы получить текущий обменный курс между двумя валютами.

Код MCP-сервера находится в 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,
        )
    )

Запустите MCP-сервер локально

Запустите MCP-сервер в терминале:

uv run python currency_mcp_server/server.py

Сервер запускается на порте 8080, а конечная точка Streamable HTTP доступна по адресу /mcp (http://localhost:8080/mcp).

Протестируйте MCP-сервер

Откройте второе окно терминала (не закрывая первое, в котором запущен MCP-сервер), перейдите в папку python (cd getting-started-mcp-a2a-adk/python) и запустите тестовый скрипт:

uv run python currency_mcp_server/test_server.py

Тестовый скрипт подключается к конечной точке MCP с помощью Client FastMCP, выводит список инструментов и вызывает 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}} ---

Здорово! У вас есть работающий MCP-сервер, на котором размещен инструмент для конвертации валют. Не закрывайте терминал. Он понадобится вам на следующих этапах.

4. Создание агента для конвертации валют с помощью ADK

Теперь создайте агента для конвертации валют с помощью Agent Development Kit (ADK).

ADK предоставляет встроенную поддержку инструментов MCP через класс McpToolset. Агент валют подключается к нашему MCP-серверу с помощью StreamableHTTPConnectionParams.

Посмотрите на определение агента валют в 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
            )
        )
    ],
)

Обратите внимание, что McpToolset автоматически обнаруживает и загружает инструмент get_exchange_rate непосредственно с работающего MCP-сервера по протоколу HTTP.

Тестирование агента для конвертации валют в веб-интерфейсе ADK

Вы можете протестировать агент отдельно, используя веб-интерфейс разработки ADK. Во втором терминале выполните следующую команду:

uv run adk web --allow_origins "*" currency_agent

Откройте в браузере страницу http://localhost:8000 (или нажмите Web Preview (Предварительный просмотр) в Cloud Shell).

Агент ADK Web Currency

Спросите агента:

"Сколько будет 250 долларов США в евро?"

Вы увидите, как агент вызывает инструмент MCP get_exchange_rate и возвращает конвертированную сумму. Прежде чем продолжить, остановите процесс adk web с помощью Ctrl+C.

5. Протокол Agent2Agent (A2A)

Протокол Agent2Agent (A2A) – это открытый стандарт, разработанный для обеспечения связи и взаимодействия между ИИ-агентами.

В современных мультиагентных системах агенты часто создаются с помощью разных фреймворков (ADK, LangChain, CrewAI, AutoGen) и развертываются в разной инфраструктуре. A2A устраняет эти барьеры, определяя стандартизированный контракт на обмен данными.

Протокол A2A

Основные понятия A2A

  • Обнаружение агентов (карточка агента). Каждый агент, соответствующий стандарту A2A, сообщает о своих возможностях, поддерживаемых режимах I/O, требованиях к аутентификации и навыках через стандартный JSON-файл, размещенный по адресу /.well-known/agent-card.json.
  • Навыки агента (AgentSkill). Определенные возможности или инструменты, которые может использовать агент. Другие агенты читают эти навыки, чтобы решить, когда делегировать задачи.
  • Обмен данными JSON-RPC. Агенты обмениваются структурированными сообщениями, задачами и артефактами по стандартным транспортным протоколам, таким как HTTP JSON-RPC 2.0.

Карточка A2A-агента

На следующем шаге вы сделаете агент ADK Currency Agent доступным в качестве сервера A2A, чтобы другие агенты могли находить его и делегировать ему задачи по конвертации валют.

6. Как предоставить доступ к агенту валют в качестве сервера A2A

С помощью служебной функции to_a2a() ADK позволяет легко превратить любой LlmAgent в сервер, совместимый с A2A.

Проверьте нижнюю часть 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)

Помощник to_a2a() автоматически:

  1. Проверяет инструменты и инструкции LlmAgent.
  2. Генерирует AgentCard A2A с описанием навыков (например, currency_agent-get_exchange_rate).
  3. Оборачивает агент в приложение FastAPI (a2a_app), поддерживающее конечные точки JSON-RPC.
  4. Динамически настраивает рекламируемый url в карточке агента на основе AGENT_URL (или localhost).

Запустите сервер агента валют A2A

Во втором терминале запустите агент валют:

uv run python currency_agent/agent.py

Сервер запускается на порте 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)

Проверьте карточку агента

В браузере перейдите к конечной точке карточки агента: http://localhost:8081/.well-known/agent-card.json.

Вы увидите автоматически сгенерированные метаданные JSON:

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

Тестирование с помощью клиента A2A

Откройте третий терминал, перейдите в папку python (cd getting-started-mcp-a2a-adk/python) и протестируйте конечную точку A2A с помощью специального тестового клиентского скрипта A2A:

uv run python currency_agent/test_a2aclient.py

Клиент разрешает карточку агента с помощью A2ACardResolver и отправляет сообщение 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...

Агент валют теперь работает как полноценный сервер A2A!

7. Создание турагентства

Теперь вы создадите управляющего турагента. Этот агент демонстрирует, как агент ADK может легко комбинировать две разные парадигмы инструментов:

  1. Инструмент Local Agent (weather_agent). Внутрипроцессный субагент ADK, работающий в той же среде выполнения Python, что позволяет избежать задержек, связанных с сетью или сериализацией.
  2. Инструмент удаленного агента (currency_agent). Внешний агент, подключенный по сети через протокол A2A с помощью 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. Субагент "Местный прогноз погоды"

Посмотрите на 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],
)

Агент погоды – это LlmAgent с инструментом-функцией, который получает данные о погоде в реальном времени от wttr.in с надежным резервным вариантом.

2. Управляющий агент для турагентства

Теперь посмотрите на 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)

Основные моменты:

  • RemoteA2aAgent получает карточку агента по валютам из http://localhost:8081/.well-known/agent-card.json.
  • И currency_remote_agent, и weather_agent упакованы с помощью AgentTool ADK.
  • При непосредственном запуске travel_agent/agent.py загружается веб-интерфейс ADK на порте 8082 с использованием get_fast_api_app(web=True).

8. Запуск и тестирование мультиагентной системы локально

Теперь у вас есть все три компонента. Давайте запустим и протестируем всю систему локально.

Запуск всех трех сервисов

Убедитесь, что сервисы запущены в трех отдельных окнах терминала (из каталога getting-started-mcp-a2a-adk/python) в следующем порядке:

Терминал 1 (MCP-сервер для валют):

uv run python currency_mcp_server/server.py

(Running on port 8080)

Терминал 2 (A2A-агент по обмену валюты):

uv run python currency_agent/agent.py

(Работает на порту 8081)

Терминал 3 (турагентство с веб-интерфейсом)

uv run python travel_agent/agent.py

(работает на порту 8082)

Тестирование в веб-интерфейсе ADK

Откройте в браузере страницу http://localhost:8082 (или используйте Web Preview на порте 8082 в Cloud Shell).

Задайте турагенту составной вопрос, требующий использования обоих инструментов:

"Я планирую поездку в Лондон. Какая сейчас погода и сколько будет 200 евро в фунтах стерлингов?"

Посмотрите, как выполняется код:

  1. Турагент получает запрос в веб-интерфейсе.
  2. Оно передает вопрос о погоде локальному weather_agent, который получает текущие условия от wttr.in.
  3. Он делегирует конвертацию валюты по протоколу A2A агенту currency_agent на порту 8081.
  4. currency_agent вызывает currency_mcp_server через порт 8080 по протоколу MCP, чтобы получить обменный курс.
  5. Все результаты будут обобщены и представлены в виде единого полезного ответа.

ADK Web Remote Currency Agent

Тестирование с помощью командной строки

Вы также можете тестировать запросы непосредственно из CLI, не открывая браузер:

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

Теперь, когда все работает на вашем локальном компьютере, давайте развернем всю систему в Google Cloud Run.

9. Развертывание системы из нескольких агентов в Cloud Run

У каждого компонента есть собственный файл Dockerfile и автономный файл pyproject.toml, поэтому его можно создать и развернуть в Cloud Run независимо от других.

С помощью gcloud вы развернете каждый сервис и автоматически свяжете их URL.

Как настроить переменные среды

Укажите идентификатор проекта Cloud и целевой регион:

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

Шаг 1. Разверните MCP-сервер Currency

Разверните MCP-сервер непосредственно из источника:

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

Шаг 2. Разверните агент валют

Поскольку общедоступный URL сервиса currency-agent назначается при его первом развертывании, сначала разверните сервис, скопируйте его URL и обновите переменную среды AGENT_URL, чтобы в карточке A2A-агента был указан правильный общедоступный HTTPS-адрес.

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

Шаг 3. Разверните Travel Agent

Теперь разверните турагента, настроив его с помощью 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. Тестирование системы из нескольких агентов в Cloud Run

После развертывания всех трех микросервисов давайте проверим каждый уровень в Cloud Run.

1. Протестируйте удаленный MCP-сервер

Протестируйте развернутый MCP-сервер Cloud Run из командной строки:

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

Вы должны увидеть инструмент в списке и сообщение о том, что он успешно вызван в Cloud Run.

2. Протестируйте валютного агента через A2A

Протестируйте развернутый агент валют с помощью тестового клиента A2A:

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

Клиент получит удаленную карточку агента из Cloud Run и будет обмениваться сообщениями по протоколу HTTPS JSON-RPC.

3. Тестирование веб-интерфейса турагентства в Cloud Run

Откройте $TRAVEL_AGENT_URL в браузере.

Веб-интерфейс ADK полностью обслуживается Cloud Run. Примеры вопросов:

"Я планирую поездку в Токио. Какая там погода и сколько будет 500 долларов США в японских иенах?"

[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)

Все три сервиса масштабируются независимо друг от друга в бессерверной инфраструктуре и взаимодействуют по открытым протоколам.

11. Поздравления и уборка

Что вы сделали

Поздравляем! Вы создали и развернули систему из нескольких агентов, готовую к использованию в рабочей среде:

  • Model Context Protocol (MCP). Создан сервер FastMCP, который предоставляет доступ к инструментам API через Streamable HTTP.
  • Agent Development Kit (ADK). Создание модульных агентов с помощью LlmAgent, подключение инструментов MCP с помощью McpToolset и размещение веб-интерфейса ADK.
  • Протокол Agent2Agent (A2A). Вы предоставили доступ к агенту как к сервису A2A (to_a2a), опубликовали карточки агентов (agent-card.json) и использовали удаленных агентов с помощью RemoteA2aAgent.
  • Мультиагентная архитектура. Объединение локальных внутрипроцессных субагентов (weather_agent) с распределенными удаленными агентами (currency_agent).
  • Бессерверное развертывание Cloud Run. Контейнеризация и развертывание всех трех сервисов с автоматической настройкой конфигурации.

Полный код (включая реализации на Python и Java) и будущие обновления доступны в репозитории getting-started-mcp-a2a-adk.

Организовать

Чтобы избежать списания средств с вашего аккаунта Google Cloud за сервисы Cloud Run, созданные в этой практической работе, выполните следующие действия:

Удалите развернутые сервисы Cloud Run:

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

Если вы создали отдельный проект для этой практической работы, вы можете удалить его целиком.

gcloud projects delete $PROJECT_ID