Premiers pas avec MCP, ADK et A2A

Premiers pas avec MCP, ADK et A2A

À propos de cet atelier de programmation

subjectDernière mise à jour : juin 25, 2025
account_circleRédigé par Jack Wotherspoon

1. Présentation

Les agents d'IA gagnent rapidement en popularité. Ils révolutionnent l'automatisation des tâches et la prise de décision grâce à leur capacité à fonctionner de manière autonome, à apprendre et à interagir avec leur environnement pour atteindre des objectifs.

Mais comment créer un agent ? Cet atelier de programmation vous aidera à vous lancer en vous montrant comment créer un agent de change capable de convertir les devises de différents pays. L'objectif est de vous présenter les dernières technologies pour vous aider à comprendre les acronymes que vous avez peut-être vus sur Internet (MCP, ADK, A2A).

Architecture

Protocole de contexte de modèle (MCP)

Le protocole MCP (Model Context Protocol) est un protocole ouvert qui normalise la façon dont les applications fournissent du contexte aux LLM. Le protocole MCP fournit une méthode standardisée pour connecter les modèles d'IA aux ressources, aux requêtes et aux outils.

Agent Development Kit (ADK)

Agent Development Kit (ADK) est un framework d'orchestration flexible permettant de développer et de déployer des agents d'IA. L'ADK est indépendant du modèle et du déploiement, et est conçu pour être compatible avec d'autres frameworks. L'ADK a été conçu pour que le développement d'agents ressemble davantage au développement de logiciels. Il permet aux développeurs de créer, de déployer et d'orchestrer plus facilement des architectures d'agents allant de tâches simples à des workflows complexes.

Protocole Agent2Agent (A2A)

Le protocole Agent2Agent (A2A) est une norme ouverte conçue pour permettre une communication et une collaboration fluides entre les agents d'IA. Tout comme le protocole MCP fournit un moyen standardisé d'accorder aux LLM l'accès aux données et aux outils, l'A2A fournit un moyen standardisé permettant aux agents de communiquer entre eux. Dans un monde où les agents sont conçus à l'aide de frameworks divers et par différents fournisseurs, A2A fournit un langage commun, éliminant les silos et favorisant l'interopérabilité.

Points abordés

  • Créer un serveur MCP local
  • Déployer le serveur MCP sur Cloud Run
  • Créer un agent avec le kit de développement d'agents qui utilise les outils MCP
  • Exposer un agent ADK en tant que serveur A2A
  • Tester le serveur A2A à l'aide du client A2A

Prérequis

  • Un navigateur tel que Chrome ou Firefox
  • Un projet Google Cloud avec facturation activée.

2. Avant de commencer

Créer un projet

  1. Dans la console Google Cloud, sur la page de sélection du projet, sélectionnez ou créez un projet Google Cloud.
  2. Assurez-vous que la facturation est activée pour votre projet Cloud. Découvrez comment vérifier si la facturation est activée sur un projet.
  3. Activez Cloud Shell en cliquant sur ce lien. Vous pouvez basculer entre le terminal Cloud Shell (pour exécuter des commandes cloud) et l'éditeur (pour créer des projets) en cliquant sur le bouton correspondant dans Cloud Shell.
  4. Une fois connecté à Cloud Shell, vérifiez que vous êtes déjà authentifié et que le projet est défini sur votre ID de projet à l'aide de la commande suivante :
gcloud auth list
  1. Exécutez la commande suivante dans Cloud Shell pour vérifier que la commande gcloud connaît votre projet.
gcloud config list project
  1. Utilisez la commande suivante pour définir votre projet :
export PROJECT_ID=<YOUR_PROJECT_ID>
gcloud config set project $PROJECT_ID
  1. Activez les API requises à l'aide de la commande suivante. L'opération peut prendre quelques minutes.
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. Assurez-vous d'avoir Python 3.10 ou version ultérieure.

Consultez la documentation pour connaître les commandes gcloud et leur utilisation.

3. Installation

  1. Clonez le dépôt :
git clone https://github.com/jackwotherspoon/currency-agent.git
cd currency-agent
  1. Installez uv (utilisé pour gérer les dépendances) :
# 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. Configurer les variables d'environnement (via le fichier .env) :

Créez un fichier .env en exécutant la commande suivante :

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

4. Créer un serveur MCP local

Avant d'orchestrer votre agent de devises, vous devez d'abord créer un serveur MCP pour exposer les outils dont votre agent aura besoin.

Un serveur MCP vous permet d'écrire des programmes légers pour exposer des fonctionnalités spécifiques (comme la récupération des taux de change) en tant qu'outils. Un ou plusieurs agents peuvent ensuite accéder à ces outils à l'aide du Model Context Protocol (MCP) standardisé.

Le package Python FastMCP peut être utilisé pour créer un serveur MCP qui expose un seul outil appelé get_exchange_rate. L'outil get_exchange_rate effectue un appel sur Internet à l'API Frankfurter pour obtenir le taux de change actuel entre deux devises.

Le code du serveur MCP se trouve dans le fichier 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),
       
)
   
)

Pour démarrer le serveur MCP en local, ouvrez un terminal et exécutez la commande suivante (le serveur démarrera sur http://localhost:8080) :

uv run mcp-server/server.py

Testez le bon fonctionnement du serveur MCP et l'accessibilité de l'outil get_exchange_rate à l'aide du protocole Model Context Protocol.

Dans une nouvelle fenêtre de terminal (pour ne pas arrêter le serveur MCP local), exécutez la commande suivante :

uv run mcp-server/test_server.py

Le taux de change actuel de 1 USD (dollar américain) en EUR (euro) devrait s'afficher :

--- 🛠️ 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
 
}
} ---

Formidable ! Vous disposez désormais d'un serveur MCP fonctionnel avec un outil auquel votre agent pourra accéder.

Avant de passer à la station suivante, arrêtez le serveur MCP exécuté localement en exécutant Ctrl+C (ou Command+C sur Mac) dans le terminal où vous l'avez démarré.

5. Déployer votre serveur MCP sur Cloud Run

Vous êtes maintenant prêt à déployer le serveur MCP en tant que serveur MCP distant sur Cloud Run 🚀☁️

Avantages de l'exécution d'un serveur MCP à distance

L'exécution d'un serveur MCP à distance sur Cloud Run peut présenter plusieurs avantages :

  • 📈 Scalabilité : Cloud Run est conçu pour effectuer rapidement un scaling horizontal afin de gérer toutes les requêtes entrantes. Cloud Run fera évoluer automatiquement votre serveur MCP en fonction de la demande.
  • 👥 Serveur centralisé : vous pouvez partager l'accès à un serveur MCP centralisé avec les membres de votre équipe grâce aux droits IAM. Ils pourront ainsi s'y connecter depuis leur machine locale au lieu d'exécuter chacun leur propre serveur localement. Si une modification est apportée au serveur MCP, tous les membres de l'équipe en bénéficieront.
  • 🔐 Sécurité : Cloud Run permet d'appliquer facilement les requêtes authentifiées. Cela permet d'autoriser uniquement les connexions sécurisées à votre serveur MCP, ce qui empêche tout accès non autorisé.

Accédez donc à ce répertoire mcp-server :

cd mcp-server

Déployez le serveur MCP sur Cloud Run :

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

Si votre service a bien été déployé, un message semblable à celui-ci s'affiche :

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

Authentifier les clients MCP

Étant donné que vous avez spécifié --no-allow-unauthenticated pour exiger l'authentification, tout client MCP se connectant au serveur MCP distant devra s'authentifier.

La documentation officielle Héberger des serveurs MCP sur Cloud Run fournit plus d'informations à ce sujet, en fonction de l'endroit où vous exécutez votre client MCP.

Vous devrez exécuter le proxy Cloud Run pour créer un tunnel authentifié vers le serveur MCP distant sur votre machine locale.

Par défaut, l'URL des services Cloud Run exige que toutes les requêtes soient autorisées avec le rôle IAM Demandeur Cloud Run (roles/run.invoker). Cette liaison de stratégie IAM garantit qu'un mécanisme de sécurité renforcé est utilisé pour authentifier votre client MCP local.

Assurez-vous que vous ou les membres de votre équipe qui tentent d'accéder au serveur MCP distant disposez du rôle IAM roles/run.invoker lié à votre compte principal IAM (compte Google Cloud).

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

Vous devriez obtenir le résultat suivant :

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

Tout le trafic vers http://127.0.0.1:8080 sera désormais authentifié et transféré vers le serveur MCP distant.

Tester le serveur MCP distant

Dans un nouveau terminal, revenez au dossier racine et réexécutez le fichier mcp-server/test_server.py pour vous assurer que le serveur MCP distant fonctionne.

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

Vous devriez obtenir un résultat semblable à celui obtenu lors de l'exécution du serveur en local :

--- 🛠️ 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
 
}
} ---

Vous pouvez interroger les journaux du serveur MCP Cloud Run déployé si vous souhaitez vérifier que le serveur distant a bien été appelé :

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

Vous devriez obtenir le résultat suivant dans les journaux :

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}}

Maintenant que vous disposez d'un serveur MCP à distance, vous pouvez passer à la création d'un agent. 🤖

6. Créer un agent avec Agent Development Kit (ADK)

Vous avez déployé un serveur MCP. Il est maintenant temps de créer l'agent de devise à l'aide de l'Agent Development Kit (ADK).

Le kit de développement d'agents a récemment publié sa version stable 1.0.0. Cette étape marque la disponibilité de l'ADK Python en production. Les développeurs disposent désormais d'une plate-forme fiable et robuste pour créer et déployer leurs agents dans des environnements réels.

L'ADK permet de créer des agents extrêmement légers et de les connecter facilement aux serveurs MCP grâce à la prise en charge intégrée des outils MCP. L'agent de devise accédera à l'outil get_exchange_rate à l'aide de la classe MCPToolset de l'ADK.

Le code de l'agent de devise se trouve dans 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()

Pour tester rapidement l'agent de devises, vous pouvez utiliser l'UI de développement de l'ADK, accessible en exécutant adk web :

uv run adk web

Dans un navigateur, accédez à http://localhost:8000 pour voir et tester l'agent.

Assurez-vous que currency_agent est sélectionné comme agent en haut à gauche de l'interface utilisateur Web.

UI Web de l&#39;ADK

Dans la zone de chat, posez une question à l'agent, par exemple "Combien font 250 CAD en USD ?". Vous devriez voir l'agent appeler notre outil MCP get_exchange_rate avant de donner une réponse.

Agent de devise Web ADK

L'agent fonctionne ! Il peut répondre aux questions concernant les conversions de devises 💸.

7. Protocole Agent2Agent (A2A)

Le protocole Agent2Agent (A2A) est une norme ouverte conçue pour permettre une communication et une collaboration fluides entre les agents d'IA. Cela permet aux agents créés à l'aide de différents frameworks et par différents fournisseurs de communiquer entre eux dans une langue commune, ce qui élimine les silos et favorise l'interopérabilité.

Protocole A2A

A2A permet aux agents :

  • Découverte : trouvez d'autres agents et découvrez leurs compétences (AgentSkill) et leurs capacités (AgentCapabilities) à l'aide de fiches d'agent standardisées.
  • Communiquer : échanger des messages et des données de manière sécurisée.
  • Collaborer : déléguer des tâches et coordonner des actions pour atteindre des objectifs complexes.

Le protocole A2A facilite cette communication grâce à des mécanismes tels que les "cartes d'agent", qui servent de cartes de visite numériques que les agents peuvent utiliser pour présenter leurs capacités et leurs informations de connexion.

Carte d&#39;agent A2A

Il est maintenant temps d'exposer l'agent de devise à l'aide d'A2A afin qu'il puisse être appelé par d'autres agents et clients.

SDK Python A2A

Le SDK Python A2A fournit des modèles Pydantic pour chacune des ressources mentionnées ci-dessus : AgentSkill, AgentCapabilities et AgentCard. Cela fournit une interface permettant d'accélérer le développement et l'intégration au protocole A2A.

Un AgentSkill vous permet d'indiquer aux autres agents que l'agent de change dispose d'un outil pour 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?'],
)

Ensuite, dans le AgentCard, il listera les compétences et les capacités de l'agent, ainsi que d'autres détails tels que les modes d'entrée et de sortie que l'agent peut gérer :

# 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],
)

L'interface AgentExecutor gère la logique de base de la façon dont un agent A2A traite les requêtes et génère des réponses/événements. Le SDK Python A2A fournit une classe de base abstraite a2a.server.agent_execution.AgentExecutor que vous devez implémenter.

Il est temps de tout rassembler avec l'agent de change et de montrer la puissance d'A2A !

8. Serveur A2A de l&#39;agent de change

Vous allez maintenant examiner certains éléments de code et voir comment les différents éléments qui composent un serveur A2A s'assemblent.

En examinant le fichier currency_agent/agent_executor.py, vous trouverez la classe ADKAgentExecutor qui hérite de la classe abstraite A2A AgentExecutor. Il gère l'appel de l'agent ADK en appelant le runner ADK, en traitant les requêtes adressées à l'agent et en effectuant des conversions entre google.genai.types (utilisé par ADK) et a2a.types (utilisé par 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

C'est dans currency_agent/__main__.py que vous initialisez AgentSkill et AgentCard, et que vous créez l'agent de devise ADK. C'est également là que vous configurez et démarrez le serveur A2A.

Le SDK Python A2A fournit une classe A2AFastAPIApplication qui simplifie l'exécution d'un serveur HTTP conforme à A2A. Il utilise FastAPI pour le framework Web et est généralement exécuté avec un serveur ASGI tel que 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

Pour exécuter le serveur A2A, exécutez la commande suivante dans un nouveau terminal :

uv run currency_agent/

Si le serveur démarre correctement, le résultat suivant s'affiche, indiquant qu'il s'exécute sur le port 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)

L'agent de change s'exécute désormais en tant que serveur A2A et peut être appelé par d'autres agents ou clients à l'aide du protocole A2A.

Tester le serveur A2A

Vous pouvez maintenant tester le serveur en lui envoyant des requêtes à l'aide d'A2A.

Le SDK Python A2A fournit une classe a2a.client.A2AClient qui simplifie cette tâche.

Le fichier currency_agent/test_client.py contient du code qui exécute plusieurs cas de test différents sur le serveur 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.')

Exécutez les tests à l'aide de la commande suivante :

uv run currency_agent/test_client.py

Si le test s'exécute correctement, vous obtiendrez les résultats suivants :

--- 🔄 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. ---

Ça fonctionne ! Vous avez correctement testé votre capacité à communiquer avec l'agent de change via un serveur A2A. 🎉

Consultez le dépôt a2a-samples sur GitHub pour découvrir des cas d'utilisation plus avancés.

Vous souhaitez déployer votre agent ? Vertex AI Agent Engine offre une expérience gérée pour déployer des agents IA en production.

9. Félicitations

Félicitations ! Vous avez réussi à créer et à déployer un serveur MCP à distance, à créer un agent de devise à l'aide du kit de développement d'agents (ADK) qui se connecte aux outils à l'aide de MCP, et à exposer votre agent à l'aide du protocole Agent2Agent (A2A). L'agent de devises peut désormais interagir avec d'autres agents de n'importe quel framework à l'aide du protocole A2A.

Cliquez ici pour accéder à la documentation complète du code.

Points abordés

  • Créer un serveur MCP local
  • Déployer le serveur MCP sur Cloud Run
  • Créer un agent avec le kit de développement d'agents qui utilise les outils MCP
  • Exposer un agent ADK en tant que serveur A2A
  • Tester le serveur A2A à l'aide du client A2A

Effectuer un nettoyage

Pour éviter que les ressources utilisées dans cet atelier soient facturées sur votre compte Google Cloud, procédez comme suit :

  1. Dans la console Google Cloud, accédez à la page Gérer les ressources.
  2. Dans la liste des projets, sélectionnez le projet que vous souhaitez supprimer, puis cliquez sur Supprimer.
  3. Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez sur Arrêter pour supprimer le projet.