A multi-agent system for generating comprehensive research reports using specialized AI agents communicating exclusively via the A2A (Agent-to-Agent) Protocol v1.0 and using the MCP (Model Context Protocol) 2025-11-25 specification for all tool-calling.
ARRG is currently well along, but still a work in progress. So far I have only tested with the Tetrate
provider, using claude-haiku-4-5. Example reports are in the example_reports directory.
ARRG uses five specialized agents working together to produce high-quality research reports:
- Planning Agent: Creates structured research plans with outlines and methodologies
- Research Agent: Gathers information and sources based on research questions (uses MCP tools)
- Analysis Agent: Synthesizes research data into insights and findings
- Writing Agent: Transforms analysis into polished, professional reports
- QA Agent: Reviews and validates reports for quality and accuracy
ARRG uses two complementary protocols that separate concerns cleanly:
All agent-to-agent communication uses the A2A Protocol exclusively:
- AgentCards — Each agent advertises its capabilities via an
AgentCardwith skills, supported input/output modes, and provider metadata (per the A2A discovery spec) - Tasks — The unit of work exchanged between agents. Tasks follow the A2A lifecycle state machine:
submitted → working → completed/failed(with additional states:canceled,input_required,rejected,auth_required) - Messages — Communication within tasks uses
Messageobjects with arole(user/agent) and typedParts:TextPart— Plain text contentDataPart— Structured JSON data (research plans, analysis results, etc.)FilePart— Binary file content with MIME types
- Artifacts — Deliverable outputs attached to completed tasks (reports, QA results, etc.)
- TaskStatus — Tracks state transitions with timestamps and status messages
The orchestrator creates A2A Tasks for each phase of the workflow and sends Messages to agents via process_task(). Agents process the task, transition through states, and return completed tasks with artifacts.
All tool-calling follows the MCP specification:
- Tool Discovery — Tools are registered in an
MCPToolRegistrywith JSON Schema input definitions - Tool Invocation — LLM-initiated tool calls are executed via
MCPToolCall/MCPToolResult - Built-in Tools —
web_searchfor internet research, extensible to more tools - JSON-RPC 2.0 — MCP communication uses standard JSON-RPC over stdio transport
Why two protocols? A2A handles agent-to-agent communication (task delegation, results, artifacts), while MCP handles agent-to-tool communication (search, file I/O, APIs). They are complementary — an agent receives work via A2A and uses MCP tools to accomplish it.
┌─────────────────────────────────────────────────────┐
│ Orchestrator │
│ (creates A2A Tasks, routes Messages) │
└─────────┬───────┬───────┬───────┬───────┬───────────┘
│ A2A │ A2A │ A2A │ A2A │ A2A
▼ ▼ ▼ ▼ ▼
┌─────────┐ ┌─────┐ ┌────────┐ ┌───────┐ ┌────┐
│Planning │ │Rsrch│ │Analysis│ │Writing│ │ QA │
│ Agent │ │Agent│ │ Agent │ │ Agent │ │Agnt│
└─────────┘ └──┬──┘ └────────┘ └───────┘ └────┘
│ MCP
▼
┌─────────┐
│MCP Tools│
│(search) │
└─────────┘
- Planning — Orchestrator sends topic via A2A Task → Planning Agent returns research plan
- Research — Research questions sent via A2A Task → Research Agent uses MCP
web_searchtool → returns findings - Analysis — Research data sent via A2A Task → Analysis Agent returns synthesized insights
- Writing — Analysis sent via A2A Task → Writing Agent returns formatted report
- QA — Report sent via A2A Task → QA Agent returns quality assessment
- Revision Loop — If QA rejects, the report is sent back to Writing Agent with feedback (up to 2 retries)
Each workflow phase follows the A2A task state machine:
submitted → working → completed
→ failed
→ input_required (for revision requests)
The orchestrator tracks all tasks and their state transitions, maintaining a full message history for debugging and audit.
from arrg.a2a import AgentCard, AgentSkill, AgentProvider, AgentCapabilities
card = AgentCard(
name="Research Agent",
description="Gathers information from web sources",
url="local://research-agent",
provider=AgentProvider(organization="ARRG"),
capabilities=AgentCapabilities(streaming=True),
skills=[
AgentSkill(
id="web_research",
name="Web Research",
description="Search and synthesize web sources",
tags=["research", "search"],
)
],
input_modes=["application/json"],
output_modes=["application/json"],
)from arrg.a2a import Task, TaskState, Message, MessageRole, TextPart, DataPart
# Create a task
task = Task()
# Add a user message with text and structured data
message = Message.create_user_message(
text="Research the impact of AI on healthcare",
data={"topic": "AI in healthcare", "questions": ["What are the benefits?"]},
sender="orchestrator",
task_id=task.id,
)
task.add_message(message)
# Update task state
task.update_state(TaskState.WORKING, message="Agent processing...")
task.update_state(TaskState.COMPLETED, message="Research complete")from arrg.a2a import Artifact
# Create a data artifact
artifact = Artifact.create_data_artifact(
data={"findings": [...], "sources": [...]},
name="research_results",
description="Research findings for AI in healthcare",
)
task.add_artifact(artifact)# Clone the repository
git clone <repository-url>
cd arrg
# Install in development mode
pip install -e .
# Run the dashboard
python -m arrg dashboard
# Or generate a report from CLI
python -m arrg cli --topic "Your Research Topic" --api-key YOUR_API_KEYpython -m arrg dashboard
# or
streamlit run arrg/ui/dashboard.pypython -m arrg cli --topic "The Impact of AI on Healthcare" --api-key YOUR_KEY --model claude-haiku-4-5from arrg import Orchestrator
from pathlib import Path
orchestrator = Orchestrator(
api_key="your-api-key",
provider_endpoint="Tetrate",
models={"planning": "claude-haiku-4-5", "research": "claude-haiku-4-5", ...},
workspace_dir=Path("./workspace"),
)
result = orchestrator.generate_report("Your Research Topic")
if result["status"] == "success":
report = result["report"]
print(report["title"])
print(report["full_text"])arrg/
├── a2a/ # A2A Protocol v1.0 implementation
│ ├── __init__.py # Package exports
│ ├── agent_card.py # AgentCard, AgentSkill, AgentProvider, AgentCapabilities
│ ├── task.py # Task, TaskState, TaskStatus
│ ├── message.py # Message, MessageRole, TextPart, DataPart, FilePart
│ └── artifact.py # Artifact with typed Parts
├── agents/ # Agent implementations
│ ├── base.py # BaseAgent (abstract) - A2A + MCP integration
│ ├── planning.py # PlanningAgent - research plan generation
│ ├── research.py # ResearchAgent - web research via MCP tools
│ ├── analysis.py # AnalysisAgent - data synthesis
│ ├── writing.py # WritingAgent - report composition + revision
│ └── qa.py # QAAgent - quality validation
├── core/
│ └── orchestrator.py # Workflow orchestrator (A2A task coordination)
├── mcp/ # MCP 2025-11-25 implementation
│ ├── client.py # MCP client (JSON-RPC/stdio)
│ ├── server.py # MCP server
│ ├── schema.py # MCP tool schemas
│ └── tools.py # Built-in tools (web_search)
├── protocol/ # Backward-compatible re-exports from a2a/
│ ├── __init__.py # Re-exports A2A types + SharedWorkspace
│ ├── message.py # Deprecated shim → arrg.a2a
│ └── workspace.py # SharedWorkspace (key-value artifact storage)
├── ui/
│ └── dashboard.py # Streamlit dashboard
├── utils/
│ └── llm_client.py # LLM API client (OpenAI/Anthropic)
├── __init__.py # Package exports
└── __main__.py # CLI entry point
Every interaction between agents uses A2A Protocol data structures:
- No custom message types — All messages use
MessagewithTextPart/DataPartinstead of custom enums - Task-centric workflow — Each phase creates an A2A
Taskwith proper state transitions - Artifacts for outputs — Agent deliverables are represented as A2A
Artifactobjects - AgentCards for discovery — Each agent advertises capabilities via an
AgentCardwith skills
MCP is used exclusively for tool calling (web search, etc.) — it does NOT handle agent-to-agent communication. This clean separation follows the intended design of both protocols:
- A2A = how agents talk to each other
- MCP = how agents use tools
Large data (research results, full reports) is stored in a SharedWorkspace and referenced by key in A2A messages. This avoids passing large payloads directly in messages while maintaining A2A Protocol compliance — the workspace key is passed as a DataPart within an A2A Message.
Register a new tool in arrg/mcp/tools.py:
from arrg.mcp import MCPTool, MCPToolCall, MCPToolResult, TextContent
def my_tool_executor(call: MCPToolCall) -> MCPToolResult:
"""Execute the tool and return MCP-compliant result."""
result_text = f"Executed with args: {call.arguments}"
return MCPToolResult(
call_id=call.call_id,
content=[TextContent(text=result_text)],
is_error=False,
)
# In MCPToolRegistry._register_builtin_tools():
self.register_tool(
MCPTool(
name="my_tool",
description="Description of my tool",
inputSchema={
"type": "object",
"properties": {
"param1": {"type": "string", "description": "First parameter"},
},
"required": ["param1"],
},
),
executor=my_tool_executor,
)- Create a new agent class inheriting from
BaseAgent - Implement
get_capabilities()returning a list of skill descriptions - Implement
process_task(task: Task) -> Taskfollowing the A2A task lifecycle - Add the agent to the orchestrator workflow
- Create an
AgentSkillfor each capability the agent offers
API Key Error:
- Ensure your API key is correctly entered in the sidebar
- Verify the key has access to the selected model
Model Not Available:
- Check that your provider supports the selected model
- Try a different model from the dropdown
Workspace Errors:
- Ensure the
./workspacedirectory is writable - Clear the workspace if it contains corrupted data
Import Errors:
- Verify the package is installed:
pip install -e . - Check Python version:
python --version(requires 3.12+)
MCP Tool Errors:
- Check tool registry initialization:
python -c "from arrg.mcp import get_tool_registry; r = get_tool_registry(); print(r.list_tools())" - Verify tool schemas:
python -c "from arrg.mcp import get_tool_registry; r = get_tool_registry(); print([t.name for t in r.list_tools()])"
[Your License Here]
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
For issues and questions:
- Open an issue on GitHub
- Check the documentation
- Review the PRD (Product Requirements Document)
Future enhancements:
- HTTP JSON-RPC transport for true networked A2A communication
- A2A Agent Card serving at
/.well-known/agent-card.json - SSE streaming for real-time task updates via A2A
- A2A push notifications
- Replace mock tool executors with real implementations (web search API, file I/O, etc.)
- Support for multi-topic batch processing
- Advanced citation and reference management
- Integration with external research databases via MCP client connections
- Custom agent plugins
- Report templates and styling options
- Collaboration features for team workflows
- API endpoint for programmatic access
- MCP server discovery and multi-server tool aggregation