Pierwsze kroki z MCP i A2A z ADK

1. Przegląd

Agenty AI szybko zyskują na popularności, rewolucjonizując automatyzację zadań i podejmowanie decyzji dzięki możliwości autonomicznego działania, uczenia się i interakcji z otoczeniem w celu osiągania celów.

To ćwiczenie pomoże Ci rozpocząć tworzenie kompleksowego systemu wieloagentowego. Utworzysz serwer MCP walut, agenta walutowego, który korzysta z serwera MCP i jest udostępniany przez protokół Agent2Agent (A2A), oraz biuro podróży z działającym w procesie subagentem pogodowym, który korzysta z agenta walutowego przez A2A. Na koniec wdrożysz wszystkie usługi w Cloud Run.

Architektura

Core Technologies

Model Context Protocol (MCP)

Model Context Protocol (MCP) to otwarty protokół, który standaryzuje sposób, w jaki aplikacje dostarczają kontekst i narzędzia do LLM. MCP można porównać do portu USB-C dla aplikacji AI: zapewnia on ustandaryzowany sposób łączenia modeli AI z zewnętrznymi źródłami danych, interfejsami API i narzędziami.

W tym ćwiczeniu currency_mcp_server udostępnia narzędzie get_exchange_rate przez Streamable HTTP (/mcp) przy użyciu publicznego interfejsu Frankfurter API.

Pakiet Agent Development Kit (ADK)

Agent Development Kit (ADK) to elastyczny pakiet Agent Development Kit do koordynowania, który służy do tworzenia i wdrażania agentów AI. Pakiet ADK jest niezależny od modelu i wdrożenia oraz został zaprojektowany pod kątem zgodności z innymi platformami. ADK sprawia, że tworzenie agentów przypomina standardową inżynierię oprogramowania, co ułatwia tworzenie, testowanie i koordynowanie złożonych Agentic Workflows.

ADK obsługuje rozmowy użytkowników, udostępnia interaktywny interfejs internetowy, łączy się z narzędziami MCP przez McpToolset i zarządza komunikacją A2A.

Protokół Agent2Agent (A2A)

Protokół Agent2Agent (A2A) to otwarty standard, który umożliwia komunikację i współpracę między agentami AI. Podobnie jak MCP standaryzuje połączenia agentów z narzędziami, A2A standaryzuje współpracę między agentami. W świecie, w którym agenty są tworzone w różnych środowiskach, środowiskach hostingowych i organizacjach, A2A zapewnia wspólny język do wykrywania i delegowania zadań.

Pakiet ADK udostępnia currency_agent jako usługę A2A (to_a2a) i umożliwia travel_agent korzystanie z niej zdalnie jako AgentTool (RemoteA2aAgent).

Lokalne subagenty a zdalne agenty A2A

Ta architektura podkreśla kluczowy wzorzec w projektowaniu systemów wieloagentowych:

  • Narzędzie agenta lokalnego (weather_agent): działa w ramach procesu w orkiestratorze jako AgentTool, bez opóźnień sieciowych i narzutu związanego z serializacją protokołu.
  • Narzędzie agenta zdalnego (currency_agent): działa jako niezależny mikroserwis wywoływany w sieci za pomocą protokołu A2A.

Czego się nauczysz

  • Jak utworzyć i przetestować lokalny serwer MCP za pomocą FastMCP przez Streamable HTTP
  • Jak utworzyć agenta za pomocą pakietu ADK, który korzysta z narzędzi MCP (McpToolset)
  • Jak udostępnić agenta ADK jako serwer A2A (to_a2a)
  • Jak przetestować serwer A2A za pomocą klienta A2A w Pythonie (a2a.client)
  • Jak utworzyć agenta orkiestratora, który łączy lokalne narzędzia subagentów ze zdalnymi agentami A2A
  • jak uruchomić i przetestować cały system wieloagentowy lokalnie za pomocą interfejsu internetowego ADK.
  • jak skonteneryzować i wdrożyć wszystkie 3 komponenty w Google Cloud Run.

Czego potrzebujesz

  • przeglądarkę, np. Chrome;
  • projekt Google Cloud z włączonymi płatnościami,

2. Zanim zaczniesz

Utwórz projekt

Jeśli nie masz projektu Google Cloud, utwórz go.

W konsoli Google Cloud na stronie selektora projektów wybierz lub utwórz projekt Google Cloud.

Sprawdź też, czy w projekcie w chmurze włączone są płatności. Dowiedz się, jak sprawdzić, czy w projekcie są włączone płatności.

Aktywowanie Cloud Shell

Google Cloud Shell to interaktywne, oparte na przeglądarce środowisko programistyczne udostępniane bezpośrednio w konsoli Google Cloud. To najprostszy sposób na rozpoczęcie korzystania z Google Cloud bez konieczności instalowania narzędzi lokalnie.

Aktywuj Cloud Shell, klikając ten link. Możesz przełączać się między terminalem Cloud Shell (do uruchamiania poleceń w chmurze) a edytorem (do wyświetlania plików), klikając odpowiedni przycisk w Cloud Shell.

Po połączeniu z Cloud Shell sprawdź, czy uwierzytelnianie zostało przeprowadzone:

gcloud auth list

Sprawdź, czy polecenie gcloud ma informacje o Twoim projekcie:

gcloud config list project

Ustaw identyfikator projektu:

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

Włączanie interfejsów Cloud APIs

Włącz wymagane interfejsy API dla Cloud Run, Cloud Build, Artifact Registry i Vertex AI:

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

Pobierz kod

Sklonuj repozytorium i przejdź do katalogu python:

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

Instalowanie zależności za pomocą uv

uv to szybki system zarządzania pakietami i projektami Pythona. Jest ono już zainstalowane w Cloud Shell. Jeśli uruchamiasz go lokalnie, możesz go zainstalować w ten sposób:

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

Katalog Pythona ma strukturę ujednoliconego uv.

Workspace. Zainstaluj wszystkie zależności we wszystkich elementach obszaru roboczego (currency_mcp_server, currency_agent i travel_agent) w jednym środowisku wirtualnym, uruchamiając:

uv sync

Konfigurowanie zmiennych środowiskowych

Skonfiguruj zmienne środowiskowe w pliku .env w katalogu python:

Opcja 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

Opcja B: Google AI Studio (lokalny klucz interfejsu API)

Jeśli wolisz używać klucza interfejsu API z Google AI Studio:

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

3. Tworzenie serwera MCP przeliczającego waluty

Zanim utworzysz agentów, zapoznasz się z serwerem MCP, który udostępnia narzędzie do przeliczania walut.

Serwer MCP umożliwia pisanie lekkich programów, które udostępniają możliwości jako narzędzia. Agent (lub wielu agentów) może następnie uzyskać dostęp do tych narzędzi za pomocą ustandaryzowanego protokołu Model Context Protocol.

Pakiet Pythona FastMCP można wykorzystać do utworzenia serwera MCP, który udostępnia jedno narzędzie o nazwie get_exchange_rate. Narzędzie get_exchange_rate wywołuje interfejs Frankfurter API, aby uzyskać aktualny kurs wymiany między 2 walutami.

Kod serwera MCP znajduje się w pliku 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,
        )
    )

Uruchamianie serwera MCP lokalnie

Uruchom serwer MCP w terminalu:

uv run python currency_mcp_server/server.py

Serwer uruchamia się na porcie 8080, a punkt końcowy HTTP do strumieniowego przesyłania danych jest dostępny pod adresem /mcp (http://localhost:8080/mcp).

Testowanie serwera MCP

Otwórz drugie okno terminala (pozostawiając serwer MCP uruchomiony w pierwszym), przejdź do folderu python (cd getting-started-mcp-a2a-adk/python) i uruchom skrypt testowy:

uv run python currency_mcp_server/test_server.py

Skrypt testowy łączy się z punktem końcowym MCP za pomocą Client FastMCP, wyświetla listę narzędzi i wywołuje 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}} ---

Świetnie! Masz działający serwer MCP, który udostępnia narzędzie do przeliczania walut na żywo. Nie zamykaj tego terminala, ponieważ będzie potrzebny w kolejnych krokach.

4. Tworzenie agenta walutowego za pomocą pakietu ADK

Teraz utworzymy agenta walutowego za pomocą pakietu Agent Development Kit (ADK).

ADK zapewnia wbudowaną obsługę narzędzi MCP za pomocą klasy McpToolset. Agent walutowy łączy się z naszym serwerem MCP za pomocą StreamableHTTPConnectionParams.

Przyjrzyj się definicji agenta walutowego w pliku 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
            )
        )
    ],
)

Zwróć uwagę, jak McpToolset automatycznie wykrywa i wczytuje narzędzie get_exchange_rate bezpośrednio z uruchomionego serwera MCP przez HTTP.

Testowanie agenta walutowego za pomocą interfejsu internetowego ADK

Możesz przetestować agenta w izolacji, korzystając z interfejsu internetowego ADK dla programistów. W drugim terminalu uruchom:

uv run adk web --allow_origins "*" currency_agent

Otwórz przeglądarkę na stronie http://localhost:8000 (lub kliknij Podgląd w przeglądarce w Cloud Shell).

Agent ADK Web Currency

Zapytaj agenta:

„Ile to jest 250 USD w EUR?”

Zobaczysz, że agent wywoła narzędzie MCP get_exchange_rate i zwróci przeliczoną kwotę. Zanim przejdziesz dalej, zatrzymaj proces adk web za pomocą Ctrl+C.

5. Protokół Agent2Agent (A2A)

Protokół Agent2Agent (A2A) to otwarty standard, który umożliwia komunikację i współpracę między agentami AI.

W nowoczesnych systemach wieloagentowych agenty są często tworzone przy użyciu różnych platform (ADK, LangChain, CrewAI, AutoGen) i wdrażane w różnych infrastrukturach. A2A eliminuje te silosy, definiując standardową umowę dotyczącą komunikacji.

Protokół A2A

Kluczowe pojęcia dotyczące A2A

  • Wykrywanie agenta (karta agenta): każdy agent zgodny z protokołem A2A reklamuje swoje możliwości, obsługiwane tryby wejścia/wyjścia, wymagania dotyczące uwierzytelniania i umiejętności za pomocą standardowego pliku JSON hostowanego na stronie /.well-known/agent-card.json.
  • Umiejętności agenta (AgentSkill): konkretne funkcje lub narzędzia, które agent może wykonywać. Inne agenty odczytują te umiejętności, aby zdecydować, kiedy delegować zadania.
  • Komunikacja JSON-RPC: agenty wymieniają ustrukturyzowane wiadomości, zadania i artefakty za pomocą standardowych protokołów transportowych, takich jak HTTP JSON-RPC 2.0.

Karta agenta A2A

W następnym kroku udostępnisz agenta walutowego ADK jako serwer A2A, aby inne agenty mogły go wykryć i delegować mu zadania przeliczania walut.

6. Udostępnianie agenta walutowego jako serwera A2A

Dzięki funkcji użytkowej to_a2a() pakiet ADK ułatwia przekształcenie dowolnego LlmAgent w serwer zgodny z A2A.

Sprawdź dolną część 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)

Pomocnik to_a2a() automatycznie:

  1. Sprawdza narzędzia i instrukcje agenta LlmAgent.
  2. Generuje odpowiedź A2A AgentCard opisującą umiejętności (np. currency_agent-get_exchange_rate).
  3. opakowuje agenta w aplikację FastAPI (a2a_app) obsługującą punkty końcowe JSON-RPC;
  4. Dynamicznie konfiguruje reklamowany url na karcie agenta na podstawie AGENT_URL (lub hosta lokalnego).

Uruchamianie serwera A2A agenta walutowego

W drugim terminalu uruchom agenta walutowego:

uv run python currency_agent/agent.py

Serwer uruchamia się na porcie 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)

Sprawdzanie karty agenta

W przeglądarce otwórz punkt końcowy karty agenta: http://localhost:8081/.well-known/agent-card.json

Zobaczysz wygenerowane automatycznie metadane 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"
      ]
    }
  ]
}

Testowanie za pomocą klienta A2A

Otwórz trzeci terminal, przejdź do folderu python (cd getting-started-mcp-a2a-adk/python) i przetestuj punkt końcowy A2A za pomocą dedykowanego skryptu klienta testowego A2A:

uv run python currency_agent/test_a2aclient.py

Klient rozpoznaje kartę agenta za pomocą A2ACardResolver i wysyła wiadomość 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...

Agent walutowy działa teraz jako w pełni funkcjonalny serwer A2A.

7. Tworzenie agenta ds. podróży

Teraz utworzysz agenta biura podróży, który będzie pełnił funkcję koordynatora. Ten agent pokazuje, jak agent ADK może bez wysiłku połączyć 2 różne paradygmaty narzędzi:

  1. Local Agent Tool (weather_agent): subagent ADK działający w tym samym środowisku wykonawczym Pythona, co pozwala uniknąć opóźnień sieciowych i opóźnień serializacji.
  2. Narzędzie agenta zdalnego (currency_agent): agent zewnętrzny połączony przez sieć za pomocą protokołu A2A przy użyciu 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. Subagent lokalnej prognozy pogody

Spójrz na 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],
)

Agent pogodowy to LlmAgent z narzędziem funkcji, które pobiera informacje o pogodzie w czasie rzeczywistym z wttr.in z odpornym na błędy mechanizmem zastępczym.

2. Aranżer agenta biura podróży

Teraz spójrz na 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)

Najważniejsze informacje:

  • RemoteA2aAgent pobiera kartę agenta walutowego z usługi http://localhost:8081/.well-known/agent-card.json.
  • Zarówno currency_remote_agent, jak i weather_agent są opakowane za pomocą AgentTool pakietu ADK.
  • Uruchomienie travel_agent/agent.py powoduje bezpośrednie uruchomienie interfejsu internetowego ADK na porcie 8082 przy użyciu get_fast_api_app(web=True).

8. Uruchamianie i testowanie systemu wieloagentowego lokalnie

Masz teraz gotowe wszystkie 3 komponenty. Uruchommy i przetestujmy cały system lokalnie.

Uruchamianie wszystkich 3 usług

Upewnij się, że usługi są uruchomione w 3 osobnych oknach terminala (z katalogu getting-started-mcp-a2a-adk/python) w tej kolejności:

Terminal 1 (Serwer MCP waluty):

uv run python currency_mcp_server/server.py

(Running on port 8080)

Terminal 2 (agent Currency A2A):

uv run python currency_agent/agent.py

(Running on port 8081)

Terminal 3 (biuro podróży z interfejsem internetowym):

uv run python travel_agent/agent.py

(Running on port 8082)

Testowanie za pomocą interfejsu internetowego ADK

Otwórz przeglądarkę na stronie http://localhost:8082 (lub użyj podglądu w przeglądarce na porcie 8082 w Cloud Shell).

Zadaj agentowi ds. podróży złożone pytanie, które wymaga użycia obu narzędzi:

„Planuję wyjazd do Londynu. Jaka jest pogoda i ile to jest 200 EUR w GBP?”

Obserwuj przepływ wykonywania:

  1. Agent biura podróży otrzymuje prośbę w interfejsie internetowym.
  2. Przekazuje pytanie o pogodę do lokalnego weather_agent, który pobiera aktualne warunki z wttr.in.
  3. Przekazuje przeliczanie waluty przez protokół A2A do currency_agent na porcie 8081.
  4. currency_agent wywołuje currency_mcp_server na porcie 8080 przez MCP, aby pobrać kurs wymiany.
  5. Wszystkie wyniki są syntetyzowane i zwracane w postaci ujednoliconej, pomocnej odpowiedzi.

Agent ADK Web Remote Currency

Testowanie za pomocą wiersza poleceń

Możesz też testować zapytania bezpośrednio z interfejsu wiersza poleceń bez otwierania przeglądarki:

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

Teraz, gdy wszystko działa bezproblemowo na Twoim komputerze lokalnym, wdróżmy cały system w Google Cloud Run.

9. Wdrażanie systemu wieloagentowego w Cloud Run

Każdy komponent ma własny plik Dockerfile i samodzielny plik pyproject.toml, dzięki czemu można go skompilować i wdrożyć niezależnie w Cloud Run.

Za pomocą gcloud wdrożysz każdą usługę i automatycznie połączysz ich adresy URL.

Ustawianie zmiennych środowiskowych

Ustaw identyfikator projektu w chmurze i region docelowy:

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

Krok 1. Wdróż serwer MCP Currency

Wdróż serwer MCP bezpośrednio ze źródła:

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

Krok 2. Wdróż agenta walutowego

Publiczny adres URL usługi currency-agent jest przypisywany podczas jej pierwszego wdrożenia, dlatego najpierw wdróż usługę, przechwyć jej adres URL i zaktualizuj zmienną środowiskową AGENT_URL, aby karta agenta A2A reklamowała prawidłowy publiczny adres 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"

Krok 3. Wdróż agenta ds. podróży

Teraz wdróż agenta biura podróży, konfigurując go za pomocą 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. Testowanie systemu wieloagentowego w Cloud Run

Po wdrożeniu wszystkich 3 mikrousług sprawdźmy każdą warstwę w Cloud Run.

1. Testowanie zdalnego serwera MCP

Przetestuj wdrożony serwer MCP Cloud Run z poziomu wiersza poleceń:

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

Narzędzie powinno być widoczne na liście i zostać wywołane w Cloud Run.

2. Testowanie agenta walutowego przez A2A

Przetestuj wdrożonego agenta walutowego za pomocą klienta testowego A2A:

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

Klient pobierze zdalną kartę agenta z Cloud Run i będzie wymieniać wiadomości przez HTTPS JSON-RPC.

3. Testowanie interfejsu internetowego biura podróży w Cloud Run

Otwórz $TRAVEL_AGENT_URL w przeglądarce.

Kompletny interfejs internetowy ADK jest udostępniany bezpośrednio z Cloud Run. Spróbuj zapytać:

„Planuję wyjazd do Tokio. Jaka jest pogoda i ile to jest 500 USD w 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)

Wszystkie 3 usługi skalują się niezależnie w infrastrukturze bezserwerowej i komunikują się bezproblemowo za pomocą otwartych protokołów.

11. Gratulacje i sprzątanie

osiągnięcia,

Gratulacje! Udało Ci się utworzyć i wdrożyć system wieloagentowy klasy produkcyjnej:

  • Model Context Protocol (MCP): utworzyliśmy serwer FastMCP, który udostępnia narzędzia Live API przez Streamable HTTP.
  • Pakiet Agent Development Kit (ADK): utworzono modułowych agentów za pomocą LlmAgent, połączono narzędzia MCP z McpToolset i hostowano interfejs internetowy ADK.
  • Protokół Agent2Agent (A2A): udostępniono agenta jako usługę A2A (to_a2a), opublikowano karty agenta (agent-card.json) i wykorzystano zdalnych agentów za pomocą RemoteA2aAgent.
  • Architektura z wieloma agentami: połączone lokalne subagenty w procesie (weather_agent) z rozproszonymi agentami zdalnymi (currency_agent).
  • Wdrożenie bezserwerowe Cloud Run: wszystkie 3 usługi zostały skonteneryzowane i wdrożone z automatyczną konfiguracją połączeń.

Pełny kod (w tym implementacje w językach Python i Java) oraz przyszłe aktualizacje znajdziesz w repozytorium getting-started-mcp-a2a-adk.

Czyszczenie danych

Aby uniknąć obciążenia konta Google Cloud opłatami za usługi Cloud Run utworzone w tym ćwiczeniu:

Usuń wdrożone usługi 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

Jeśli na potrzeby tego ćwiczenia został przez Ciebie utworzony osobny projekt, możesz go zamknąć:

gcloud projects delete $PROJECT_ID