Création d'une salle de presse avec agent LLM, protocole A2A et MCP dans Elasticsearch : Partie II
Découvrez comment construire une salle de presse hybride spécialisée pour les agents LLM en utilisant le protocole A2A pour la collaboration entre agents et MCP pour l'accès aux outils dans Elasticsearch.
A2A et MCP : le code en action
Cet article est le complément de l'article "Creating an LLM Agent newsroom with A2A protocol and MCP in Elasticsearch !", qui expliquait les avantages de la mise en œuvre des architectures A2A et MCP au sein du même agent afin de profiter pleinement des avantages uniques des deux frameworks. Un référentiel est disponible si vous souhaitez exécuter la démo par vous-même.

Voyons comment les agents de notre salle de presse collaborent en utilisant à la fois A2A et MCP pour produire un article. Le référentiel d'accompagnement pour voir les agents en action est disponible ici.
Étape 1 : Attribution de l'histoire
Le chef de l'information (agissant en tant que client) attribue un sujet :
{
"message_type": "task_request",
"sender": "news_chief",
"receiver": "reporter_agent",
"payload": {
"task_id": "story_renewable_energy_2024",
"assignment": {
"topic": "Renewable Energy Adoption in Europe",
"angle": "Policy changes driving solar and wind expansion",
"target_length": 1200,
"deadline": "2025-09-30T18:00:00Z"
}
}
}Étape 2 : Le journaliste demande des recherches
L'agent rapporteur reconnaît qu'il a besoin d'informations générales et délègue à l'agent chercheur par l'intermédiaire de l'A2A :
{
"message_type": "task_request",
"sender": "reporter_agent",
"receiver": "researcher_agent",
"payload": {
"task_id": "research_eu_renewable_2024",
"parent_task_id": "story_renewable_energy_2024",
"capability": "fact_gathering",
"parameters": {
"queries": [
"EU renewable energy capacity 2024",
"Solar installations growth Europe",
"Wind energy policy changes 2024"
],
"depth": "comprehensive"
}
}
}Étape 3 : Le rapporteur demande le contexte historique à l'agent d'archivage
L'agent rapporteur reconnaît que le contexte historique renforcerait l'histoire. Il délègue à l'agent d'archivage (alimenté par l'agent A2A d'Elastic), via A2A, le soin d'effectuer des recherches dans les archives d'articles de la salle de presse alimentées par Elasticsearch :
{
"message_type": "task_request",
"sender": "reporter_agent",
"receiver": "archive_agent",
"payload": {
"task_id": "archive_search_renewable_2024",
"parent_task_id": "story_renewable_energy_2024",
"capability": "search_archive",
"parameters": {
"query": "European renewable energy policy changes and adoption trends over past 5 years",
"focus_areas": ["solar", "wind", "policy", "Germany", "France"],
"time_range": "2019-2024",
"result_count": 10
}
}
}Étape 4 : L'agent d'archivage utilise l'agent Elastic A2A avec MCP
L'agent d'archivage utilise l'agent A2A d'Elastic, qui à son tour utilise MCP pour accéder aux outils Elasticsearch. Ceci démontre l'architecture hybride où A2A permet la collaboration des agents tandis que MCP fournit l'accès aux outils :
# Archive Agent using Elastic A2A Agent
async def search_historical_articles(self, query_params):
# The Archive Agent sends a request to Elastic's A2A Agent
elastic_response = await self.a2a_client.send_request(
agent="elastic_agent",
capability="search_and_analyze",
parameters={
"natural_language_query": query_params["query"],
"index_pattern": "newsroom-articles-*",
"filters": {
"topics": query_params["focus_areas"],
"date_range": query_params["time_range"]
},
"analysis_type": "trend_analysis"
}
)
# Elastic's A2A Agent internally uses MCP tools:
# - platform.core.search (to find relevant articles)
# - platform.core.generate_esql (to analyze trends)
# - platform.core.index_explorer (to identify relevant indices)
return elastic_responseL'agent d'archivage reçoit des données historiques complètes de l'agent A2A d'Elastic et les renvoie au rapporteur :
{
"message_type": "task_response",
"sender": "archive_agent",
"receiver": "reporter_agent",
"payload": {
"task_id": "archive_search_renewable_2024",
"status": "completed",
"archive_data": {
"historical_articles": [
{
"title": "Germany's Energiewende: Five Years of Solar Growth",
"published": "2022-06-15",
"key_points": [
"Germany added 7 GW annually 2020-2022",
"Policy subsidies drove 60% of growth"
],
"relevance_score": 0.94
},
{
"title": "France Balances Nuclear and Renewables",
"published": "2023-03-20",
"key_points": [
"France increased renewable target to 40% by 2030",
"Solar capacity doubled 2021-2023"
],
"relevance_score": 0.89
}
],
"trend_analysis": {
"coverage_frequency": "EU renewable stories increased 150% since 2019",
"emerging_themes": ["policy incentives", "grid modernization", "battery storage"],
"coverage_gaps": ["Small member states", "offshore wind permitting"]
},
"total_articles_found": 47,
"search_confidence": 0.91
}
}
}Cette étape montre comment l'agent A2A d'Elastic s'intègre dans le flux de travail de la salle de presse. L'Archive Agent (un agent spécifique à la salle de presse) se coordonne avec l'A2A Agent d'Elastic (un spécialiste tiers) pour exploiter les puissantes capacités de recherche et d'analyse d'Elasticsearch. L'agent Elastic utilise MCP en interne pour accéder aux outils Elasticsearch, ce qui montre la séparation nette entre la coordination de l'agent (A2A) et l'accès aux outils (MCP).
Étape 5 : Le chercheur utilise les serveurs MCP
L'agent chercheur accède à plusieurs serveurs MCP pour recueillir des informations :
# Researcher Agent using MCP to access tools
async def gather_facts(self, queries):
results = []
# Use News API MCP Server
news_data = await self.mcp_client.invoke_tool(
server="news_api_mcp",
tool="search_articles",
parameters={
"query": queries[0],
"date_range": "2024-01-01 to 2024-09-30",
"sources": ["reuters", "bloomberg", "euractiv"]
}
)
# Use Statistics MCP Server
stats_data = await self.mcp_client.invoke_tool(
server="eurostat_mcp",
tool="get_energy_statistics",
parameters={
"metrics": ["solar_capacity_mw", "wind_capacity_mw"],
"countries": ["EU27"],
"year": 2024
}
)
# Use Fact-Checking MCP Server
verified_facts = await self.mcp_client.invoke_tool(
server="factcheck_mcp",
tool="verify_claims",
parameters={
"claims": [
"EU solar capacity increased 40% in 2024",
"Germany leads in wind installations"
]
}
)
return self._synthesize_research(news_data, stats_data, verified_facts)Étape 6 : Le chercheur renvoie les données au rapporteur
L'agent chargé de la recherche renvoie la recherche complète par l'intermédiaire de l'A2A :
{
"message_type": "task_response",
"sender": "researcher_agent",
"receiver": "reporter_agent",
"payload": {
"task_id": "research_eu_renewable_2024",
"status": "completed",
"research_data": {
"key_facts": [
{
"claim": "EU solar capacity reached 260 GW in 2024",
"source": "Eurostat Q3 2024 Report",
"confidence": 0.95,
"verified": true
},
{
"claim": "Germany installed 12 GW of wind capacity in 2024",
"source": "German Federal Network Agency",
"confidence": 0.92,
"verified": true
}
],
"statistics": {
"solar_growth_rate": "35%",
"wind_growth_rate": "28%"
},
"sources_count": 15
}
}
}Étape 7 : Le journaliste rédige un article
L'agent rapporteur utilise les données de recherche et ses propres capacités LLM pour rédiger l'article. Pendant la rédaction, le Reporter utilise les serveurs MCP pour le style et les modèles :
# Reporter Agent writing with MCP assistance
async def write_article(self, research_data, assignment):
# Get style guidelines via MCP
style_guide = await self.mcp_client.get_resource(
server="newsroom_mcp",
resource="style://editorial/ap_style_guide"
)
# Get article template via MCP
template = await self.mcp_client.get_resource(
server="newsroom_mcp",
resource="template://articles/news_story"
)
# Generate article using LLM + research + style
draft = await self.llm.generate(
prompt=f"""
Write a news article following these guidelines:
{style_guide}
Using this template:
{template}
Based on this research:
{research_data}
Assignment: {assignment}
"""
)
# Self-evaluate confidence in claims
confidence_check = await self._evaluate_confidence(draft)
return draft, confidence_checkÉtape 8 : le manque de confiance déclenche une nouvelle recherche
L'agent déclarant évalue son projet et constate qu'une créance a un faible degré de confiance. Il envoie une autre demande à l'agent du chercheur :
{
"message_type": "collaboration_request",
"sender": "reporter_agent",
"receiver": "researcher_agent",
"payload": {
"request_type": "fact_verification",
"claims": [
{
"text": "France's nuclear phase-down contributed to 15% increase in renewable capacity",
"context": "Discussing policy drivers for renewable growth",
"current_confidence": 0.45,
"required_confidence": 0.80
}
],
"urgency": "high"
}
}Le chercheur vérifie l'allégation à l'aide des serveurs MCP de vérification des faits et renvoie les informations mises à jour :
{
"message_type": "collaboration_response",
"sender": "researcher_agent",
"receiver": "reporter_agent",
"payload": {
"verified_claims": [
{
"original_claim": "France's nuclear phase-down contributed to 15% increase...",
"verified_claim": "France's renewable capacity increased 18% in 2024, partially offsetting reduced nuclear output",
"confidence": 0.88,
"corrections": "Percentage was 18%, not 15%; nuclear phase-down is gradual, not primary driver",
"sources": ["RTE France", "French Energy Ministry Report 2024"]
}
]
}
}Étape 9 : Le journaliste révise le texte et le soumet au rédacteur en chef
Le rapporteur incorpore les faits vérifiés et envoie le projet complet à l'agent rédacteur par l'intermédiaire de l'A2A :
{
"message_type": "task_request",
"sender": "reporter_agent",
"receiver": "editor_agent",
"payload": {
"task_id": "edit_renewable_story",
"parent_task_id": "story_renewable_energy_2024",
"content": {
"headline": "Europe's Renewable Revolution: Solar and Wind Surge 30% in 2024",
"body": "[Full article text...]",
"word_count": 1185,
"sources": [/* array of sources */]
},
"editing_requirements": {
"check_style": true,
"check_facts": true,
"check_seo": true
}
}
}Étape 10 : Examens des éditeurs à l'aide des outils MCP
L'agent rédacteur utilise plusieurs serveurs MCP pour réviser l'article :
# Editor Agent using MCP for quality checks
async def review_article(self, content):
# Grammar and style check
grammar_issues = await self.mcp_client.invoke_tool(
server="grammarly_mcp",
tool="check_document",
parameters={"text": content["body"]}
)
# SEO optimization check
seo_analysis = await self.mcp_client.invoke_tool(
server="seo_mcp",
tool="analyze_content",
parameters={
"headline": content["headline"],
"body": content["body"],
"target_keywords": ["renewable energy", "Europe", "solar", "wind"]
}
)
# Plagiarism check
originality = await self.mcp_client.invoke_tool(
server="plagiarism_mcp",
tool="check_originality",
parameters={"text": content["body"]}
)
# Generate editorial feedback
feedback = await self._generate_feedback(
grammar_issues,
seo_analysis,
originality
)
return feedbackLe rédacteur en chef approuve l'article et le transmet :
{
"message_type": "task_response",
"sender": "editor_agent",
"receiver": "reporter_agent",
"payload": {
"status": "approved",
"quality_score": 9.2,
"minor_edits": [
"Changed 'surge' to 'increased' in paragraph 3 for AP style consistency",
"Added Oxford comma in list of countries"
],
"approved_content": "[Final edited article]"
}
}Étape 11 : L'éditeur publie via CI/CD
Enfin, l'agent imprimeur publie l'article approuvé en utilisant les serveurs MCP pour le CMS et le pipeline CI/CD :
# Publisher Agent publishing via MCP
async def publish_article(self, content, metadata):
# Upload to CMS via MCP
cms_result = await self.mcp_client.invoke_tool(
server="wordpress_mcp",
tool="create_post",
parameters={
"title": content["headline"],
"body": content["body"],
"status": "draft",
"categories": metadata["categories"],
"tags": metadata["tags"],
"featured_image_url": metadata["image_url"]
}
)
post_id = cms_result["post_id"]
# Trigger CI/CD deployment via MCP
deploy_result = await self.mcp_client.invoke_tool(
server="cicd_mcp",
tool="trigger_deployment",
parameters={
"pipeline": "publish_article",
"environment": "production",
"post_id": post_id,
"schedule": "immediate"
}
)
# Track analytics
await self.mcp_client.invoke_tool(
server="analytics_mcp",
tool="register_publication",
parameters={
"post_id": post_id,
"publish_time": datetime.now().isoformat(),
"story_id": metadata["story_id"]
}
)
return {
"status": "published",
"post_id": post_id,
"url": f"https://newsroom.example.com/articles/{post_id}",
"deployment_id": deploy_result["deployment_id"]
}L'éditeur confirme la publication via A2A :
{
"message_type": "task_complete",
"sender": "printer_agent",
"receiver": "news_chief",
"payload": {
"task_id": "story_renewable_energy_2024",
"status": "published",
"publication": {
"url": "https://newsroom.example.com/articles/renewable-europe-2024",
"published_at": "2025-09-30T17:45:00Z",
"post_id": "12345"
},
"workflow_metrics": {
"total_time_minutes": 45,
"agents_involved": ["reporter", "researcher", "archive", "editor", "printer"],
"iterations": 2,
"mcp_calls": 12
}
}
}Voici la séquence complète du flux de travail A2A dans le référentiel d'accompagnement en utilisant les mêmes agents que ceux décrits ci-dessus.
# | De | Pour | Action | Protocole | Description |
|---|---|---|---|---|---|
1 | Utilisateur | Chef de l'information | Attribuer l'histoire | HTTP POST | L'utilisateur soumet le sujet et l'angle de l'article |
2 | Chef de l'information | Interne | Créer une histoire | - | Création d'un enregistrement d'histoire avec un identifiant unique |
3 | Chef de l'information | Reporter | Affectation des délégués | A2A | Envoi de l'article via le protocole A2A |
4 | Reporter | Interne | Accepter l'affectation | - | Stockage interne de l'affectation |
5 | Reporter | Serveur MCP | Générer un plan | MCP/HTTP | Création d'un plan d'article et de questions de recherche |
6a | Reporter | Chercheur | Demande de recherche | A2A | Envoie des questions (parallèle avec 6b) |
6b | Reporter | Archiviste | Recherche dans les archives | A2A JSONRPC | Recherche d'articles historiques (parallèle avec 6a) |
7 | Chercheur | Serveur MCP | Questions de recherche | MCP/HTTP | Utilise l'Anthropique via le MCP pour répondre aux questions |
8 | Chercheur | Reporter | Recherche en matière de retour | A2A | Réponses à la recherche sur les retours |
9 | Archiviste | Elasticsearch | Index de recherche | API REST ES | Requêtes news_archive index |
10 | Archiviste | Reporter | Retour à l'archive | A2A JSONRPC | Renvoie les résultats de la recherche historique |
11 | Reporter | Serveur MCP | Générer un article | MCP/HTTP | Création d'un article dans un contexte de recherche ou d'archives |
12 | Reporter | Interne | Projet de magasin | - | Sauvegarde interne du projet |
13 | Reporter | Chef de l'information | Soumettre le projet | A2A | Soumission d'un projet achevé |
14 | Chef de l'information | Interne | Mise à jour de l'histoire | - | Stocke le projet, met à jour le statut à "draft_submitted" |
15 | Chef de l'information | Éditeur | Projet de révision | A2A | Routes automatiques vers l'éditeur pour révision |
16 | Éditeur | Serveur MCP | Article de synthèse | MCP/HTTP | Analyse du contenu à l'aide d'Anthropic via MCP |
17 | Éditeur | Chef de l'information | Retourner à l'examen | A2A | Envoi d'un retour d'information et de suggestions éditoriales |
18 | Chef de l'information | Interne | Revue des magasins | - | Stocke les commentaires des éditeurs |
19 | Chef de l'information | Reporter | Appliquer les modifications | A2A | Acheminement du retour d'information sur l'examen au rapporteur |
20 | Reporter | Serveur MCP | Appliquer les modifications | MCP/HTTP | Révision de l'article en fonction du retour d'information |
21 | Reporter | Interne | Projet de mise à jour | - | Mise à jour du projet avec des révisions |
22 | Reporter | Chef de l'information | Retour Révisé | A2A | Retourne l'article révisé |
23 | Chef de l'information | Interne | Mise à jour de l'histoire | - | Stocker le projet révisé, statut à "révisé" |
24 | Chef de l'information | Éditeur | Publier un article | A2A | Routes automatiques vers l'éditeur |
25 | Éditeur | Serveur MCP | Générer des étiquettes | MCP/HTTP | Création d'étiquettes et de catégories |
26 | Éditeur | Elasticsearch | Index Article | API REST ES | Indexe l'article dans l'index news_archive |
27 | Éditeur | Système de fichiers | Sauvegarder la démarque | Fichier E/S | Enregistre l'article au format .md fichier dans /articles |
28 | Éditeur | Chef de l'information | Confirmer la publication | A2A | Renvoie l'état de réussite |
29 | Chef de l'information | Interne | Mise à jour de l'histoire | - | Mise à jour du statut de l'article à "publié" |
Conclusion
L'A2A et le MCP ont tous deux un rôle important à jouer dans le paradigme moderne de l'infrastructure augmentée-LLM. L'A2A offre une certaine souplesse pour les systèmes multi-agents complexes, mais potentiellement moins de portabilité et une plus grande complexité opérationnelle. MCP offre une approche standardisée pour l'intégration des outils, plus simple à mettre en œuvre et à maintenir, bien qu'il ne soit pas conçu pour gérer l'orchestration multi-agents.
Le choix n'est pas binaire. Comme le montre notre exemple de salle de presse, les systèmes les plus sophistiqués et les plus efficaces soutenus par le LLM combinent souvent les deux approches : les agents se coordonnent et se spécialisent par le biais de protocoles A2A tout en accédant à leurs outils et à leurs ressources par le biais de serveurs MCP. Cette architecture hybride offre les avantages organisationnels des systèmes multi-agents ainsi que les avantages de la normalisation et de l'écosystème du MCP. Cela suggère qu'il n'est peut-être pas nécessaire de faire un choix : il suffit d'utiliser les deux en tant qu'approche standard.
C'est à vous, en tant que développeur ou architecte, de tester et de déterminer le meilleur mélange de ces deux solutions pour obtenir le bon résultat pour votre cas d'utilisation spécifique. Comprendre les points forts, les limites et les applications appropriées de chaque approche vous permettra de construire des systèmes d'IA plus efficaces, plus faciles à maintenir et plus évolutifs.
Que vous construisiez une salle de presse numérique, une plateforme de service à la clientèle, un assistant de recherche ou toute autre application alimentée par le LLM, l'examen attentif de vos besoins de coordination (A2A) et des exigences d'accès aux outils (MCP) vous mettra sur la voie de la réussite.
Ressources supplémentaires
Elasticsearch Agent Builder : https://www.elastic.co/docs/solutions/search/elastic-agent-builder
Spécification A2A : https://a2a-protocol.org/latest/specification/
Intégration A2A et MCP : https://a2a-protocol.org/latest/topics/a2a-and-mcp/
Modèle de protocole de contexte : https://modelcontextprotocol.io




