DEV Community

vishalmysore
vishalmysore

Posted on

A2A MCP RAG Application : Live Demo

Image description

Building a Dual-Protocol RAG Application with A2A and MCP

In this tutorial, we'll build a sophisticated Retrieval-Augmented Generation (RAG) application that supports both Google's Agent-to-Agent (A2A) protocol and Model Context Protocol (MCP). The unique aspect? We'll create a single application that seamlessly works with both protocols using a2ajava, a versatile framework for building agent-based applications.It is multi-protocol — works seamlessly with both A2A (Agent-to-Agent) and MCP (Model Context Protocol). It is multi-language — supports Java, Kotlin, and Groovy. It is multi-platform — compatible with Gemini, OpenAI, Claude, and Grok. It is multi-client — includes A2A and MCP clients with connectors in Java, Node, and Python. It provides multi-integration — out-of-the-box support for Selenium, human-in-the-loop workflows, multi-LLM voting for consensus-based decision making, RAG integration, Spring Security, and RBAC control. Agents built using the A2A protocol with a2ajava run seamlessly on MCP as well, ensuring maximum interoperability across platforms. It is also multi-channel — supports Shell, HTTP endpoints, and Java actions, with hundreds of examples and live demos, making it incredibly easy to get started. Additionally, it can integrate with robotics applications, acting as an LLM-based router to intelligently route HTTP REST calls to microcontrollers.

System Architecture

The system architecture combines several key components:

  1. RAG Engine: MongoDB Atlas Vector Store for semantic search
  2. Protocol Support: Dual protocol handlers for A2A and MCP
  3. Agent Services: Annotated Java classes that auto-convert to both A2A tasks and MCP tools

Live Demo

The application is deployed and accessible at:

https://vishalmysore-a2amcpmongo.hf.space/
Enter fullscreen mode Exit fullscreen mode

Adding the Agent

For A2A clients, add the agent using:

vishalmysore-a2amcpmongo.hf.space
Enter fullscreen mode Exit fullscreen mode

The agent card will automatically load from:

https://vishalmysore-a2amcpmongo.hf.space/.well-known/agent.json
Enter fullscreen mode Exit fullscreen mode

MCP Integration

For MCP clients like Claude Desktop, add the following configuration:

Java Connector

{
  "laundry": {
    "command": "java",
    "args": [    
      "-jar",
      "/work/a2a-mcp-bridge/target/mcp-connector-full.jar",
      "https://vishalmysore-a2amcpmongo.hf.space/" 
    ],
    "timeout": 30000
  }
}
Enter fullscreen mode Exit fullscreen mode

Node.js Connector

{
  "admincar": {
    "command": "node",
    "args": [    
      "/work/a2a-mcp-bridge/src/main/resources/a2ajava.cjs",
      "https://vishalmysore-a2amcpdemo.hf.space/" 
    ],
    "timeout": 30000
  }
}
Enter fullscreen mode Exit fullscreen mode

The MCP connector code is available on GitHub:
https://github.com/vishalmysore/mcp-connector/

API Documentation and Testing

Swagger UI

API documentation is available through Swagger UI:

https://vishalmysore-a2amcpmongo.hf.space/swagger-ui/index.html
Enter fullscreen mode Exit fullscreen mode

MCP Tools List

View available MCP tools:

https://vishalmysore-a2amcpmongo.hf.space/mcp/list-tools
Enter fullscreen mode Exit fullscreen mode

RAG Search Example

Query the vector database for similar tasks:

curl -X 'GET' \
  'https://vishalmysore-a2amcpmongo.hf.space/getTask?taskText=wedding%20dress' \
  -H 'accept: */*'
Enter fullscreen mode Exit fullscreen mode

Protocol Conversion

Example of protocol conversion between A2A and MCP

Implementation Details

The magic behind the protocol conversion lies in the agent implementation. The following Java class automatically gets converted into both A2A tasks and MCP tools:

package vishalmysore;

import com.t4a.annotations.Action;
import com.t4a.annotations.Agent;
import com.t4a.detect.ActionCallback;
import com.t4a.detect.ActionState;
import lombok.extern.java.Log;

@log
@agent(groupName = "laundry", groupDescription = "actions related to laundry")
public class LaundryMachine {
private ActionCallback callback;

private boolean isRunning = false;
private int temperature = 30;
private String cycleType = "normal";
@Action(description = "Start the washing machine")
public void startWashing() {
    log.info("Washing started");
}

@Action(description = "get quote for laundry")
public Integer getQuoteForLaundry(String typeOfCloth, String weight) {
    log.info("Quote for laundry: " + typeOfCloth + ", " + weight);
    if(callback!= null) {
        callback.sendtStatus("Quote for laundry: " + typeOfCloth + ", " + weight+" is "+100, ActionState.COMPLETED);
    }
    return 100;
}

@Action(description = "Stop the washing machine")
public void stopWashing() {
    isRunning = false;
    log.info("Washing stopped");
    if(callback != null) {
        callback.sendtStatus("Washing machine stopped", ActionState.COMPLETED);
    }
}

@Action(description = "Set washing temperature")
public void setTemperature(int temp) {
    this.temperature = temp;
    log.info("Temperature set to: " + temp);
    if(callback != null) {
        callback.sendtStatus("Temperature set to " + temp + " degrees", ActionState.COMPLETED);
    }
}

@Action(description = "Select washing cycle type")
public void setCycleType(String cycle) {
    this.cycleType = cycle;
    log.info("Cycle type set to: " + cycle);
    if(callback != null) {
        callback.sendtStatus("Cycle type changed to " + cycle, ActionState.COMPLETED);
    }
}

@Action(description = "Get machine status")
public String getStatus() {
    String status = String.format("Machine is %s, Temperature: %d°C, Cycle: %s",
            isRunning ? "running" : "stopped", temperature, cycleType);
    log.info("Status checked: " + status);
    return status;
}
Enter fullscreen mode Exit fullscreen mode

}

How It Works

  1. The @Agent annotation defines the service group and description
  2. Each @Action annotated method becomes both:
    • An A2A task endpoint
    • An MCP tool
  3. Methods are exposed via JSON-RPC endpoints
  4. RAG integration stores task details in MongoDB vector store
  5. Semantic search enables natural language querying

Testing in Different Environments

Claude Integration

Using the service through Claude

Tool Chain View

Visualizing the tool chain integration

Conclusion

This implementation demonstrates the power of protocol-agnostic design in AI services. By supporting both A2A and MCP protocols, we enable broader integration possibilities while maintaining a single, maintainable codebase.

For more examples and detailed documentation, visit the a2ajava GitHub repository.

✅ Advantages of the Dual-Protocol Architecture

1. Maximum Interoperability

  • Supports both Google A2A and Anthropic MCP protocols
  • Agents serve multiple ecosystems (Gemini, Claude) simultaneously
  • Single codebase works across different vendors, tools, and LLM providers

2. Single Codebase, Multiple Targets

Thanks to annotation-based design (@Agent, @Action), you write once and expose as:

  • A2A Tasks
  • MCP Tools
  • REST Endpoints
  • Shell Commands (optional)

This approach reduces development effort, ensures maintainability, and prevents protocol lock-in.

3. Multi-Language + Multi-Platform

  • JVM Ecosystem: Java, Kotlin, Groovy support
  • LLM Integration: OpenAI, Claude, Grok, Gemini
  • Client Support: Java, Node.js, Python

4. Built-in AI Ops and RAG Integration

  • Seamless MongoDB Atlas integration for vector storage
  • Protocol-agnostic retrieval and generation
  • Agents learn and serve from vectorized memory

5. Full DevSecOps Support

  • RBAC and Spring Security integration
  • Selenium for agent testing
  • Multi-LLM voting capabilities
  • Production-ready AI platform features

6. Human-in-the-Loop and Robotic Control

  • Critical decision workflow support
  • REST-based hardware control
  • LLM routers for physical actuation (e.g., Chotu Robo)

🚀 Future Expansion Opportunities

1. Agent Orchestration Layer

Build a meta-agent system that can:

  • Discover agents dynamically (agent registry)
  • Assign tasks based on capabilities and load
  • Track agent skills and performance
  • Implement dynamic load balancing

2. Agent Marketplace

  • Agent registration with metadata (capabilities.json, requirements.json)
  • Runtime plugin system for third-party agents
  • Simple deployment via JAR or .agent.json descriptors

3. Monitoring Console

Create a Spring Boot + React UI for:

  • Real-time agent status visualization
  • Workflow triggering and management
  • LLM response and RAG query monitoring

4. Scalability and Edge Computing

  • Containerized agent deployment
  • Auto-scaling based on LLM request volume
  • Edge deployment support (Raspberry Pi, ESP32)
  • Microservice-style agent interactions

5. Advanced Voting Strategies

Enhance multi-LLM decision making with:

  • Weighted voting systems
  • Specialty-based routing (e.g., Claude for legal, Grok for tech)
  • Response-time-based fallback mechanisms

6. Memory-Aware Agent Chains

Implement sophisticated workflows:

  1. RAG-based information retrieval
  2. LLM-powered decision making
  3. External system integration
  4. Shared vector memory storage
  5. Long-term context preservation

7. Enhanced Security and Observability

Integrate with:

  • OpenTelemetry for distributed tracing
  • Spring Boot Actuator for health metrics
  • Comprehensive request auditing
  • Protocol-specific interaction logging

8. Universal Protocol Conversion

Create dynamic protocol converters:

  • JSON-RPC ↔ LangChain tools
  • A2A ↔ OpenAI Function Calls
  • MCP ↔ Zapier plugins

📌 Strategic Vision

This architecture represents more than just a dual-protocol application—it's a comprehensive platform strategy. With a2ajava, you're positioned at the intersection of:

  • Agent-based computing
  • LLM interoperability
  • Full-stack enterprise integration

By expanding into agent orchestration, edge deployment, and developer plugins, this framework is poised to become the standard for enterprise GenAI applications.

Top comments (0)