Quickstart: Build Your First A2A Server Agent
Get a working A2A server agent running in under 5 minutes using Python and the official SDK. By the end of this guide, your agent will be discoverable, invokable, and ready to register with Foldspace.
Prerequisites
- Python 3.10+
- A basic understanding of A2A concepts
Step 1: Install the SDK
pip install a2a-sdk uvicornStep 2: Implement Your Agent
Create a file called agent.py:
import uvicorn
from a2a.server.apps.jsonrpc import A2AFastAPIApplication
from a2a.server.request_handlers import DefaultRequestHandler
from a2a.server.agent_execution import AgentExecutor, RequestContext
from a2a.server.events import EventQueue
from a2a.server.tasks import InMemoryTaskStore, TaskUpdater
from a2a.types import (
AgentCard,
AgentCapabilities,
AgentSkill,
Part,
TextPart,
)
class TravelBookingExecutor(AgentExecutor):
"""Handles flight and hotel search requests."""
async def execute(self, context: RequestContext, event_queue: EventQueue) -> None:
updater = TaskUpdater(event_queue, context.task_id, context.context_id)
await updater.start_work()
user_input = context.get_user_input()
result = await self._search_travel_options(user_input)
await updater.add_artifact(parts=[Part(root=TextPart(text=result))])
await updater.complete()
async def cancel(self, context: RequestContext, event_queue: EventQueue) -> None:
updater = TaskUpdater(event_queue, context.task_id, context.context_id)
await updater.cancel()
async def _search_travel_options(self, query: str) -> str:
# Replace with your actual logic — call an LLM, query APIs, etc.
return f"Found 3 flight options and 5 hotels matching: {query}"
# --- Agent Card: describes what your agent can do ---
agent_card = AgentCard(
name="Travel Booking Agent",
description="Searches flights, hotels, and packages based on travel preferences",
url="http://localhost:8080/",
version="1.0.0",
capabilities=AgentCapabilities(streaming=True),
default_input_modes=["text/plain"],
default_output_modes=["text/plain", "application/json"],
skills=[
AgentSkill(
id="search-flights",
name="Search Flights",
description="Find available flights between destinations",
tags=["travel", "flights", "booking"],
examples=["Find flights from NYC to London next Friday"],
),
AgentSkill(
id="search-hotels",
name="Search Hotels",
description="Find hotels at a destination with filters",
tags=["travel", "hotels", "accommodation"],
examples=["Find 4-star hotels in Paris for 3 nights"],
),
],
)
# --- Wire up and start the server ---
request_handler = DefaultRequestHandler(
agent_executor=TravelBookingExecutor(),
task_store=InMemoryTaskStore(),
)
app = A2AFastAPIApplication(
agent_card=agent_card,
http_handler=request_handler,
).build()
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8080)Step 3: Run It
python agent.pyYour agent is now serving at http://localhost:8080.
Step 4: Test It
Fetch the Agent Card:
curl http://localhost:8080/.well-known/agent.json | jq .Send a message:
curl -X POST http://localhost:8080/ \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "test-001",
"method": "message/send",
"params": {
"message": {
"role": "user",
"parts": [{"kind": "text", "text": "Find flights from SF to Tokyo next week"}],
"messageId": "msg-001"
}
}
}'You should get a JSON-RPC response with a completed task and an artifact containing your agent's result.
Validate with the A2A Inspector:
npx @a2a-js/inspector http://localhost:8080How It Works
The three components of an A2A server:
- AgentExecutor — Your business logic. Receives a
RequestContext(the user's message) and publishes results to anEventQueue. - DefaultRequestHandler — Protocol plumbing. Routes incoming JSON-RPC calls to your executor, manages task lifecycle and storage.
- A2AFastAPIApplication — HTTP layer. Builds a FastAPI/Starlette app with the correct endpoints (
/.well-known/agent.json, JSON-RPC POST).
Artifact vs. status: The text you send via
add_artifact(...)is what the Foldspace Copilot shows as the answer. Status updates (update_status(state="working", ...)) are treated as progress only — don't put your final answer there. See How Foldspace renders your response for details.
Request flow:
- A client sends a JSON-RPC request to A2AFastAPIApplication (the HTTP layer).
- It routes the call to DefaultRequestHandler, which manages the task lifecycle.
- The handler invokes YourExecutor with the user's message.
- Your executor uses TaskUpdater to publish status updates and artifacts to the EventQueue.
- Those events are returned to the client as an SSE stream (streaming) or a single JSON-RPC response (non-streaming).
Troubleshooting
-
Problem: Agent Card not found at
/.well-known/agent.json.
What to do: Ensure you're hitting the correct port and the server started without errors. -
Problem: Tasks stay in
workingstate forever.
What to do: Ensure your executor always callscomplete(),fail(), orcancel()— including in error paths. -
Problem: Authentication fails when Foldspace invokes your agent.
What to do: Confirm your Agent Card'sauthentication.schemesmatches what your server validates.
Updated about 1 month ago
What’s Next
LangGraph integration, streaming, multi-turn, native implementations, TypeScript and Java