Skip to main content
This example shows two agents communicating via Google’s A2A protocol. The server wraps a Vibes agent with A2AAdapter, exposing it as a JSON-RPC HTTP server. The client uses plain fetch() to send a task - showing the wire format every A2A client must produce.

What you’ll learn

  • Wrapping a Vibes agent with A2AAdapter
  • Exposing an agent as an A2A-compatible HTTP server with adapter.handler()
  • Calling an A2A server using the message/send JSON-RPC method
  • The A2A wire format (JSON-RPC 2.0 message structure)

Prerequisites

  • Vibes installed (npm:@vibesjs/sdk)
  • ANTHROPIC_API_KEY environment variable set (for the server)

Complete example

import { A2AAdapter, Agent } from "npm:@vibesjs/sdk";
import { anthropic } from "npm:@ai-sdk/anthropic";

// The agent being exposed
const researchAgent = new Agent({
  model: anthropic("claude-haiku-4-5-20251001"),
  systemPrompt: "You are a research assistant. Answer factual questions concisely and accurately.",
});

// Wrap with A2AAdapter
const adapter = new A2AAdapter(researchAgent, {
  name: "Research Agent",
  description: "Answers factual research questions",
  url: "http://localhost:8000",
  version: "1.0.0",
});

// Start the HTTP server
Deno.serve({ port: 8000 }, adapter.handler());
console.log("A2A server running on http://localhost:8000");
console.log("Agent card available at: http://localhost:8000/.well-known/agent.json");

Run it

# Terminal 1: start the server
ANTHROPIC_API_KEY=your-key deno run --allow-net --allow-env server.ts

# Terminal 2: run the client (after server is ready)
deno run --allow-net --allow-env client.ts

How it works

A2AAdapter

Wraps a Vibes agent and handles all A2A protocol details - routing, task lifecycle, JSON-RPC marshaling. The options object becomes the AgentCard served at GET /.well-known/agent.json for agent discovery.

adapter.handler()

Returns a Deno-compatible (req: Request) => Promise<Response> function. Pass directly to Deno.serve().

JSON-RPC wire format

A2A uses JSON-RPC 2.0. method: "message/send" is synchronous - the response body contains the complete A2ATask result. Use method: "message/stream" for SSE streaming.

Response shape

The result is an A2ATask object. Text responses are in result.artifacts[0].parts[0].text. The task state will be "completed" for successful runs.
The client uses plain fetch() intentionally - this is the A2A wire protocol that any A2A-compatible client must produce. In production, you would typically use an A2A client SDK or another Vibes agent as the caller.

Next steps