Google A2A Protocol: Building a Database Agent
In this article, I’ll demonstrate how to create a powerful database agent using the Google A2A Protocol. This agent can dynamically create tables, insert records, and query data — all through A2A protocol. If you’re new to the protocol, I recommend checking out my earlier articles where I explain the fundamentals of the Google A2A Protocol, its specifications, and how it compares to the Model Context Protocol (MCP). Those articles provide essential context on the key differences and similarities. The complete source code for this database agent is open source and actively maintained. Please note, it’s still evolving and not yet the final version. Service Class Create a service with annotations package io.github.vishalmysore.service; import com.t4a.annotations.Action; import com.t4a.annotations.Agent; import com.t4a.detect.ActionCallback; import io.github.vishalmysore.data.ColumnData; import io.github.vishalmysore.data.RowData; import io.github.vishalmysore.data.TableData; import io.github.vishalmysore.data.User; import io.github.vishalmysore.domain.Task; import io.github.vishalmysore.domain.TaskState; import lombok.extern.java.Log; import org.springframework.stereotype.Service; import java.sql.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @Log @Service @Agent(groupName = "Database related actions") public class DerbyService { @Action(description = "Create database") public String createDatabase(String databaseName) { ((Task)callback.getContext()).setDetailedAndMessage(TaskState.COMPLETED, "Creating database: " + databaseName); // Create a database try (Connection conn = DriverManager.getConnection(JDBC_URL)) { if (conn != null) { return "Database created successfully."; } else { return "Failed to create database."; } } catch (SQLException e) { e.printStackTrace(); } return "Failed to create database."; } The DerbyService class demonstrates how Java annotations like @agent and @Action can be used to declaratively define AI-powered agent capabilities using the Google A2A Protocol. The @agent annotation marks the class as an agent responsible for database-related actions, while each method annotated with @Action is exposed as an agent action. These annotations are automatically processed at runtime by the A2AJava framework, which converts them into discrete, executable tasks that can be triggered via natural language inputs or API calls. For example, actions such as starting a server, creating databases or tables, inserting records, and retrieving data are exposed as individual operations in the A2A agent framework. Each method operates within the context of a Task object, allowing the system to track state transitions such as COMPLETED, IN_PROGRESS, or FAILED. This enables seamless integration between user prompts and backend service execution, effectively turning annotated methods into intelligent agent behaviors. The A2A package uses reflection and runtime processing to detect these annotations, build a task graph, and dynamically invoke the corresponding logic when requested. This design decouples business logic from interaction logic, empowering developers to build sophisticated AI-enabled agents with minimal boilerplate, while ensuring traceability and observability through task states and contextual metadata. Agent Card import io.github.vishalmysore.domain.AgentCard; import io.github.vishalmysore.server.RealTimeAgentCardController; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/.well-known/") public class A2ADatabaseCardController extends RealTimeAgentCardController { @GetMapping(value = "/agent.json", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity getAgentCardForDatabase() { AgentCard card = getCachedAgentCard(); card.setUrl("http://localhost:7860"); // Replace with actual URL return ResponseEntity.ok(card); } } The A2ADatabaseCardController class is a streamlined Spring Boot REST controller that automatically generates and serves an AgentCard in compliance with the Google A2A Protocol. By extending the RealTimeAgentCardController, this class inherits logic that dynamically discovers all annotated actions (e.g., @Action, @agent) defined across the service classes—such as those in DerbyService—and compiles them into a machine-readable agent.json file. This file acts as a service manifest, allowing clients and A2A-compliant tools to discover the database agent's capabilities, including supported actions like creating tables, inserting data, and querying databases. De

In this article, I’ll demonstrate how to create a powerful database agent using the Google A2A Protocol. This agent can dynamically create tables, insert records, and query data — all through A2A protocol. If you’re new to the protocol, I recommend checking out my earlier articles where I explain the fundamentals of the Google A2A Protocol, its specifications, and how it compares to the Model Context Protocol (MCP). Those articles provide essential context on the key differences and similarities. The complete source code for this database agent is open source and actively maintained. Please note, it’s still evolving and not yet the final version.
Service Class
Create a service with annotations
package io.github.vishalmysore.service;
import com.t4a.annotations.Action;
import com.t4a.annotations.Agent;
import com.t4a.detect.ActionCallback;
import io.github.vishalmysore.data.ColumnData;
import io.github.vishalmysore.data.RowData;
import io.github.vishalmysore.data.TableData;
import io.github.vishalmysore.data.User;
import io.github.vishalmysore.domain.Task;
import io.github.vishalmysore.domain.TaskState;
import lombok.extern.java.Log;
import org.springframework.stereotype.Service;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Log
@Service
@Agent(groupName = "Database related actions")
public class DerbyService {
@Action(description = "Create database")
public String createDatabase(String databaseName) {
((Task)callback.getContext()).setDetailedAndMessage(TaskState.COMPLETED, "Creating database: " + databaseName);
// Create a database
try (Connection conn = DriverManager.getConnection(JDBC_URL)) {
if (conn != null) {
return "Database created successfully.";
} else {
return "Failed to create database.";
}
} catch (SQLException e) {
e.printStackTrace();
}
return "Failed to create database.";
}
The DerbyService class demonstrates how Java annotations like @agent and @Action can be used to declaratively define AI-powered agent capabilities using the Google A2A Protocol. The @agent annotation marks the class as an agent responsible for database-related actions, while each method annotated with @Action is exposed as an agent action. These annotations are automatically processed at runtime by the A2AJava framework, which converts them into discrete, executable tasks that can be triggered via natural language inputs or API calls. For example, actions such as starting a server, creating databases or tables, inserting records, and retrieving data are exposed as individual operations in the A2A agent framework.
Each method operates within the context of a Task object, allowing the system to track state transitions such as COMPLETED, IN_PROGRESS, or FAILED. This enables seamless integration between user prompts and backend service execution, effectively turning annotated methods into intelligent agent behaviors. The A2A package uses reflection and runtime processing to detect these annotations, build a task graph, and dynamically invoke the corresponding logic when requested. This design decouples business logic from interaction logic, empowering developers to build sophisticated AI-enabled agents with minimal boilerplate, while ensuring traceability and observability through task states and contextual metadata.
Agent Card
import io.github.vishalmysore.domain.AgentCard;
import io.github.vishalmysore.server.RealTimeAgentCardController;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/.well-known/")
public class A2ADatabaseCardController extends RealTimeAgentCardController {
@GetMapping(value = "/agent.json", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<AgentCard> getAgentCardForDatabase() {
AgentCard card = getCachedAgentCard();
card.setUrl("http://localhost:7860"); // Replace with actual URL
return ResponseEntity.ok(card);
}
}
The A2ADatabaseCardController class is a streamlined Spring Boot REST controller that automatically generates and serves an AgentCard in compliance with the Google A2A Protocol. By extending the RealTimeAgentCardController, this class inherits logic that dynamically discovers all annotated actions (e.g., @Action, @agent) defined across the service classes—such as those in DerbyService—and compiles them into a machine-readable agent.json file. This file acts as a service manifest, allowing clients and A2A-compliant tools to discover the database agent's capabilities, including supported actions like creating tables, inserting data, and querying databases.
Developers don’t need to manually configure or serialize the AgentCard. When a GET request is made to /.well-known/agent.json, the controller fetches the auto-generated AgentCard, optionally sets the endpoint URL (e.g., http://localhost:7860), and returns it as a JSON response. This hands-off architecture simplifies agent onboarding and ensures the agent metadata stays in sync with the actual codebase, making your AI-enabled microservices more scalable, discoverable, and interoperable in any A2A ecosystem.
Json RPC Controller
package io.github.vishalmysore;
import io.github.vishalmysore.domain.JsonRpcRequest;
import io.github.vishalmysore.server.A2ATaskController;
import io.github.vishalmysore.server.JsonRpcController;
import lombok.extern.java.Log;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/")
@Log
public class DatabaseRpCController extends JsonRpcController {
@PostMapping
public Object handleRpc(@RequestBody JsonRpcRequest request) {
log.info(request.toString());
return super.handleRpc(request);
}
@Override
public A2ATaskController getTaskController() {
return new DBTaskController();
}
}
The DatabaseRpCController extends the JsonRpcController and serves as a lightweight adapter that delegates all JSON-RPC method handling to the base controller while injecting a custom task controller (DBTaskController). It inherits support for a wide range of task-related methods defined in the base, including "tasks/send", "tasks/get", "tasks/sendSubscribe", "tasks/cancel", "tasks/setPushNotification", "tasks/getPushNotification", and "tasks/resubscribe". These methods are automatically routed and handled by the base JsonRpcController, making this class a simple plug-in point for injecting domain-specific task logic without modifying the core dispatch behavior
Task Controller
package io.github.vishalmysore;
import io.github.vishalmysore.domain.SendTaskResponse;
import io.github.vishalmysore.domain.TaskSendParams;
import io.github.vishalmysore.server.DyanamicTaskContoller;
import lombok.extern.java.Log;
@Log
public class DBTaskController extends DyanamicTaskContoller {
public SendTaskResponse sendTask(TaskSendParams taskSendParams) {
SendTaskResponse response= sendTask(taskSendParams, new CustomTaskCallback());
log.info("Task sent with ID: " + response.toString());
return response;
}
}
The DBTaskController is a thin extension of the DyanamicTaskContoller that overrides the sendTask method to inject a custom callback (CustomTaskCallback) when dispatching tasks. This callback integration ensures that task status updates are passed back into the A2A Java base framework for further handling, such as logging, monitoring, or triggering downstream processes. Aside from adding this callback, all core task execution logic remains within the base class, making this an efficient and modular way to extend functionality without altering the foundational framework.
Within your service class DerbyService, you can seamlessly update the status of a task during its execution by utilizing the CustomTaskCallback's context. This allows you to relay real-time progress back to the A2A Java framework. You can access the current Task instance from the callback and update its state using:
((Task) callback.getContext()).setDetailedAndMessage(TaskState.WORKING, "Creating database: " + databaseName);
Supported TaskState values include: SUBMITTED, WORKING, INPUT_REQUIRED, COMPLETED, CANCELED, FAILED, and UNKNOWN. These granular statuses help communicate precise task progress and outcomes to the client or orchestrating agent.
Hereby I have demonstrated how you can quickly create a database agent with the Google A2A Protocol and Spring Java. This implementation showcases how annotation-driven development can transform ordinary database operations into intelligent agent capabilities through simple @agent and @Action decorators.
The architecture leverages Spring Boot’s REST controllers to expose JSON-RPC endpoints and agent capability manifests, while delegating the actual database operations to an embedded Derby instance. By extending base controllers and task handlers from the A2A Java framework, this solution minimizes boilerplate code while maintaining full observability through task state transitions (SUBMITTED, WORKING, COMPLETED, etc.).
This is still work in progress, and I will continue to enhance it. The same approach can be used with MongoDB, PostgreSQL, or any other database system by simply swapping the underlying data access layer while preserving the A2A interface. The open-source implementation demonstrates the power and flexibility of the Google A2A Protocol for creating specialized, domain-specific agents that can participate in complex AI workflows.
Future enhancements will focus on improved error handling, transaction support, and expanded query capabilities to make this database agent even more robust for production use cases.
Source code for this article is available here