Blog

Creación de una redacción de agentes LLM con protocolo A2A y MCP en Elasticsearch: Parte II

Descubre cómo construir una sala de redacción híbrida especializada para agentes LLM empleando el protocolo A2A para la colaboración de agentes y MCP para el acceso a herramientas en Elasticsearch.

A2A y MCP: el código en acción

Este es el artículo complementario al artículo "¡Creando una redacción para agentes LLM con protocolo A2A y MCP en Elasticsearch!", que explicaba los beneficios de implementar tanto las arquitecturas A2A como MCP dentro del mismo agente para aprovechar realmente los beneficios únicos de ambos frameworks. Hay un repositorio disponible si deseas ejecutar la demo por tu cuenta.

Flujo de trabajo de agentes de protocolos A2A y MCP

Vamos a repasar cómo colaboran nuestros agentes de redacción empleando tanto A2A como MCP para producir un artículo de noticias. El repositorio adjunto para ver a los agentes en acción se puede encontrar aquí.

Paso 1: Asignación de la historia

El Jefe de Noticias (actuando como cliente) asigna una noticia:

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

Paso 2: El reportero aplicar investigación

El Agente Reportero reconoce que necesita información de fondo y delega al Agente Investigador mediante 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"
    }
  }
}

Paso 3: El reportero aplicar contexto histórico al Agente de Archivo

El Reporter Agent reconoce que el contexto histórico fortalecería la historia. Delega al Agente de Archivo (impulsado por el Agente A2A de Elastic) a través de A2A para buscar en el archivo de artículos impulsado por Elasticsearch de la redacción:

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

Paso 4: El Agente de Archivo emplea el Agente Elastic A2A con MCP

El Archive Agent emplea el A2A Agent de Elastic, que a su vez emplea MCP para acceder a las herramientas de Elasticsearch. Esto demuestra la arquitectura híbrida donde A2A permite la colaboración entre agentes mientras que MCP proporciona acceso a herramientas:

# 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_response

El Agente de Archivo recibe datos históricos completos del Agente A2A de Elastic y los devuelve al Reportero:

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

Este paso demuestra cómo el Agente A2A de Elastic se integra en el flujo de trabajo de la redacción. El Agente de Archivo (un agente específico de redacción) coordina con el Agente A2A de Elastic (un especialista externo) para aprovechar las poderosas capacidades de búsqueda y análisis de Elasticsearch. El agente de Elastic emplea MCP internamente para acceder a las herramientas de Elasticsearch, mostrando la separación limpia entre la coordinación del agente (A2A) y el acceso a la herramienta (MCP).

Paso 5: El investigador emplea servidores MCP

El Agente Investigador accede a múltiples servidores MCP para recopilar información:

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

Paso 6: El investigador devuelve los datos al Reportero

El Agente Investigador envía una investigación exhaustiva de vuelta a través de 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
    }
  }
}

Paso 7: Reportero escribe artículo

El Reporter Agent emplea los datos de investigación y sus propias capacidades de LLM para redactar el artículo. Durante la redacción, el Reportero emplea los servidores MCP para el estilo y las plantillas:

# 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

Paso 8: la baja confianza desencadena la re-investigación

El Agente Reportero evalúa su borrador y encuentra que una afirmación tiene baja confianza. Envía otra solicitud al Agente Investigador:

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

El investigador verifica la afirmación empleando servidores MCP de verificación de hechos y devuelve información actualizada:

{
  "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"]
      }
    ]
  }
}

Paso 9: El reportero revisa y envía al editor

El Reportero incorpora los hechos verificados y envía el borrador completo al Agente Editor a través de 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
    }
  }
}

Paso 10: Revisiones del editor usando herramientas MCP

El Editor Agent emplea múltiples servidores MCP para revisar el artículo:

# 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 feedback

El editor aprueba el artículo y lo envía hacia adelante:

{
  "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]"
  }
}

Paso 11: El editor publica vía CI/CD

Finalmente, el Agente de Impresora publica el artículo aprobado empleando los servidores MCP para la tubería CMS y 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"]
    }

El editor confirma la publicación a través de 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
    }
  }
}

Aquí está la secuencia completa del flujo de trabajo A2A en el repositorio adjunto usando los mismos Agentes descritos anteriormente.

#

De

Para

Acción

Protocolo

Descripción

1

Usuario

Jefe de Noticias

Asignar historia

HTTP POST

El usuario presenta la historia, tema y ángulo

2

Jefe de Noticias

Interno

Crear historia

-

Crea un registro de historia con un ID único

3

Jefe de Noticias

Reportero

Asignación de Delegados

A2A

Envía asignación de historia mediante el protocolo A2A

4

Reportero

Interno

Aceptar Asignación

-

Asignación interna de almacenes

5

Reportero

Servidor MCP

Generar esquema

MCP/HTTP

Crea un esquema de artículos y preguntas de investigación

6A

Reportero

Investigador

Solicitud de investigación

A2A

Envía preguntas (paralelo con 6b)

6b

Reportero

Archivero

Archivo de búsqueda

A2A JSONRPC

Busca en artículos históricos (paralelo con 6a)

7

Investigador

Servidor MCP

Preguntas de investigación

MCP/HTTP

Emplea Anthropic vía MCP para responder preguntas

8

Investigador

Reportero

Investigación de Retorno

A2A

Respuestas de investigación de retornos

9

Archivero

Elasticsearch

Índice de búsqueda

ES REST API

Consultas news_archive índice

10

Archivero

Reportero

Archivo de retorno

A2A JSONRPC

Devuelve resultados históricos de búsqueda

11

Reportero

Servidor MCP

Generar artículo

MCP/HTTP

Crea un artículo con contexto de investigación/archivo

12

Reportero

Interno

Tiro de la tienda

-

Salvamentos en el draft interno

13

Reportero

Jefe de Noticias

Enviar Borrador

A2A

Entrega borrador completado

14

Jefe de Noticias

Interno

Actualización de la historia

-

Borrador de la tienda, actualiza el estado a "draft_submitted"

15

Jefe de Noticias

Editor

Borrador de revisión

A2A

Rutas automáticas al Editor para su revisión

16

Editor

Servidor MCP

Artículo de revisión

MCP/HTTP

Analiza contenido usando Anthropic a través de MCP

17

Editor

Jefe de Noticias

Reseña de Retorno

A2A

Envía comentarios y sugerencias editoriales

18

Jefe de Noticias

Interno

Reseña de la tienda

-

Comentarios sobre el editor de tiendas

19

Jefe de Noticias

Reportero

Aplicar ediciones

A2A

Comentarios de la revisión de rutas al Reportero

20

Reportero

Servidor MCP

Aplicar ediciones

MCP/HTTP

Revisa el artículo basar en los comentarios

21

Reportero

Interno

Actualización del borrador

-

Borrador de actualizaciones con revisiones

22

Reportero

Jefe de Noticias

Devolución revisada

A2A

Artículo revisado de declaraciones

23

Jefe de Noticias

Interno

Actualización de la historia

-

Borrador revisado de las tiendas, estado a "revisado"

24

Jefe de Noticias

Editor

Publicar artículo

A2A

Rutas automáticas hacia el editor

25

Editor

Servidor MCP

Generar etiquetas

MCP/HTTP

Crea etiquetas y categorías

26

Editor

Elasticsearch

Artículo índice

ES REST API

Índice de artículos a índice news_archive

27

Editor

Sistema de archivos

Almacenar Markdown

E/S de archivos

Almacena el artículo como .md archivo en /articles

28

Editor

Jefe de Noticias

Confirmar publicación

A2A

Resultados de éxito

29

Jefe de Noticias

Interno

Actualización de la historia

-

Actualiza el estado de la noticia a "publicado"

Conclusión

Tanto A2A como MCP tienen papeles importantes en el paradigma moderno de infraestructura de LLM aumentado. A2A ofrece flexibilidad para sistemas complejos multiagente, pero potencialmente menos portabilidad y mayor complejidad operativa. MCP ofrece un enfoque estandarizado para la integración de herramientas que es más sencillo de implementar y mantener, aunque no está diseñado para manejar orquestación multiagente.

La elección no es binaria. Como demuestra nuestro ejemplo de redacción, los sistemas respaldados por LLM más sofisticados y efectivos suelen combinar ambos enfoques: los agentes coordinan y se especializan mediante protocolos A2A mientras acceden a sus herramientas y recursos a través de servidores MCP. Esta arquitectura híbrida ofrece los beneficios organizacionales de los sistemas multiagente junto con los beneficios de estandarización y ecosistema del MCP. Esto sugiere que puede que no sea necesario elegir en absoluto: simplemente usar ambos como un enfoque estándar

Depende de ti, como desarrollador o arquitecto, probar y determinar la mejor combinación de ambas soluciones para crear el resultado adecuado para tu caso de uso específico. Comprender las fortalezas, limitaciones y aplicaciones adecuadas de cada enfoque te permitirá construir sistemas de IA más eficaces, mantenibles y escalables.

Ya sea que estés construyendo una redacción digital, una plataforma de atención al cliente, un asistente de investigación o cualquier otra aplicación impulsada por LLM, considerar cuidadosamente tus necesidades de coordinación (A2A) y requisitos de acceso a herramientas (MCP) te pondrá en el camino hacia el éxito.

Recursos adicionales

Contenido relacionado

Agent Builder, más allá del chat: presentamos la infraestructura aumentada

Alexander Wert

Gestión de la memoria agentic con Elasticsearch

Someshwaran Mohankumar

Uso de la API de inferencia de Elasticsearch junto con modelos de Hugging Face

Jeffrey Rengifo

Construir un agente de IA para RRHH con Elastic Agent Builder y GPT-OSS

Tomás Murúa

Cómo crear un servidor MCP de Elasticsearch con TypeScript

Jeffrey Rengifo

¿Estás listo para crear experiencias de búsqueda de última generación?

No se logra una búsqueda suficientemente avanzada con los esfuerzos de uno. Elasticsearch está impulsado por científicos de datos, operaciones de ML, ingenieros y muchos más que son tan apasionados por la búsqueda como tú. Conectemos y trabajemos juntos para crear la experiencia mágica de búsqueda que te dará los resultados que deseas.

Pruébalo tú mismo