◉GEMINI LABJP
●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●DEEP RES — deep-research-pro-preview-12-2025 shuts down 10/23, 6 days left. Move to deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●MCP — One write-up cut an 85,000-token tool result to 310 tokens by wrapping it in an ADK FunctionTool●FLASH — gemini-3.7-flash and 3.5-flash now route automatically to newer Flash models (10/08)●NEW — Stop Re-Reading Every Crash Report: Gre…●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●DEEP RES — deep-research-pro-preview-12-2025 shuts down 10/23, 6 days left. Move to deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●MCP — One write-up cut an 85,000-token tool result to 310 tokens by wrapping it in an ADK FunctionTool●FLASH — gemini-3.7-flash and 3.5-flash now route automatically to newer Flash models (10/08)●NEW — Stop Re-Reading Every Crash Report: Gre…
Articles/Advanced
⬡ Advanced/2026-04-11Advanced

Connecting Gemini Agents with Google's A2A Protocol: Design, Implementation, and Cloud Run Operations

Build cross-framework agent coordination with the Agent2Agent (A2A) protocol and Gemini API. Agent card design, measured comparison of three coordination patterns, and the operational details that matter on Cloud Run.

a2aagent2agentgemini-api286multi-agentadkprotocolproduction140

✦ Premium Article

One night I split my article pipeline into three agents. Topic selection, drafting, quality checks. Cleaner separation, I thought.

A week later I was staring at my own glue code, stuck. As an indie developer, I own every seam I create — there is no platform team to hand them to. The three agents were written against different libraries, and every seam meant reshaping JSON, picking a timeout, and hand-rolling retry logic. The glue had grown longer than the agents.

Google's Agent2Agent (A2A) protocol is an attempt to standardize that seam. Agents built on different frameworks, from different providers, speak one HTTP-based spec. Neither side needs to know how the other is implemented.

What follows walks through the A2A specification, builds a FastAPI implementation alongside Gemini API and ADK, and takes it all the way to Cloud Run. The later sections cover the operational lessons I only found by running it.

Who this is for:

  • Developers with existing Gemini API agent experience
  • Engineers looking to build multi-agent coordination systems
  • Teams ready to apply A2A protocol in production environments

Reading Gemini API Function Calling: Tool Integration in Practice and Building a Custom Gemini API Agent Loop Without ADK first will make the design decisions here easier to follow.


A2A Protocol Specification and Core Concepts

Protocol Architecture

A2A is a lightweight specification built on HTTP/JSON-RPC 2.0. Each agent operates as an "A2A server," exposing standardized endpoints that any A2A client can interact with.

The four core components of A2A are:

① Agent Card: A JSON metadata document describing an agent's capabilities, endpoint URL, and authentication requirements. Published at /.well-known/agent.json, this is how other agents "discover" your agent.

② Task: The unit of work a client delegates to an agent. Each task has a unique ID and progresses through a lifecycle: submitted → working → completed / failed.

③ Artifact: The output produced by a task. Supports multiple MIME types (text, JSON, files) and can be streamed incrementally during processing.

④ Message: The communication channel during task execution. Enables multi-turn dialogue between user and agent, or between coordinating agents.

Communication Flow

Client                          A2A Server (Agent)
  |                                     |
  |--- GET /.well-known/agent.json ---> |  ① Discover agent capabilities
  |<-- {"name":"...", "skills":[...]} --|
  |                                     |
  |--- POST /tasks/send --------------> |  ② Submit task
  |    {"id":"task-123",                |
  |     "message":{"role":"user",...}}  |
  |<-- {"status":{"state":"submitted"}} |
  |                                     |
  |--- GET /tasks/get?id=task-123 ----> |  ③ Poll for result
  |<-- {"status":{"state":"completed"}, |
  |     "artifacts":[...]}              |
  |                                     |
  |  OR — subscribe to real-time stream |
  |--- POST /tasks/sendSubscribe -----> |
  |<== data: {"type":"artifact",...}  --|  (SSE streaming)
  |<== data: {"type":"status",...}   --|

Designing an Agent Card

The agent card is your agent's calling card—it determines what requests other agents will send your way. A well-designed card improves discoverability and reduces integration friction.

{
  "name": "Data Analysis Agent",
  "description": "Statistical analysis of CSV and JSON data with insights and visualizations",
  "url": "https://data-agent.example.run.app",
  "version": "1.2.0",
  "capabilities": {
    "streaming": true,
    "pushNotifications": false
  },
  "authentication": {
    "schemes": ["Bearer"]
  },
  "skills": [
    {
      "id": "analyze-csv",
      "name": "CSV Statistical Analysis",
      "description": "Accepts a CSV file or text, returns statistics (mean, variance, correlation) and key business insights",
      "inputModes": ["text", "file"],
      "outputModes": ["text", "data"]
    },
    {
      "id": "generate-chart",
      "name": "Data Visualization",
      "description": "Automatically selects the best chart type (bar, line, scatter) and generates it from numerical data",
      "inputModes": ["data"],
      "outputModes": ["file"]
    }
  ]
}

Design guidelines:

  • Write description in one sentence that captures the agent's specific domain
  • Make skills[].description concrete: what goes in, what comes out
  • Be precise with inputModes / outputModes—clients use these to decide if your agent is the right choice

Setup and Basic A2A Server Implementation

Installing Dependencies

# Google ADK (includes A2A server utilities)
pip install google-adk
 
# Gemini API client
pip install google-generativeai
 
# Web framework + utilities
pip install fastapi uvicorn httpx pyjwt

Minimal A2A Server

# a2a_server.py
import uuid
import asyncio
from datetime import datetime
from typing import Optional
from fastapi import FastAPI, HTTPException, BackgroundTasks
from pydantic import BaseModel
import google.generativeai as genai
import os
 
# Initialize Gemini API
# ⚠️ Always load API keys from environment variables in production
genai.configure(api_key=os.environ["GEMINI_API_KEY"])
model = genai.GenerativeModel("gemini-2.5-pro")
 
app = FastAPI(title="Gemini A2A Agent", version="1.0.0")
 
# Task store (use Redis or Firestore in production)
tasks: dict[str, dict] = {}
 
# =====================
# Agent Card Definition
# =====================
AGENT_CARD = {
    "name": "Gemini General Analysis Agent",
    "description": "Text analysis, summarization, and structured data extraction powered by Gemini 2.5 Pro",
    "url": "https://your-agent.run.app",
    "version": "1.0.0",
    "capabilities": {"streaming": True, "pushNotifications": False},
    "authentication": {"schemes": ["Bearer"]},
    "skills": [
        {
            "id": "analyze-text",
            "name": "Text Analysis",
            "description": "Analyzes input text and returns summaries, insights, or structured JSON",
            "inputModes": ["text"],
            "outputModes": ["text", "data"]
        }
    ]
}
 
# =====================
# Endpoints
# =====================
 
@app.get("/.well-known/agent.json")
async def get_agent_card():
    """Expose the agent card (required A2A endpoint)"""
    return AGENT_CARD
 
class TaskRequest(BaseModel):
    id: str
    message: dict
    sessionId: Optional[str] = None
 
@app.post("/tasks/send")
async def send_task(req: TaskRequest, background_tasks: BackgroundTasks):
    """Accept a task asynchronously and begin processing"""
    task_id = req.id
    tasks[task_id] = {
        "id": task_id,
        "status": {"state": "submitted", "timestamp": datetime.utcnow().isoformat()},
        "artifacts": [],
        "history": [req.message]
    }
    background_tasks.add_task(process_with_gemini, task_id, req.message)
    return tasks[task_id]
 
@app.get("/tasks/get")
async def get_task(id: str):
    """Return the current state of a task"""
    if id not in tasks:
        raise HTTPException(status_code=404, detail="Task not found")
    return tasks[id]
 
async def process_with_gemini(task_id: str, message: dict):
    """Internal function: call Gemini API and store the result"""
    try:
        tasks[task_id]["status"]["state"] = "working"
 
        user_text = " ".join(
            part.get("text", "")
            for part in message.get("parts", [])
            if part.get("type") == "text"
        )
 
        # Run blocking Gemini call in a thread pool
        response = await asyncio.to_thread(model.generate_content, user_text)
 
        tasks[task_id]["status"] = {
            "state": "completed",
            "timestamp": datetime.utcnow().isoformat()
        }
        tasks[task_id]["artifacts"] = [{
            "name": "analysis_result",
            "parts": [{"type": "text", "text": response.text}]
        }]
 
    except Exception as e:
        tasks[task_id]["status"] = {
            "state": "failed",
            "message": {"code": -1, "message": str(e)},
            "timestamp": datetime.utcnow().isoformat()
        }

Verify it works:

# Start the server
uvicorn a2a_server:app --reload
 
# Fetch the agent card
curl http://localhost:8000/.well-known/agent.json
 
# Submit a task
curl -X POST http://localhost:8000/tasks/send \
  -H "Content-Type: application/json" \
  -d '{"id":"task-001","message":{"role":"user","parts":[{"type":"text","text":"Explain AI agents in 3 sentences."}]}}'
 
# Retrieve the result
curl "http://localhost:8000/tasks/get?id=task-001"
# → {"status":{"state":"completed"},"artifacts":[{"parts":[{"type":"text","text":"..."}]}]}

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Build the full A2A skeleton in working FastAPI code — agent cards, task lifecycle, and artifacts
✦Compare pipeline, fan-out, and dynamic routing on the same task with measured latency and token costs, and learn when each one wins
✦Get the operational details the spec leaves out — agent card cache drift, task retry idempotency, and how A2A fits alongside Managed Agents
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

⬡ Advanced2026-04-23
Defending Gemini API Apps from Prompt Injection: A Multi-Layer Production Architecture
A four-layer prompt injection defense for Gemini apps: sanitized input, hardened prompts, structured output, and a moderator LLM — with runnable Python.
⬡ Advanced2026-07-16
What language should your system instruction be in? Measuring three approaches when most prompts arrive in the user's language
Keep the system instruction in English, or translate it into the user's language? I measured input tokens per language with countTokens, then lined up output-language match and schema compliance to find where nine tokens is enough.
⬡ Advanced2026-05-06
Gemini 2.5 Pro + Imagen 4 Content Automation Pipeline: Complete Build Guide
Build a production-ready pipeline combining Gemini 2.5 Pro and Imagen 4 API to auto-generate blog articles, SNS posts, and thumbnails. Covers async processing, quality filters, and monetization design.