Criando uma sala de imprensa para agentes LLM com protocolo A2A e MCP no Elasticsearch: Parte II
Descubra como construir uma redação especializada para agentes LLM em um ambiente híbrido, utilizando o protocolo A2A para colaboração entre agentes e o MCP para acesso a ferramentas no Elasticsearch.
A2A e MCP: o código em ação
Este artigo é um complemento ao artigo "Criando uma sala de imprensa com o agente LLM usando os protocolos A2A e MCP no Elasticsearch!", que explicou os benefícios de implementar as arquiteturas A2A e MCP no mesmo agente para aproveitar ao máximo as vantagens exclusivas de ambas as estruturas. Um repositório está disponível caso você queira executar a demonstração por conta própria.

Vamos analisar como nossos agentes de redação colaboram usando tanto o A2A quanto o MCP para produzir um artigo jornalístico. O repositório que acompanha o projeto, onde é possível ver os agentes em ação, pode ser encontrado aqui.
Etapa 1: Atribuição da história
O chefe de jornalismo (atuando como cliente) designa uma pauta:
{
"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"
}
}
}Etapa 2: O repórter solicita pesquisa.
O Agente Repórter reconhece que precisa de informações básicas e delega essa tarefa ao Agente Pesquisador por meio do método 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"
}
}
}Etapa 3: O repórter solicita contexto histórico ao Agente de Arquivo.
O agente repórter reconhece que o contexto histórico fortaleceria a matéria. Ele delega ao Agente de Arquivo (com tecnologia A2A do Elastic) via A2A a busca no arquivo de artigos da sala de notícias, que utiliza o 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
}
}
}Etapa 4: O Agente de Arquivamento usa o Agente A2A Elástico com MCP
O Agente de Arquivamento utiliza o Agente A2A da Elastic, que por sua vez usa o MCP para acessar as ferramentas do Elasticsearch. Isso demonstra a arquitetura híbrida onde o A2A permite a colaboração entre agentes enquanto o MCP fornece acesso às ferramentas:
# 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_responseO Agente de Arquivamento recebe dados históricos abrangentes do Agente A2A da Elastic e os retorna ao Reporter:
{
"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
}
}
}Esta etapa demonstra como o agente A2A da Elastic se integra ao fluxo de trabalho da redação. O Agente de Arquivo (um agente específico para redações) trabalha em conjunto com o Agente A2A da Elastic (um especialista terceirizado) para aproveitar os poderosos recursos de busca e análise do Elasticsearch. O agente da Elastic usa o MCP internamente para acessar as ferramentas do Elasticsearch, demonstrando a clara separação entre a coordenação do agente (A2A) e o acesso às ferramentas (MCP).
Etapa 5: O pesquisador utiliza servidores MCP
O Agente Pesquisador acessa vários servidores MCP para coletar informações:
# 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)Etapa 6: O pesquisador devolve os dados ao repórter.
O Agente de Pesquisa envia uma pesquisa completa de volta via 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
}
}
}Etapa 7: O repórter escreve o artigo
O Repórter Agente utiliza os dados da pesquisa e suas próprias capacidades de mestrado em Direito (LLM) para redigir o artigo. Durante a escrita, o Repórter utiliza os servidores MCP para estilo e modelos:
# 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_checkEtapa 8: baixa confiança desencadeia nova pesquisa
O agente repórter avalia sua versão preliminar e constata que uma das afirmações apresenta baixo nível de confiança. Envia outra solicitação ao Agente Pesquisador:
{
"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"
}
}O pesquisador verifica a alegação usando servidores de checagem de fatos do MCP e retorna informações atualizadas:
{
"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"]
}
]
}
}Etapa 9: O repórter revisa e envia ao editor.
O repórter incorpora os fatos verificados e envia a versão finalizada ao editor por meio do sistema 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
}
}
}Etapa 10: Revisão do editor usando as ferramentas MCP
O Agente de Edição utiliza vários servidores MCP para revisar o artigo:
# 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 feedbackO editor aprova o artigo e o encaminha:
{
"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]"
}
}Etapa 11: A editora publica via CI/CD
Por fim, o Agente de Impressão publica o artigo aprovado usando os servidores MCP para o pipeline CMS e 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"]
}A editora confirma a publicação 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
}
}
}Segue abaixo a sequência completa do fluxo de trabalho A2A no repositório anexo, utilizando os mesmos agentes descritos acima.
# | De | Para | Ação | Protocolo | Descrição |
|---|---|---|---|---|---|
1 | Usuário | Chefe de Notícias | Atribuir história | HTTP POST | O usuário envia o tema e o enfoque da matéria. |
2 | Chefe de Notícias | Interno | Criar história | - | Cria um registro de história com um ID exclusivo. |
3 | Chefe de Notícias | Repórter | Atribuição de Delegado | A2A | Envia a atribuição da matéria através do protocolo A2A |
4 | Repórter | Interno | Aceitar tarefa | - | Atribuição de estoques internamente |
5 | Repórter | Servidor MCP | Gerar esboço | MCP/HTTP | Cria o esboço do artigo e as perguntas de pesquisa. |
6a | Repórter | Pesquisador | Solicitar pesquisa | A2A | Envia perguntas (paralelo com 6b) |
6b | Repórter | Arquivista | Pesquisar no arquivo | A2A JSONRPC | Pesquisa artigos históricos (paralelo com 6a) |
7 | Pesquisador | Servidor MCP | Questões de pesquisa | MCP/HTTP | Utiliza a abordagem antropogênica via MCP para responder a perguntas. |
8 | Pesquisador | Repórter | Retornar à pesquisa | A2A | Devolve respostas de pesquisa |
9 | Arquivista | Elasticsearch | Índice de pesquisa | API REST do ES | Consultas ao índice news_archive |
10 | Arquivista | Repórter | Retornar ao arquivo | A2A JSONRPC | Retorna resultados de pesquisa históricos |
11 | Repórter | Servidor MCP | Gerar artigo | MCP/HTTP | Cria artigo com contexto de pesquisa/arquivo |
12 | Repórter | Interno | Rascunho da loja | - | Salva o rascunho internamente |
13 | Repórter | Chefe de Notícias | Enviar rascunho | A2A | Entrega a versão finalizada |
14 | Chefe de Notícias | Interno | Atualização da história | - | Armazena o rascunho e atualiza o status para "rascunho_enviado". |
15 | Chefe de Notícias | Editor | Revisão do rascunho | A2A | Encaminha automaticamente para o Editor para revisão. |
16 | Editor | Servidor MCP | Artigo de revisão | MCP/HTTP | Analisa conteúdo usando Anthropic via MCP. |
17 | Editor | Chefe de Notícias | Revisão de retorno | A2A | Envia comentários e sugestões editoriais. |
18 | Chefe de Notícias | Interno | Avaliação da loja | - | Feedback do editor de lojas |
19 | Chefe de Notícias | Repórter | Aplicar edições | A2A | Feedback da revisão de rotas para o repórter |
20 | Repórter | Servidor MCP | Aplicar edições | MCP/HTTP | Revisa o artigo com base no feedback. |
21 | Repórter | Interno | Rascunho atualizado | - | Atualiza a versão preliminar com revisões. |
22 | Repórter | Chefe de Notícias | Devolução revisada | A2A | Devolve artigo revisado |
23 | Chefe de Notícias | Interno | Atualização da história | - | Lojas revisaram a versão preliminar, status para "revisado" |
24 | Chefe de Notícias | Editor | Publicar artigo | A2A | Rotas automáticas para o editor |
25 | Editor | Servidor MCP | Gerar etiquetas | MCP/HTTP | Cria etiquetas e categorias |
26 | Editor | Elasticsearch | Artigo de índice | API REST do ES | Indexa o artigo ao índice news_archive |
27 | Editor | Sistema de arquivos | Salvar Markdown | Entrada/Saída de Arquivos | Salva o artigo como .md arquivo em /artigos |
28 | Editor | Chefe de Notícias | Confirmar publicação | A2A | Retorna o status de sucesso |
29 | Chefe de Notícias | Interno | Atualização da história | - | Atualiza o status da matéria para "publicada". |
Conclusão
Tanto o A2A quanto o MCP desempenham papéis importantes no paradigma moderno de infraestrutura de LLM aumentada. A tecnologia A2A oferece flexibilidade para sistemas multiagentes complexos, mas potencialmente menor portabilidade e maior complexidade operacional. O MCP oferece uma abordagem padronizada para integração de ferramentas que é mais simples de implementar e manter, embora não seja projetado para lidar com orquestração multiagente.
A escolha não é binária. Conforme demonstrado em nosso exemplo de redação, os sistemas mais sofisticados e eficazes baseados em LLM geralmente combinam ambas as abordagens: os agentes se coordenam e se especializam por meio de protocolos A2A, enquanto acessam suas ferramentas e recursos por meio de servidores MCP. Essa arquitetura híbrida proporciona os benefícios organizacionais dos sistemas multiagentes, juntamente com a padronização e as vantagens do ecossistema do MCP. Isso sugere que talvez não seja necessário escolher: basta usar ambos como abordagem padrão.
Cabe a você, como desenvolvedor ou arquiteto, testar e determinar a melhor combinação de ambas as soluções para obter o resultado adequado ao seu caso de uso específico. Compreender os pontos fortes, as limitações e as aplicações adequadas de cada abordagem permitirá que você construa sistemas de IA mais eficazes, fáceis de manter e escaláveis.
Seja para criar uma redação digital, uma plataforma de atendimento ao cliente, um assistente de pesquisa ou qualquer outro aplicativo baseado em LLM, considerar cuidadosamente suas necessidades de coordenação (A2A) e requisitos de acesso às ferramentas (MCP) o colocará no caminho do sucesso.
Recursos adicionais
Construtor de Agentes do Elasticsearch: https://www.elastic.co/docs/solutions/search/elastic-agent-builder
Especificação A2A: https://a2a-protocol.org/latest/specification/
Integração A2A e MCP: https://a2a-protocol.org/latest/topics/a2a-and-mcp/
Protocolo de Contexto do Modelo: https://modelcontextprotocol.io




