شروع به کار با MCP و A2A با ADK

۱. نمای کلی

محبوبیت عامل‌های هوش مصنوعی به‌سرعت درحال افزایش است و با توانایی‌شان در عملکرد مستقل، یادگیری، و تعامل با محیط برای دستیابی به اهداف، انقلابی در خودکارسازی تکالیف و تصمیم‌گیری ایجاد کرده‌اند.

این codelab به شما کمک می‌کند تا با ساختن یک سیستم چندعاملی سرتاسری شروع به کار کنید. شما یک سرور MCP ارز خواهید ساخت، یک عامل ارز خواهید ساخت که از سرور MCP استفاده می‌کند و ازطریق پروتکل Agent2Agent (A2A) درمعرض دید قرار می‌گیرد، یک آژانس مسافرتی با یک عامل فرعی آب‌وهوا درحال پردازش خواهید ساخت که از عامل ارز ازطریق A2A استفاده می‌کند، و درنهایت همه سرویس‌ها را در Cloud Run مستقر خواهید کرد.

معماری

فناوری‌های اصلی

پروتکل بافتار مدل (MCP)

Model Context Protocol (MCP) یک پروتکل باز است که نحوه ارائه بافت و ابزارها به مدل‌های زبانی بزرگ توسط برنامه‌ها را استانداردسازی می‌کند. MCP را مانند درگاه USB-C برای برنامه‌های هوش مصنوعی درنظر بگیرید: این پروتکل روشی استاندارد برای اتصال مدل‌های هوش مصنوعی به منابع داده خارجی، میاناهای برنامه‌سازی کاربردی، و ابزارها ارائه می‌دهد.

در این codelab،‏ currency_mcp_server ابزار get_exchange_rate را ازطریق Streamable HTTP‏ (/mcp) که توسط Frankfurter API عمومی پشتیبانی می‌شود، نمایش می‌دهد.

Agent Development Kit (ADK)

Agent Development Kit (ADK) چارچوب هماهنگی انعطاف‌پذیری برای توسعه و مستقر کردن عامل‌های هوش مصنوعی است. ‫ADK مستقل از مدل و مستقل از استقرار است و برای سازگاری با چارچوب‌های دیگر ساخته شده است. ‫ADK توسعه عامل را شبیه به مهندسی نرم‌افزار استاندارد می‌کند و ایجاد، آزمایش، و هماهنگ‌سازی گردش کارهای عامل‌گرای پیچیده را آسان می‌سازد.

‫ADK مکالمه‌های کاربر را مدیریت می‌کند، «رابط کاربری وب» تعاملی را ارائه می‌دهد، ازطریق McpToolset به ابزارهای MCP متصل می‌شود، و ارتباطات A2A را مدیریت می‌کند.

پروتکل Agent2Agent (A2A)

پروتکل Agent2Agent (A2A) یک استاندارد باز است که برای فعال کردن ارتباط و همکاری بین عامل‌های هوش مصنوعی طراحی شده است. درست همان‌طور که MCP اتصالات عامل به ابزار را استاندارد می‌کند، A2A همکاری عامل به عامل را استاندارد می‌کند! در دنیایی که عامل‌ها در چارچوب‌ها، محیط‌های میزبانی، و سازمان‌های مختلف ساخته می‌شوند، A2A زبان مشترکی برای کاوش و واگذاری تکلیف ارائه می‌دهد.

‫ADK‏ currency_agent را به‌عنوان سرویس A2A‏ (to_a2a) نمایش می‌دهد و به travel_agent اجازه می‌دهد آن را از راه دور به‌عنوان AgentTool‏ (RemoteA2aAgent) مصرف کند.

عامل‌های فرعی محلی درمقابل عامل‌های A2A ازراه‌دور

این معماری الگوی مهمی را در طراحی چندعاملی برجسته می‌کند:

  • Local Agent Tool (weather_agent): Runs in-process within the orchestrator as an AgentTool, with zero network latency or protocol serialization overhead.
  • ابزار نماینده از راه دور (currency_agent): به‌عنوان یک ریزسرویس مستقل اجرا می‌شود که ازطریق پروتکل A2A در سراسر شبکه فراخوانی می‌شود.

آنچه خواهید آموخت

  • نحوه ایجاد و آزمایش سرور MCP محلی بااستفاده از FastMCP ازطریق HTTP جاری‌سازی‌شدنی
  • نحوه ساختن «عامل» با ADK که از ابزارهای MCP استفاده می‌کند (McpToolset)
  • نحوه نمایش دادن عامل ADK به‌عنوان سرور A2A‏ (to_a2a)
  • نحوه آزمایش سرور A2A بااستفاده از «کارخواه پایتون A2A»‏ (a2a.client)
  • نحوه ساختن عامل هماهنگ‌کننده که ابزارهای عامل فرعی محلی را با عامل‌های A2A راه دور ترکیب می‌کند
  • نحوه اجرا و آزمایش کردن سیستم چندعاملی کامل به‌صورت محلی با ADK Web UI
  • نحوه کانتینرسازی و استقرار هر سه مؤلفه در Google Cloud Run

آنچه نیاز خواهید داشت

  • مرورگری مانند Chrome.
  • پروژه Google Cloud با صورت‌حساب فعال.

۲. قبل‌از شروع

ایجاد کردن پروژه

اگر پروژه Google Cloud ندارید، پروژه‌ای ایجاد کنید.

در کنسول Google Cloud، در صفحه انتخابگر پروژه، یک پروژه Google Cloud را انتخاب یا ایجاد کنید.

همچنین مطمئن شوید که صورت‌حساب برای پروژه Cloud شما فعال باشد. با نحوه بررسی فعال بودن صورت‌حساب در پروژه آشنا شوید.

فعال کردن Cloud Shell

Google Cloud Shell محیطی تعاملی و مبتنی بر مرورگر برای توسعه نرم‌افزار است که مستقیماً در «کنسول Google Cloud» ارائه می‌شود. این ساده‌ترین راه برای شروع کار با Google Cloud بدون نیاز به نصب ابزارها به‌صورت محلی است.

با کلیک کردن روی این پیوند، Cloud Shell را فعال کنید. با کلیک کردن روی دکمه مربوطه در Cloud Shell، می‌توانید بین Cloud Shell Terminal (برای اجرای فرمان‌های ابری) و Editor (برای مشاهده فایل‌ها) جابه‌جا شوید.

پس‌از اتصال به 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

میاناهای برنامه‌سازی کاربردی لازم را برای 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 یک مدیر پروژه و بسته پایتون سریع است. این ابزار ازپیش در 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 (کلید میانای برنامه‌سازی کاربردی محلی)

اگر ترجیح می‌دهید از کلید میانای برنامه‌سازی کاربردی از Google AI Studio استفاده کنید:

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

۳. ایجاد کردن سرور MCP ارز

قبل‌از ایجاد کردن عامل‌هایتان، ابتدا سرور MCP را که ابزار تبدیل ارز را ارائه می‌دهد کاوش خواهید کرد.

سرور MCP به شما امکان می‌دهد برنامه‌های سبک بنویسید تا قابلیت‌ها را به‌عنوان ابزار ارائه دهید. سپس یک عامل (یا چند عامل) می‌تواند بااستفاده از پروتکل بافت مدل استانداردشده به این ابزارها دسترسی پیدا کند.

از بسته پایتون 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 با نقطه پایانی 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

اسکریپت آزمایشی بااستفاده از Client FastMCP به نقطه پایان MCP متصل می‌شود، ابزارها را فهرست می‌کند، و 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 فعال دارید که ابزار ارز زنده را نمایش می‌دهد. این پایانه را برای مراحل بعدی باز نگه دارید.

۴. ساختن «عامل ارز» با ADK

اکنون زمان ایجاد «عامل ارز» بااستفاده از Agent Development Kit (ADK) است.

‫ADK ازطریق کلاس McpToolset پشتیبانی داخلی برای ابزارهای MCP ارائه می‌دهد. «عامل ارز» بااستفاده از StreamableHTTPConnectionParams به سرور MCP ما متصل می‌شود.

به تعریف عامل واحد پول در 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 باز کنید (یا روی پیش‌نمایش وب در Cloud Shell کلیک کنید).

عامل واحد پول وب ADK

از عامل بپرسید:

«۲۵۰ دلار امریکا چند یورو می‌شود؟»

خواهید دید که نماینده ابزار MCP get_exchange_rate را فراخوانی می‌کند و مبلغ تبدیل‌شده را برمی‌گرداند. قبل‌از ادامه دادن، فرایند adk web را بااستفاده از Ctrl+C متوقف کنید.

۵. پروتکل Agent2Agent (A2A)

پروتکل Agent2Agent (A2A) یک استاندارد باز است که برای فعال کردن ارتباط و همکاری بین عامل‌های هوش مصنوعی طراحی شده است.

در سیستم‌های چندعاملی مدرن، عامل‌ها اغلب بااستفاده از چارچوب‌های مختلف (ADK،‏ LangChain،‏ CrewAI،‏ AutoGen) ساخته می‌شوند و در زیرساخت‌های مختلف مستقر می‌شوند. A2A با تعریف یک قرارداد ارتباطی استاندارد، این سیلوها را ازبین می‌برد.

پروتکل A2A

مفاهیم کلیدی A2A

  • کاوش عامل (کارت عامل): هر عامل سازگار با A2A قابلیت‌ها، حالت‌های ورودی/خروجی پشتیبانی‌شده، الزامات اصالت‌سنجی، و مهارت‌های خود را ازطریق یک فایل JSON استاندارد میزبانی‌شده در /.well-known/agent-card.json تبلیغ می‌کند.
  • مهارت‌های عامل (AgentSkill): قابلیت‌ها یا ابزارهای خاصی که عامل می‌تواند اجرا کند. نماینده‌های دیگر این مهارت‌ها را می‌خوانند تا تصمیم بگیرند چه زمانی تکالیف را واگذار کنند.
  • ارتباط JSON-RPC: عامل‌ها پیام‌ها، تکالیف، و مصنوعات ساختاریافته را ازطریق انتقال‌های استاندارد مانند HTTP JSON-RPC 2.0 مبادله می‌کنند.

کارت عامل A2A

در مرحله بعد، «عامل ارز ADK» ما را به‌عنوان سرور A2A نمایش خواهید داد تا سایر عامل‌ها بتوانند آن را پیدا کنند و کارهای تبدیل ارز را به آن واگذار کنند!

‫۶. افشا کردن «عامل ارز» به‌عنوان «سرور A2A»

‫ADK با تابع سودمندی to_a2a() تبدیل هر 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. یک A2A AgentCard تولید می‌کند که مهارت‌هایش را توصیف می‌کند (مثلاً currency_agent-get_exchange_rate).
  3. عامل را در برنامه FastAPI‏ (a2a_app) که از نقاط پایانی JSON-RPC پشتیبانی می‌کند می‌پیچد.
  4. Dynamically configures the advertised url in the Agent Card based on AGENT_URL (or 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 کاملاً کاربردی عمل می‌کند!

‫۷. ساختن «کارگزار مسافرتی»

اکنون نماینده سفر هماهنگ‌کننده را خواهید ساخت. این عامل نشان می‌دهد که چگونه یک عامل ADK می‌تواند به‌راحتی دو الگوی ابزار مختلف را ترکیب کند:

  1. ابزار عامل محلی (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 |
+-------------------------+                 +-------------------------+

۱. زیرعامل آب‌وهوای محلی

نگاهی به 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 با یک بازگشت ارتجاعی واکشی می‌کند.

۲. هماهنگ‌کننده کارگزار مسافرتی

اکنون به 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) راه‌اندازی می‌کند.

‫۸. اجرا و آزمایش کردن «سیستم چندعاملی» به‌صورت محلی

اکنون هر سه مؤلفه را آماده کرده‌اید! بیایید کل سیستم را به‌صورت محلی اجرا و آزمایش کنیم.

درحال اجرای هر سه سرویس

مطمئن شوید سرویس‌ها در سه پنجره پایانه جداگانه (از فهرست راهنمای getting-started-mcp-a2a-adk/python) به‌ترتیب زیر اجرا می‌شوند:

پایانه ۱ (سرور MCP ارز):

uv run python currency_mcp_server/server.py

(درحال اجرا در درگاه ۸۰۸۰)

پایانه ۲ (عامل A2A ارز):

uv run python currency_agent/agent.py

(درحال اجرا در درگاه ۸۰۸۱)

پایانه ۳ (کارگزار مسافرتی با میانای وب):

uv run python travel_agent/agent.py

(درحال اجرا در درگاه ۸۰۸۲)

آزمایش کردن ازطریق واسط کاربر وب ADK

مرورگرتان را در http://localhost:8082 باز کنید (یا از پیش‌نمایش وب در درگاه ۸۰۸۲ در Cloud Shell استفاده کنید).

از «کارگزار مسافرتی» سؤال مرکبی بپرسید که به هر دو ابزار نیاز داشته باشد:

«قصد دارم به لندن سفر کنم. آب‌وهوا چطور است و ۲۰۰ یورو چند پوند می‌شود؟»

تماشای جریان اجرا:

  1. کارگزار مسافرتی درخواست را در «رابط کاربری وب» دریافت می‌کند.
  2. این مدل پرسش مربوط به آب‌وهوا را در فرایند به weather_agent محلی واگذار می‌کند که شرایط فعلی را از wttr.in واکشی می‌کند.
  3. این قانون تبدیل ارز را ازطریق پروتکل A2A به currency_agent در درگاه ۸۰۸۱ واگذار می‌کند.
  4. ‫currency_agent با currency_mcp_server در درگاه ۸۰۸۰ ازطریق 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 مستقر کنیم!

‫۹. مستقر کردن سیستم چندعاملی در Cloud Run

هر مؤلفه Dockerfile و pyproject.toml مستقل خودش را دارد تا بتواند به‌طور مستقل در Cloud Run ساخته و مستقر شود.

بااستفاده از gcloud، هر سرویس را مستقر خواهید کرد و نشانی‌های وب آن‌ها را به‌طور خودکار به یکدیگر متصل خواهید کرد.

تنظیم متغیرهای محیط

شناسه پروژه Cloud و منطقه هدف را تنظیم کنید:

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

مرحله ۱: پیاده‌سازی کردن سرور MCP ارز

سرور 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"

مرحله ۲: استقرار عامل ارز

ازآنجایی‌که نشانی وب عمومی currency-agent در اولین استقرار آن اختصاص داده می‌شود، ابتدا سرویس را مستقر کنید، نشانی وب آن را ضبط کنید، و متغیر محیطی 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"

مرحله ۳: استقرار «کارگزار مسافرتی»

اکنون «کارگزار مسافرتی» را مستقر کنید و آن را با 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"

‫۱۰. آزمایش کردن سیستم چندعاملی در Cloud Run

با استقرار هر سه ریزخدمات، بیایید هر لایه را در Cloud Run تأیید کنیم.

۱. آزمایش کردن سرور MCP ازراه‌دور

سرور Cloud Run MCP مستقرشده را از خط فرمان آزمایش کنید:

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

باید ابزار را در فهرست ببینید و باموفقیت در Cloud Run فراخوانی شده باشد.

۲. آزمایش کردن «عامل واحد پول» ازطریق A2A

«عامل ارز» مستقرشده را بااستفاده از کارخواه آزمایشی A2A آزمایش کنید:

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

کارخواه «کارت نماینده» راه دور را از Cloud Run واکشی می‌کند و پیام‌ها را ازطریق HTTPS JSON-RPC ردوبدل می‌کند.

۳. آزمایش کردن «رابط کاربری وب کارگزار مسافرتی» در Cloud Run

$TRAVEL_AGENT_URL را در مرورگرتان باز کنید!

رابط کاربری وب ADK کامل مستقیماً از Cloud Run ارائه می‌شود. این پرسش‌ها را امتحان کنید:

«قصد دارم به توکیو سفر کنم. آب‌وهوا چطور است و ۵۰۰ دلار امریکا چند ین ژاپن می‌شود؟»

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

هر سه سرویس به‌طور مستقل در زیرساخت بدون سرور مقیاس‌بندی می‌شوند و به‌طور یکپارچه ازطریق پروتکل‌های باز ارتباط برقرار می‌کنند!

‫۱۱. تبریک و پاک‌سازی

آنچه انجام داده‌اید

تبریک! سیستم چندعاملی در سطح تولید را ساخته و مستقر کرده‌اید:

  • پروتکل زمینه‌ای مدل (MCP): یک سرور FastMCP ایجاد کرد که ابزارهای API زنده را ازطریق HTTP قابل‌جاری‌سازی نمایش می‌دهد.
  • Agent Development Kit (ADK): عامل‌های مدولار را بااستفاده از LlmAgent ساختید، ابزارهای MCP را با McpToolset متصل کردید، و ADK Web UI را میزبانی کردید.
  • پروتکل 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 ایجادشده در این codelab:

سرویس‌های مستقرشده 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

یا اگر پروژه اختصاصی برای این codelab ایجاد کرده‌اید، می‌توانید کل پروژه را خاموش کنید:

gcloud projects delete $PROJECT_ID