
This blog has been co-authored by Stephen Allen, Generative AI Solutions Architect and Elia Secchi, Solutions Specialist, Machine Learning at Google Cloud.
Earlier this month, we were excited to introduce a new feature that provides a complete foundation for building collaborative, production-ready agents: native Agent2Agent (A2A) protocol support in the Google Cloud Agent Starter Pack.
This release features adk_a2a_base, a new template in the starter pack that directly integrates Agent Development Kit (ADK) with the Agent2Agent (A2A) Protocol. A2A is a standard that allows your agents to discover and communicate with other autonomous agents—regardless of who built them or which framework they run on.
The goal of the Agent Starter Pack is to let you focus on your agent’s logic. The starter pack provides everything else: infrastructure, CI/CD, observability, and security.
This new template provides all the necessary scaffolding for your agent to communicate across different frameworks and even organizations, allowing you to focus solely on your agent’s core logic.
Getting started
Before you begin, you’ll need a few things set up.
Prerequisites
-
Google Cloud Project: You need a Google Cloud Project with the Vertex AI API enabled.
-
Authentication: You must be authenticated to your Google Cloud project.
-
Agent Starter Pack CLI: Ensure you have uv installed. You can find detailed installation instructions in the agent-starter-pack docs.
uvx agent-starter-pack create my-a2a-agent -a adk_a2a_base
This command creates a new directory named my-a2a-agent containing a complete project structure for your chosen deployment target, Vertex AI Agent Engine or Cloud Run.
Focus on your logic: The common agent
This is the core theme of the starter pack. Regardless of your deployment target, your primary focus will be in app/agent.py. This is where you define your agent’s identity, tools, and instructions using ADK. The scaffolding, which we’ll see later, handles how this logic is served.
Here is the example app/agent.py from the template:
import datetime
from zoneinfo import ZoneInfo
from google.adk.agents import Agent
from google.adk.apps.app import App
def get_weather(query: str) -> str:
"""Simulates a web search. Use it to get information on weather."""
if "sf" in query.lower() or "san francisco" in query.lower():
return "It's 60 degrees and foggy."
return "It's 90 degrees and sunny."
def get_current_time(query: str) -> str:
"""Simulates getting the current time for a city."""
if "sf" in query.lower() or "san francisco" in query.lower():
tz_identifier = "America/Los_Angeles"
else:
return f"Sorry, I don't have timezone information for query: {query}."
tz = ZoneInfo(tz_identifier)
now = datetime.datetime.now(tz)
return f"The current time for query {query} is {now.strftime('%Y-%m-%d %H:%M:%S %Z%z')}"
root_agent = Agent(
name="root_agent",
model="gemini-2.5-flash",
description="An agent that can provide information about the weather and time.",
instruction="You are a helpful AI assistant designed to provide accurate and useful information.",
tools=[get_weather, get_current_time],
)
app = App(root_agent=root_agent, name="app")
This is your domain. You add tools, tweak prompts, and define behavior here. Now, let’s see how the A2A scaffolding uses this app object for each deployment path.
Vertex AI Agent Engine
If you select Vertex AI Agent Engine, the starter pack generates a project built for a managed platform. The key scaffolding file is app/agent_engine_app.py.
import asyncio
from typing import Any
import click
import vertexai
from a2a.types import AgentCapabilities, AgentCard, TransportProtocol
from google.adk.a2a.executor.a2a_agent_executor import A2aAgentExecutor
from google.adk.a2a.utils.agent_card_builder import AgentCardBuilder
from google.adk.apps.app import App
from google.adk.artifacts import GcsArtifactService
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from vertexai._genai.types import AgentEngine, AgentEngineConfig
from vertexai.preview.reasoning_engines import A2aAgent
from app.agent import app
class AgentEngineApp(A2aAgent):
@staticmethod
def create(
app: App = None,
artifact_service: Any = None,
session_service: Any = None,
) -> Any:
"""Create an AgentEngineApp instance."""
if app is None:
app = adk_app
def create_runner() -> Runner:
"""Create a Runner for the AgentEngineApp."""
return Runner(
app=app,
session_service=session_service,
artifact_service=artifact_service,
)
try:
asyncio.get_running_loop()
nest_asyncio.apply()
except RuntimeError:
pass
agent_card = asyncio.run(AgentEngineApp.build_agent_card(app=app))
return AgentEngineApp(
agent_executor_builder=lambda: A2aAgentExecutor(runner=create_runner()),
agent_card=agent_card,
)
@staticmethod
async def build_agent_card(app: App) -> AgentCard:
"""Builds the Agent Card dynamically from the app."""
agent_card_builder = AgentCardBuilder(
agent=app.root_agent,
# Agent Engine does not support streaming yet
capabilities=AgentCapabilities(streaming=False),
rpc_url="http://localhost:9999/",
agent_version=os.getenv("AGENT_VERSION", "0.1.0"),
)
agent_card = await agent_card_builder.build()
agent_card.preferred_transport = TransportProtocol.http_json # Http Only.
agent_card.supports_authenticated_extended_card = True
return agent_card
agent_engine = AgentEngineApp.create(
app=adk_app,
artifact_service=GcsArtifactService(bucket_name=artifacts_bucket_name) if artifacts_bucket_name else None,
session_service=InMemorySessionService(),
)
For Agent Engine, the scaffolding class itself inherits from A2aAgent.
-
AgentEngineApp(A2aAgent): This shows that the entire application wrapper is, by design, an A2A-compliant agent. -
A2aAgentExecutor(...): This A2A agent executor is the bridge to your ADK logic. -
AgentCardBuilder(...): Used to build the agent’s public-facing card from youragent.pyfile. -
deploy_agent_engine_app: Thisclickscript, provided by the template, handles all the infrastructure-as-code. It packages yourAgentEngineApp(which is A2A-compliant) and deploys it to the managed platform.
Cloud Run
If you select Cloud Run, the starter pack generates a standard FastAPI web server. The key scaffolding file is app/server.py, which makes your ADK agent A2A-compliant.
from contextlib import asynccontextmanager
from a2a.server.apps import A2AFastAPIApplication
from a2a.server.request_handlers import DefaultRequestHandler
from a2a.server.tasks import InMemoryTaskStore
from a2a.types import AgentCapabilities, AgentCard
from a2a.utils.constants import (
AGENT_CARD_WELL_KNOWN_PATH,
EXTENDED_AGENT_CARD_PATH,
)
from fastapi import FastAPI
from google.adk.a2a.executor.a2a_agent_executor import A2aAgentExecutor
from google.adk.a2a.utils.agent_card_builder import AgentCardBuilder
from google.adk.artifacts.gcs_artifact_service import GcsArtifactService
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from app.agent import app as adk_app
runner = Runner(
app=adk_app,
artifact_service=GcsArtifactService(bucket_name=bucket_name),
session_service=InMemorySessionService(),
)
request_handler = DefaultRequestHandler(
agent_executor=A2aAgentExecutor(runner=runner),
task_store=InMemoryTaskStore()
)
A2A_RPC_PATH = f"/a2a/{adk_app.name}"
async def build_dynamic_agent_card() -> AgentCard:
"""Builds the Agent Card dynamically from the root_agent."""
agent_card_builder = AgentCardBuilder(
agent=adk_app.root_agent,
capabilities=AgentCapabilities(streaming=True),
rpc_url=f"{os.getenv('APP_URL', 'http://0.0.0.0:8000')}{A2A_RPC_PATH}",
)
agent_card = await agent_card_builder.build()
return agent_card
@asynccontextmanager
async def lifespan(app_instance: FastAPI) -> AsyncIterator[None]:
agent_card = await build_dynamic_agent_card()
a2a_app = A2AFastAPIApplication(agent_card=agent_card, http_handler=request_handler)
a2a_app.add_routes_to_app(
app_instance,
agent_card_url=f"{A2A_RPC_PATH}{AGENT_CARD_WELL_KNOWN_PATH}",
rpc_url=A2A_RPC_PATH,
extended_agent_card_url=f"{A2A_RPC_PATH}{EXTENDED_AGENT_CARD_PATH}",
)
yield
# The main FastAPI app is created
app = FastAPI(
title="my-a2a-agent",
description="API for interacting with the Agent my-a2a-agent",
lifespan=lifespan,
)
The key takeaway is that app/server.py is a standard FastAPI app, and the a2a-sdk provides helpers to make it A2A-compliant in just a few lines:
-
A2aAgentExecutor(runner=runner): This is the bridge. It’s an A2A agent executor that wraps your standard ADK Runner. -
AgentCardBuilder(...): Builds the agent card directly from youradk_app.root_agentdefinition. -
A2AFastAPIApplication(...): This is a helper class from the SDK that contains the logic for serving A2A requests. -
a2a_app.add_routes_to_app(...): This one line automatically creates A2A-compliant endpoints (/.well-known/agent-card.json, etc.) on your FastAPI server.
Production-ready from day one
You don’t just get scaffolding. The adk_a2a_base template generates a full production setup for your chosen path.
-
Production-Ready CI/CD: You don’t need to build your own automation. The template includes a full CI/CD pipeline with linting, unit tests, and—most importantly—automated integration tests that deploy your agent to its target to ensure it works before merging.
-
Observability: Built-in logging and tracing configurations.
-
Security: Standard container setup and deployment patterns.
The adk_a2a_base template marks a significant step forward in simplifying the development of complex, multi-agent systems. We are incredibly excited to see what you build with these new capabilities.
Explore the resources
-
Get started with the agent-starter-pack: https://github.com/GoogleCloudPlatform/agent-starter-pack
-
View the Development Guide: https://googlecloudplatform.github.io/agent-starter-pack/guide/development-guide.html
-
ADK Docs: https://google.github.io/adk-docs/
-
A2A Docs: https://a2a-protocol.org/latest/