תחילת העבודה עם MCP, ‏ ADK ו-A2A

תחילת העבודה עם MCP, ‏ ADK ו-A2A

מידע על Codelab זה

subjectהעדכון האחרון: יוני 25, 2025
account_circleנכתב על ידי Jack Wotherspoon

1.‏ סקירה כללית

סוכני AI צוברים פופולריות במהירות, ומשנים את האופן שבו אנחנו מבצעים אוטומציה של משימות ומקבלים החלטות. הם יכולים לפעול באופן אוטונומי, ללמוד ולקיים אינטראקציה עם הסביבה כדי להשיג יעדים.

אבל איך בדיוק יוצרים סוכן? בשיעור הזה של Codelab נלמד איך ליצור סוכן מטבע שיכול להמיר בין מטבעות שונים של מדינות שונות. המטרה היא להסביר על הטכנולוגיות העדכניות כדי לעזור לכם להבין את ראשי התיבות שראיתם באינטרנט (MCP, ‏ ADK, ‏ A2A).

ארכיטקטורה

Model Context Protocol (MCP)

Model Context Protocol (פרוטוקול הקשר של מודלים,‏ MCP) הוא פרוטוקול פתוח שמגדיר איך אפליקציות מספקות הקשר ל-LLM. ‫MCP מספק דרך סטנדרטית לחבר מודלים של AI למשאבים, להנחיות ולכלים.

ערכת פיתוח של סוכנים (ADK)

Agent Development Kit (ADK) היא מסגרת גמישה לניהול תהליכים, שמאפשרת לפתח ולפרוס סוכני AI. ערכת ה-ADK לא תלויה במודל או בפריסה, והיא מיועדת לתאימות עם מסגרות אחרות. ה-ADK נועד להפוך את פיתוח הסוכנים לתהליך שדומה יותר לפיתוח תוכנה, כדי להקל על מפתחים ליצור, לפרוס ולתזמר ארכיטקטורות של סוכנים שמבצעים משימות פשוטות ועד תהליכי עבודה מורכבים.

פרוטוקול Agent2Agent (A2A)

הפרוטוקול Agent2Agent (A2A) הוא תקן פתוח שנועד לאפשר תקשורת ושיתוף פעולה חלקים בין סוכני AI. בדומה ל-MCP, שמספק דרך סטנדרטית להעניק למודלים גדולים של שפה (LLM) גישה לנתונים ולכלים, A2A מספק דרך סטנדרטית לסוכנים לתקשר עם סוכנים אחרים. בעולם שבו סוכנים נבנים באמצעות מסגרות מגוונות ועל ידי ספקים שונים, A2A מספק שפה משותפת, מבטל את הבידוד ומקדם יכולת פעולה הדדית.

מה תלמדו

  • איך יוצרים שרת MCP מקומי
  • פריסת שרת ה-MCP ב-Cloud Run
  • איך יוצרים סוכן באמצעות ערכת פיתוח סוכנים שמשתמשת בכלים של MCP
  • איך חושפים סוכן ADK כשרת A2A
  • בדיקת שרת A2A באמצעות לקוח A2A

מה צריך בשביל להצטרף

  • דפדפן, כמו Chrome או Firefox
  • פרויקט ב-Google Cloud שהחיוב בו מופעל.

2.‏ לפני שמתחילים

יצירת פרויקט

  1. במסוף Google Cloud, בדף לבחירת הפרויקט, בוחרים או יוצרים פרויקט ב-Google Cloud.
  2. הקפידו לוודא שהחיוב מופעל בפרויקט שלכם ב-Cloud. כך בודקים אם החיוב מופעל בפרויקט
  3. לוחצים על הקישור הזה כדי להפעיל את Cloud Shell. אפשר לעבור בין Cloud Shell Terminal (להפעלת פקודות בענן) לבין Editor (לבניית פרויקטים) בלחיצה על הלחצן המתאים ב-Cloud Shell.
  4. אחרי שמתחברים ל-Cloud Shell, בודקים שכבר בוצע אימות ושהפרויקט מוגדר למזהה הפרויקט באמצעות הפקודה הבאה:
gcloud auth list
  1. מריצים את הפקודה הבאה ב-Cloud Shell כדי לוודא שפקודת gcloud מכירה את הפרויקט שלכם.
gcloud config list project
  1. משתמשים בפקודה הבאה כדי להגדיר את הפרויקט:
export PROJECT_ID=<YOUR_PROJECT_ID>
gcloud config set project $PROJECT_ID
  1. מפעילים את ממשקי ה-API הנדרשים באמצעות הפקודה הבאה. היא עשויה להימשך כמה דקות.
gcloud services enable cloudresourcemanager.googleapis.com \
                       
servicenetworking.googleapis.com \
                       
run.googleapis.com \
                       
cloudbuild.googleapis.com \
                       
artifactregistry.googleapis.com \
                       
aiplatform.googleapis.com \
                       
compute.googleapis.com
  1. מוודאים שמותקנת גרסה Python 3.10 ומעלה

אפשר לעיין במסמכי התיעוד בנושא פקודות ושימוש ב-gcloud.

3.‏ התקנה

  1. משכפלים את המאגר:
git clone https://github.com/jackwotherspoon/currency-agent.git
cd currency-agent
  1. מתקינים את uv (משמש לניהול יחסי תלות):
# macOS and Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows (uncomment below line)
# powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
  1. הגדרת משתני סביבה (באמצעות קובץ .env):

יוצרים קובץ .env על ידי הרצת הפקודה הבאה:

echo "GOOGLE_GENAI_USE_VERTEXAI=TRUE" >> .env \
&& echo "GOOGLE_CLOUD_PROJECT=$PROJECT_ID" >> .env \
&& echo "GOOGLE_CLOUD_LOCATION=us-central1" >> .env

4.‏ יצירת שרת MCP מקומי

לפני שתתחילו לתזמן את סוכן המטבעות, תצטרכו ליצור שרת MCP כדי לחשוף את הכלים שהסוכן יצטרך.

שרת MCP מאפשר לכם לכתוב תוכנות קלות משקל כדי לחשוף יכולות ספציפיות (כמו אחזור של שערי חליפין) ככלים. סוכן AI אחד או כמה סוכני AI יכולים לגשת לכלים האלה באמצעות Model Context Protocol (פרוטוקול הקשר של המודל) סטנדרטי.

אפשר להשתמש בחבילת Python‏ FastMCP כדי ליצור שרת MCP שחושף כלי יחיד בשם get_exchange_rate. הכלי get_exchange_rate מבצע קריאה באינטרנט ל-Frankfurter API כדי לקבל את שער החליפין הנוכחי בין שני מטבעות.

הקוד של שרת ה-MCP נמצא בקובץ mcp-server/server.py:

import logging
import os

import httpx
from fastmcp import FastMCP

# Set up logging
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.app/{currency_date}',
           
params={'from': currency_from, 'to': currency_to},
       
)
       
response.raise_for_status()

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

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

כדי להפעיל את שרת ה-MCP באופן מקומי, פותחים טרמינל ומריצים את הפקודה הבאה (השרת יופעל בכתובת http://localhost:8080):

uv run mcp-server/server.py

בודקים ששרת ה-MCP פועל כמו שצריך ושניתן לגשת לכלי get_exchange_rate באמצעות פרוטוקול הקשר של המודל.

בחלון טרמינל חדש (כדי לא לעצור את שרת ה-MCP המקומי), מריצים את הפקודה הבאה:

uv run mcp-server/test_server.py

שער החליפין הנוכחי של 1 דולר ארה"ב לאירו יוצג:

--- 🛠️ Tool found: get_exchange_rate ---
--- 🪛 Calling get_exchange_rate tool for USD to EUR ---
--- Success: {
 
"amount": 1.0,
 
"base": "USD",
 
"date": "2025-05-26",
 
"rates": {
   
"EUR": 0.87866
 
}
} ---

מדהים! יש לכם שרת MCP פעיל עם כלי שהסוכן יוכל לגשת אליו.

לפני שעוברים לתחנה הבאה, עוצרים את שרת ה-MCP שפועל באופן מקומי על ידי הפעלת הפקודה Ctrl+C (או Command+C ב-Mac) במסוף שבו הפעלתם אותו.

5.‏ פריסת שרת ה-MCP ב-Cloud Run

עכשיו אפשר לפרוס את שרת ה-MCP כשרת MCP מרוחק ב-Cloud Run 🚀☁️

היתרונות בהפעלת שרת MCP מרחוק

להפעלת שרת MCP מרחוק ב-Cloud Run יש כמה יתרונות:

  • 📈יכולת הרחבה: Cloud Run מיועד להרחבה מהירה כדי לטפל בכל הבקשות הנכנסות. שרת ה-MCP יותאם אוטומטית ב-Cloud Run בהתאם לביקוש.
  • 👥שרת מרכזי: אתם יכולים לשתף גישה לשרת MCP מרכזי עם חברי הצוות באמצעות הרשאות IAM, וכך לאפשר להם להתחבר אליו מהמחשבים המקומיים שלהם במקום להפעיל שרתים משלהם באופן מקומי. אם יבוצע שינוי בשרת MCP, כל חברי הצוות ייהנו ממנו.
  • 🔐אבטחה: Cloud Run מספק דרך קלה לאכיפת בקשות מאומתות. כך אפשר לאפשר רק חיבורים מאובטחים לשרת ה-MCP ולמנוע גישה לא מורשית.

עוברים לספרייה mcp-server:

cd mcp-server

פורסים את שרת ה-MCP ב-Cloud Run:

gcloud run deploy mcp-server --no-allow-unauthenticated --region=us-central1 --source .

אם הפריסה של השירות הושלמה בהצלחה, תוצג הודעה כמו זו:

Service [mcp-server] revision [mcp-server-12345-abc] has been deployed and is serving 100 percent of traffic.

אימות לקוחות של MCP

מכיוון שציינתם --no-allow-unauthenticated כדי לדרוש אימות, כל לקוח MCP שמתחבר לשרת MCP מרוחק יצטרך לעבור אימות.

במסמכים הרשמיים בנושא אירוח שרתי MCP ב-Cloud Run יש מידע נוסף על הנושא הזה, בהתאם למקום שבו מריצים את לקוח ה-MCP.

תצטרכו להריץ את Cloud Run proxy כדי ליצור מנהרה מאומתת לשרת MCP המרוחק במחשב המקומי.

כברירת מחדל, כדי לגשת לכתובת ה-URL של שירותי Cloud Run, צריך לאשר את כל הבקשות באמצעות תפקיד ה-IAM‏ Cloud Run Invoker‏ (roles/run.invoker). הקישור הזה של מדיניות IAM מבטיח שמנגנון אבטחה חזק ישמש לאימות של לקוח MCP מקומי.

צריך לוודא שלכם או לכל חבר צוות שמנסה לגשת לשרת ה-MCP המרוחק יש את תפקיד ה-IAM‏ roles/run.invoker שמשויך לישות ה-IAM (חשבון Google Cloud).

gcloud run services proxy mcp-server --region=us-central1

הפלט הבא אמור להתקבל:

Proxying to Cloud Run service [mcp-server] in project [<YOUR_PROJECT_ID>] region [us-central1]
http://127.0.0.1:8080 proxies to https://mcp-server-abcdefgh-uc.a.run.app

כל התנועה אל http://127.0.0.1:8080 תאומת ותועבר לשרת ה-MCP המרוחק.

בדיקת שרת ה-MCP המרוחק

בטרמינל חדש, חוזרים לתיקיית הבסיס ומריצים מחדש את קובץ mcp-server/test_server.py כדי לוודא ששרת ה-MCP המרוחק פועל.

cd ..
uv run mcp-server/test_server.py

הפלט שיוצג יהיה דומה לזה שהוצג כשמריצים את השרת באופן מקומי:

--- 🛠️ Tool found: get_exchange_rate ---
--- 🪛 Calling get_exchange_rate tool for USD to EUR ---
--- Success: {
 
"amount": 1.0,
 
"base": "USD",
 
"date": "2025-05-26",
 
"rates": {
   
"EUR": 0.87866
 
}
} ---

אם רוצים לוודא שהייתה קריאה לשרת המרוחק, אפשר להריץ שאילתה ביומנים של שרת ה-MCP של Cloud Run שנפרס:

gcloud run services logs read mcp-server --region us-central1 --limit 5

הפלט הבא אמור להופיע ביומנים:

2025-06-04 14:28:29,871 [INFO]: --- 🛠️ Tool: get_exchange_rate called for converting USD to EUR ---
2025-06-04 14:28:30,610 [INFO]: HTTP Request: GET https://api.frankfurter.app/latest?from=USD&to=EUR "HTTP/1.1 200 OK"
2025-06-04 14:28:30,611 [INFO]: API response: {'amount': 1.0, 'base': 'USD', 'date': '2025-06-03', 'rates': {'EUR': 0.87827}}

עכשיו, אחרי שיש לכם שרת MCP מרוחק, אפשר להמשיך ליצירת סוכן. 🤖

6.‏ יצירת סוכן באמצעות ערכת פיתוח סוכנים (ADK)

אחרי שפרסתם שרת MCP, הגיע הזמן ליצור את סוכן המטבע באמצעות ערכת פיתוח סוכנים (ADK).

לאחרונה הושקה גרסה יציבה של Agent Development Kit‏ (ADK) – גרסה 1.0.0. ההישג הזה מציין שערכת ה-ADK של Python מוכנה עכשיו לשימוש בסביבת ייצור, ומציעה פלטפורמה אמינה וחזקה למפתחים כדי לבנות ולפרוס את הסוכנים שלהם בסביבות פעילות.

ערכת ה-ADK מאפשרת ליצור סוכנים קלים מאוד ולחבר אותם בקלות לשרתי MCP עם תמיכה מובנית ב-MCP Tools. סוכן המטבע יגש לכלי get_exchange_rate באמצעות המחלקה MCPToolset של ADK.

הקוד של סוכן המטבע נמצא ב-currency_agent/agent.py:

import logging
import os

from dotenv import load_dotenv
from google.adk.agents import LlmAgent
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."
)

def create_agent() -> LlmAgent:
    """Constructs the ADK currency conversion agent."""
   
logger.info("--- 🔧 Loading MCP tools from MCP Server... ---")
   
logger.info("--- 🤖 Creating ADK Currency Agent... ---")
   
return LlmAgent(
       
model="gemini-2.5-flash",
       
name="currency_agent",
       
description="An agent that can help with currency conversions",
       
instruction=SYSTEM_INSTRUCTION,
       
tools=[
           
MCPToolset(
               
connection_params=StreamableHTTPConnectionParams(
                   
url=os.getenv("MCP_SERVER_URL", "http://localhost:8080/mcp")
               
)
           
)
       
],
   
)


root_agent = create_agent()

כדי לבדוק במהירות את סוכן המטבעות, אפשר להשתמש בממשק המשתמש למפתחים של ADK. כדי לגשת אליו, מריצים את הפקודה adk web:

uv run adk web

בדפדפן, עוברים אל http://localhost:8000 כדי לראות את הסוכן ולבדוק אותו.

מוודאים שהסמל currency_agent נבחר כסוכן בפינה הימנית העליונה של ממשק המשתמש האינטרנטי.

ממשק משתמש באינטרנט של ADK

אפשר לשאול את הסוכן באזור הצ'אט שאלה כמו "What is 250 CAD to USD?‎". אפשר לראות שהנציג מתקשר לכלי get_exchange_rate MCP שלנו לפני שהוא נותן תשובה.

ADK Web Currency Agent

הסוכן עובד! הוא יכול לטפל בשאילתות שקשורות להמרות מטבעות 💸.

7.‏ פרוטוקול Agent2Agent ‏ (A2A)

הפרוטוקול Agent2Agent (A2A) הוא תקן פתוח שנועד לאפשר תקשורת ושיתוף פעולה חלקים בין סוכני AI. הפרוטוקול מאפשר לסוכנים שנבנו באמצעות מסגרות מגוונות ועל ידי ספקים שונים לתקשר זה עם זה בשפה משותפת, וכך לשבור את המחסומים ולעודד פעולה הדדית.

פרוטוקול A2A

התכונה A2A מאפשרת לסוכנים:

  • גילוי: אפשר למצוא סוכנים אחרים וללמוד על הכישורים (AgentSkill) והיכולות (AgentCapabilities) שלהם באמצעות כרטיסי סוכנים סטנדרטיים.
  • תקשורת: החלפת הודעות ונתונים באופן מאובטח.
  • שיתוף פעולה: הקצאת משימות ותיאום פעולות להשגת יעדים מורכבים.

פרוטוקול A2A מאפשר את התקשורת הזו באמצעות מנגנונים כמו 'כרטיסי סוכן' שמשמשים ככרטיסי ביקור דיגיטליים שסוכנים יכולים להשתמש בהם כדי לפרסם את היכולות שלהם ואת פרטי החיבור שלהם.

כרטיס נציג A2A

עכשיו צריך לחשוף את סוכן המטבע באמצעות A2A כדי שסוכנים ולקוחות אחרים יוכלו לקרוא לו.

A2A Python SDK

A2A Python SDK מספק מודלים של Pydantic לכל אחד מהמשאבים שצוינו למעלה: AgentSkill, ‏ AgentCapabilities ו-AgentCard. הוא מספק ממשק להאצת הפיתוח והשילוב עם פרוטוקול A2A.

AgentSkill היא הדרך שבה תפרסמו לסוכנים אחרים שלסוכן המטבע יש כלי לget_exchange_rate:

# A2A Agent Skill definition
skill = AgentSkill(
   
id='get_exchange_rate',
   
name='Currency Exchange Rates Tool',
   
description='Helps with exchange values between various currencies',
   
tags=['currency conversion', 'currency exchange'],
   
examples=['What is exchange rate between USD and GBP?'],
)

לאחר מכן, כחלק מAgentCard, יפורטו הכישורים והיכולות של הסוכן לצד פרטים נוספים כמו מצבי קלט ופלט שהסוכן יכול לטפל בהם:

# A2A Agent Card definition
agent_card = AgentCard(
   
name='Currency Agent',
   
description='Helps with exchange rates for currencies',
   
url=f'http://{host}:{port}/',
   
version='1.0.0',
   
defaultInputModes=["text"],
   
defaultOutputModes=["text"],
   
capabilities=AgentCapabilities(streaming=True),
   
skills=[skill],
)

ממשק AgentExecutor מטפל בלוגיקה הבסיסית של אופן העיבוד של בקשות על ידי סוכן A2A ויצירת תגובות או אירועים. ה-SDK של A2A Python מספק מחלקה בסיסית מופשטת a2a.server.agent_execution.AgentExecutor שצריך להטמיע.

הגיע הזמן לשלב את הכל עם סוכן המטבעות ולהציג את העוצמה של A2A!

8.‏ שרת Currency Agent A2A

עכשיו נבחן כמה מקטעי קוד ונראה איך המקטעים השונים שמרכיבים שרת A2A משתלבים זה בזה.

אם נסתכל על הקובץ currency_agent/agent_executor.py, נראה את המחלקה ADKAgentExecutor שיורשת מהמחלקה המופשטת A2A AgentExecutor. הוא מטפל בקריאה לסוכן ADK על ידי הפעלת ADK runner, עיבוד בקשות לסוכן והמרה הלוך ושוב בין google.genai.types שמשמש את ADK לבין a2a.types שמשמש את A2A.

# ... see file for full code

class ADKAgentExecutor(AgentExecutor):
    """An AgentExecutor that runs an ADK agent."""

   
def __init__(self, runner: Runner, card: AgentCard):
       
self.runner = runner
       
self._card = card
       
self._running_sessions = {}

   
def _run_agent(
       
self, session_id, new_message: types.Content
   
) -> AsyncGenerator[Event, None]:
       
return self.runner.run_async(
           
session_id=session_id, user_id="self", new_message=new_message
       
)

   
async def _process_request(
       
self,
       
new_message: types.Content,
       
session_id: str,
       
task_updater: TaskUpdater,
   
) -> None:
       
session = await self._upsert_session(
           
session_id,
       
)
       
session_id = session.id
       
# Run through all events within the request.
       
async for event in self._run_agent(session_id, new_message):
           
if event.is_final_response():
               
parts = convert_genai_parts_to_a2a(event.content.parts)
               
logger.debug("✅ Yielding final response: %s", parts)
               
await task_updater.add_artifact(parts)
               
await task_updater.complete()
               
break
           
# If the agent is not making a function call, yield an update.
           
if not event.get_function_calls():
               
logger.debug("⏳ Yielding update response")
               
await task_updater.update_status(
                   
TaskState.working,
                   
message=task_updater.new_agent_message(
                       
convert_genai_parts_to_a2a(event.content.parts),
                   
),
               
)
           
else:
               
logger.debug("➡️ Skipping event")

   
async def execute(
       
self,
       
context: RequestContext,
       
event_queue: EventQueue,
   
):
       
# Run the agent until either complete or the task is suspended.
       
updater = TaskUpdater(event_queue, context.task_id, context.context_id)
       
# Immediately notify that the task is submitted.
       
if not context.current_task:
           
updater.submit()
       
updater.start_work()
       
await self._process_request(
           
types.UserContent(
               
parts=convert_a2a_parts_to_genai(context.message.parts),
           
),
           
context.context_id,
           
updater,
       
)
       
logger.debug("--- 💵💱💶 [Currency] execute exiting ---")

# ... see file for full code

בתוך currency_agent/__main__.py מתבצעת ההפעלה של AgentSkill ו-AgentCard, ונוצר סוכן המטבע של ADK. כאן גם מגדירים ומפעילים את שרת A2A.

‫A2A Python SDK מספק מחלקה A2AFastAPIApplication שמפשטת את ההפעלה של שרת HTTP שתואם ל-A2A. הוא משתמש ב-FastAPI למסגרת האינטרנט, ובדרך כלל מופעל עם שרת ASGI כמו Uvicorn.

# ... see file for full code
@click.command()
@click.option("--host", "host", default="localhost")
@click.option("--port", "port", default=10000)
def main(host: str, port: int):
   
# Verify one of Google AI Studio or Vertex AI is being used
   
if os.getenv("GOOGLE_GENAI_USE_VERTEXAI") != "TRUE" and not os.getenv(
       
"GOOGLE_API_KEY"
   
):
       
raise ValueError(
           
"GOOGLE_API_KEY environment variable not set and "
           
"GOOGLE_GENAI_USE_VERTEXAI is not TRUE."
       
)

   
# A2A Agent Skill definition
   
skill = AgentSkill(
       
id="get_exchange_rate",
       
name="Currency Exchange Rates Tool",
       
description="Helps with exchange values between various currencies",
       
tags=["currency conversion", "currency exchange"],
       
examples=["What is exchange rate between USD and GBP?"],
   
)

   
# A2A Agent Card definition
   
agent_card = AgentCard(
       
name="Currency Agent",
       
description="Helps with exchange rates for currencies",
       
url=f"http://{host}:{port}/",
       
version="1.0.0",
       
defaultInputModes=["text"],
       
defaultOutputModes=["text"],
       
capabilities=AgentCapabilities(streaming=True),
       
skills=[skill],
   
)

   
# Create the ADK runner and executor.
   
runner = Runner(
       
app_name=agent_card.name,
       
agent=root_agent,
       
artifact_service=InMemoryArtifactService(),
       
session_service=InMemorySessionService(),
       
memory_service=InMemoryMemoryService(),
   
)
   
agent_executor = ADKAgentExecutor(runner, agent_card)

   
request_handler = DefaultRequestHandler(
       
agent_executor=agent_executor,
       
task_store=InMemoryTaskStore(),
   
)

   
server = A2AFastAPIApplication(
       
agent_card=agent_card, http_handler=request_handler
   
)

   
uvicorn.run(server.build(), host=host, port=port)
# ... see file for full code

כדי להריץ את שרת A2A, מריצים את הפקודה הבאה בטרמינל חדש:

uv run currency_agent/

אם השרת יופעל בהצלחה, הפלט ייראה כך ויציין שהוא פועל ביציאה 10000:

[INFO]: --- 🔧 Loading MCP tools from MCP Server... ---
[INFO]: --- 🤖 Creating ADK Currency Agent... ---
INFO:     Started server process [45824]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://localhost:10000 (Press CTRL+C to quit)

סוכן המטבעות פועל עכשיו בהצלחה כשרת A2A, ויש לו אפשרות לקבל קריאות מסוכנים או מלקוחות אחרים באמצעות פרוטוקול A2A.

בדיקת שרת A2A

עכשיו אפשר לבדוק את השרת על ידי שליחת כמה בקשות באמצעות A2A.

‫A2A Python SDK מספק מחלקה a2a.client.A2AClient שמפשטת את התהליך הזה.

הקובץ currency_agent/test_client.py מכיל קוד שמופעל באמצעות כמה תרחישי בדיקה שונים מול שרת A2A.

# ... see file for full code

# Example test using A2AClient
async def run_single_turn_test(client: A2AClient) -> None:
    """Runs a single-turn non-streaming test."""

   
send_message_payload = create_send_message_payload(text="how much is 100 USD in CAD?")
   
request = SendMessageRequest(
       
id=str(uuid4()), params=MessageSendParams(**send_message_payload)
   
)

   
print("--- ✉️  Single Turn Request ---")
   
# Send Message
   
response: SendMessageResponse = await client.send_message(request)
   
print_json_response(response, "📥 Single Turn Request Response")
   
if not isinstance(response.root, SendMessageSuccessResponse):
       
print("received non-success response. Aborting get task ")
       
return

   
if not isinstance(response.root.result, Task):
       
print("received non-task response. Aborting get task ")
       
return

   
task_id: str = response.root.result.id
   
print("--- ❔ Query Task ---")
   
# query the task
   
get_request = GetTaskRequest(id=str(uuid4()), params=TaskQueryParams(id=task_id))
   
get_response: GetTaskResponse = await client.get_task(get_request)
   
print_json_response(get_response, "📥 Query Task Response")

# ----- Main Entrypoint (Create client --> Run tests) -----
async def main() -> None:
    """Main function to run the tests."""
   
print(f'--- 🔄 Connecting to agent at {AGENT_URL}... ---')
   
try:
       
async with httpx.AsyncClient() as httpx_client:
           
client = await A2AClient.get_client_from_agent_card_url(
               
httpx_client, AGENT_URL
           
)
           
print('--- ✅ Connection successful. ---')

           
await run_single_turn_test(client)
           
await run_streaming_test(client)
           
await run_multi_turn_test(client)

   
except Exception as e:
       
traceback.print_exc()
       
print(f'--- ❌ An error occurred: {e} ---')
       
print('Ensure the agent server is running.')

מריצים את הבדיקות באמצעות הפקודה הבאה:

uv run currency_agent/test_client.py

אם בדיקת ההפעלה תצליח, יקרו הדברים הבאים:

--- 🔄 Connecting to agent at http://localhost:10000... ---
--- Connection successful. ---
--- ✉️ Single Turn Request ---
--- 📥 Single Turn Request Response ---
{"id":"3bc92d7b-d857-4e93-9ff0-b2fb865f6e35","jsonrpc":"2.0","result":{"artifacts":[{"artifactId":"35e89e14-b977-4397-a23b-92c84bc32379","parts":[{"kind":"text","text":"Based on the current exchange rate, 1 USD is equivalent to 1.3704 CAD. Therefore, 100 USD would be 137.04 CAD.\n"}]}],"contextId":"2d66f277-152c-46ef-881d-7fe32866e9f5","history":[{"contextId":"2d66f277-152c-46ef-881d-7fe32866e9f5","kind":"message","messageId":"59819269f7d04849b0bfca7d43ec073c","parts":[{"kind":"text","text":"how much is 100 USD in CAD?"}],"role":"user","taskId":"52ae2392-84f5-429a-a14b-8413d3d20d97"},{"contextId":"2d66f277-152c-46ef-881d-7fe32866e9f5","kind":"message","messageId":"286095c6-12c9-40cb-9596-a9676d570dbd","parts":[],"role":"agent","taskId":"52ae2392-84f5-429a-a14b-8413d3d20d97"}],"id":"52ae2392-84f5-429a-a14b-8413d3d20d97","kind":"task","status":{"state":"completed"}}}

// ...

--- Single Turn Streaming Request ---
--- Streaming Chunk ---
{"id":"21239a5f-abbf-4a5e-a249-c101eb1dfbdd","jsonrpc":"2.0","result":{"contextId":"f268ad8c-b3bf-4439-9a64-5e02dfbb9a62","final":false,"kind":"status-update","status":{"state":"submitted"},"taskId":"761d2275-d58b-46f8-9c8d-68cd72e0667d"}}

--- Streaming Chunk ---
{"id":"21239a5f-abbf-4a5e-a249-c101eb1dfbdd","jsonrpc":"2.0","result":{"contextId":"f268ad8c-b3bf-4439-9a64-5e02dfbb9a62","final":false,"kind":"status-update","status":{"state":"working"},"taskId":"761d2275-d58b-46f8-9c8d-68cd72e0667d"}}

--- Streaming Chunk ---
{"id":"21239a5f-abbf-4a5e-a249-c101eb1dfbdd","jsonrpc":"2.0","result":{"contextId":"f268ad8c-b3bf-4439-9a64-5e02dfbb9a62","final":false,"kind":"status-update","status":{"message":{"contextId":"f268ad8c-b3bf-4439-9a64-5e02dfbb9a62","kind":"message","messageId":"25f5f972-9475-4e4a-a08d-e13f521d7462","parts":[],"role":"agent","taskId":"761d2275-d58b-46f8-9c8d-68cd72e0667d"},"state":"working"},"taskId":"761d2275-d58b-46f8-9c8d-68cd72e0667d"}}

--- Streaming Chunk ---
{"id":"21239a5f-abbf-4a5e-a249-c101eb1dfbdd","jsonrpc":"2.0","result":{"artifact":{"artifactId":"35e89e14-b977-4397-a23b-92c84bc32379","parts":[{"kind":"text","text":"The current exchange rate is 1 EUR to 164.15 JPY. So, 50 EUR would be 8207.5 JPY.\n"}]},"contextId":"f268ad8c-b3bf-4439-9a64-5e02dfbb9a62","kind":"artifact-update","taskId":"761d2275-d58b-46f8-9c8d-68cd72e0667d"}}

// ...

--- 🚀 First turn completed, no further input required for this test case. ---

זה עובד! הבדיקה שלך הצליחה ואתה יכול לתקשר עם סוכן המטבע באמצעות שרת A2A! 🎉

כדאי לעיין במאגר a2a-samples ב-GitHub כדי לראות תרחישי שימוש מתקדמים יותר.

רוצה לפרוס את הסוכן? ‫Vertex AI Agent Engine מספק חוויה מנוהלת לפריסת סוכני AI בסביבת ייצור.

9.‏ מזל טוב

מעולה! בניתם ופרסתם בהצלחה שרת MCP מרוחק, יצרתם סוכן מטבע באמצעות Agent Development Kit (ADK) שמתחבר לכלים באמצעות MCP, וחשפתם את הסוכן באמצעות פרוטוקול Agent2Agent (A2A). הנציג של המטבע זמין עכשיו לאינטראקציה עם נציגים אחרים בכל מסגרת באמצעות A2A.

כאן מופיע קישור לתיעוד המלא של הקוד.

מה נכלל

  • איך יוצרים שרת MCP מקומי
  • פריסת שרת ה-MCP ב-Cloud Run
  • איך יוצרים סוכן באמצעות ערכת פיתוח סוכנים שמשתמשת בכלים של MCP
  • איך חושפים סוכן ADK כשרת A2A
  • בדיקת שרת A2A באמצעות לקוח A2A

הסרת המשאבים

כדי לא לצבור חיובים לחשבון Google Cloud על המשאבים שבהם השתמשתם במעבדה הזו:

  1. במסוף Google Cloud, עוברים לדף Manage resources.
  2. ברשימת הפרויקטים, בוחרים את הפרויקט שרוצים למחוק ולוחצים על Delete.
  3. כדי למחוק את הפרויקט, כותבים את מזהה הפרויקט בתיבת הדו-שיח ולוחצים על Shut down.