npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@drew-foxall/a2a-js-sdk

v0.4.2

Published

Server & Client SDK for Agent2Agent protocol with Express, Hono, and Edge Runtime support

Readme

A2A JavaScript SDK with Edge Support

npm version License Upstream

Fork of a2aproject/a2a-js — Tracks upstream v0.3.6 with added multi-framework and edge runtime support.

✨ Features

  • 🎯 Multi-Framework: Express, Hono, Elysia, itty-router, Fresh, and Web Standard
  • ⚡ Edge Runtime Native: Cloudflare Workers, Deno, Bun — no compatibility layers needed
  • 🌐 Universal JavaScript: Built on web-standard APIs (EventTarget, Request/Response)
  • 🚀 SSE Streaming: Full Server-Sent Events support across all frameworks
  • 🔌 Pluggable Logger: Console, JSON, or custom logging implementations
  • 📦 Modular Architecture: Import only what you need from server/core
  • 🔄 Full A2A Protocol: Complete implementation of the Agent2Agent specification

Installation

npm install @drew-foxall/a2a-js-sdk
# or
pnpm add @drew-foxall/a2a-js-sdk
# or
yarn add @drew-foxall/a2a-js-sdk

Peer Dependencies

Install the framework you want to use:

# For Express (Node.js)
npm install express

# For Hono (Edge/Serverless)
npm install hono

# For Hono on Node.js (development)
npm install hono @hono/node-server

Quick Start

The examples below show the same "Hello Agent" implemented for different environments.

Shared Agent Logic

First, define your agent card and executor (shared across all implementations):

// shared/agent.ts
import { v4 as uuidv4 } from 'uuid';
import type { AgentCard, Message } from '@drew-foxall/a2a-js-sdk';
import {
  AgentExecutor,
  RequestContext,
  ExecutionEventBus,
} from '@drew-foxall/a2a-js-sdk/server';

export const helloAgentCard: AgentCard = {
  name: 'Hello Agent',
  description: 'A simple agent that says hello.',
  protocolVersion: '0.3.0',
  version: '0.1.0',
  url: 'http://localhost:4000/',
  skills: [{ id: 'chat', name: 'Chat', description: 'Say hello', tags: ['chat'] }],
  capabilities: { pushNotifications: false },
  defaultInputModes: ['text'],
  defaultOutputModes: ['text'],
};

export class HelloExecutor implements AgentExecutor {
  async execute(ctx: RequestContext, eventBus: ExecutionEventBus): Promise<void> {
    const response: Message = {
      kind: 'message',
      messageId: uuidv4(),
      role: 'agent',
      parts: [{ kind: 'text', text: 'Hello, world!' }],
      contextId: ctx.contextId,
    };
    eventBus.publish(response);
    eventBus.finished();
  }
  
  cancelTask = async (): Promise<void> => {};
}

Express Server (Node.js - Original)

The original Express implementation from upstream. Best for traditional Node.js servers.

// server-express.ts
import express from 'express';
import {
  DefaultRequestHandler,
  InMemoryTaskStore,
} from '@drew-foxall/a2a-js-sdk/server';
import { A2AExpressApp } from '@drew-foxall/a2a-js-sdk/server/express';
import { helloAgentCard, HelloExecutor } from './shared/agent';

const requestHandler = new DefaultRequestHandler(
  helloAgentCard,
  new InMemoryTaskStore(),
  new HelloExecutor()
);

const app = express();
const a2aApp = new A2AExpressApp(requestHandler);

// Setup routes with optional base path and middleware
a2aApp.setupRoutes(app, '/a2a', [/* middlewares */]);

app.listen(4000, () => {
  console.log('🚀 Express A2A server running on http://localhost:4000');
});

Options:

// With custom user extractor for authentication
const a2aApp = new A2AExpressApp(requestHandler, async (req) => {
  // Extract user from request (e.g., from JWT token)
  return req.user ?? new UnauthenticatedUser();
});

// Setup with REST API enabled (in addition to JSON-RPC)
a2aApp.setupRoutes(app, '/a2a', [], '.well-known/agent-card.json');

Hono Server (Edge/Serverless)

Best for Cloudflare Workers, Vercel Edge Functions, Deno Deploy, and other edge environments.

// worker.ts - Cloudflare Workers / Edge Runtime
import { Hono } from 'hono';
import {
  DefaultRequestHandler,
  InMemoryTaskStore,
} from '@drew-foxall/a2a-js-sdk/server';
import { A2AHonoApp } from '@drew-foxall/a2a-js-sdk/server/hono';
import { helloAgentCard, HelloExecutor } from './shared/agent';

const requestHandler = new DefaultRequestHandler(
  helloAgentCard,
  new InMemoryTaskStore(),
  new HelloExecutor()
);

const app = new Hono();
const a2aApp = new A2AHonoApp(requestHandler, {
  enableRest: true,           // Enable REST API endpoints
  logger: ConsoleLogger.create(),
});
a2aApp.setupRoutes(app);

export default app;

With Authentication:

import { A2AHonoApp, UserBuilder } from '@drew-foxall/a2a-js-sdk/server/hono';

const userBuilder: UserBuilder = async (request) => {
  const token = request.headers.get('Authorization')?.replace('Bearer ', '');
  if (token) {
    const user = await validateToken(token);
    return user;
  }
  return new UnauthenticatedUser();
};

const a2aApp = new A2AHonoApp(requestHandler, { userBuilder });

Deploy to Cloudflare Workers:

# wrangler.toml - No nodejs_compat needed!
name = "a2a-hello-agent"
main = "worker.ts"
compatibility_date = "2024-01-01"
wrangler deploy

Elysia Server (Bun)

Best for Bun-native applications with excellent TypeScript support.

// server-elysia.ts
import { Elysia } from 'elysia';
import { DefaultRequestHandler, InMemoryTaskStore } from '@drew-foxall/a2a-js-sdk/server';
import { A2AElysiaApp } from '@drew-foxall/a2a-js-sdk/server/elysia';
import { helloAgentCard, HelloExecutor } from './shared/agent';

const requestHandler = new DefaultRequestHandler(
  helloAgentCard,
  new InMemoryTaskStore(),
  new HelloExecutor()
);

const a2aApp = new A2AElysiaApp(requestHandler, { enableRest: true });
const routes = a2aApp.getRoutes('/a2a');

const app = new Elysia();
routes.forEach(route => {
  app[route.method](route.path, route.handler);
});

app.listen(4000);

itty-router (Cloudflare Workers - Lightweight)

Best for minimal Cloudflare Workers with the smallest bundle size.

// worker.ts
import { Router } from 'itty-router';
import { DefaultRequestHandler, InMemoryTaskStore } from '@drew-foxall/a2a-js-sdk/server';
import { A2AIttyRouterApp } from '@drew-foxall/a2a-js-sdk/server/itty-router';
import { helloAgentCard, HelloExecutor } from './shared/agent';

const requestHandler = new DefaultRequestHandler(
  helloAgentCard,
  new InMemoryTaskStore(),
  new HelloExecutor()
);

const a2aApp = new A2AIttyRouterApp(requestHandler, { enableRest: true });
const routes = a2aApp.getRoutes('/a2a');

const router = Router();
routes.forEach(route => {
  router[route.method.toLowerCase()](route.pattern, route.handler);
});

export default { fetch: router.handle };

Fresh (Deno)

Best for Deno's web framework with file-based routing.

// routes/a2a/[...path].ts
import { DefaultRequestHandler, InMemoryTaskStore } from '@drew-foxall/a2a-js-sdk/server';
import { A2AFreshApp } from '@drew-foxall/a2a-js-sdk/server/fresh';
import { helloAgentCard, HelloExecutor } from '../../shared/agent.ts';

const requestHandler = new DefaultRequestHandler(
  helloAgentCard,
  new InMemoryTaskStore(),
  new HelloExecutor()
);

const a2aApp = new A2AFreshApp(requestHandler, { enableRest: true });

export const handler = a2aApp.createHandlers('/a2a');

Client

The client works with any A2A server implementation:

import { A2AClient } from '@drew-foxall/a2a-js-sdk/client';
import { v4 as uuidv4 } from 'uuid';

const client = await A2AClient.fromCardUrl('http://localhost:4000/.well-known/agent-card.json');

const response = await client.sendMessage({
  message: {
    messageId: uuidv4(),
    role: 'user',
    parts: [{ kind: 'text', text: 'Hi there!' }],
    kind: 'message',
  },
});

console.log('Response:', response);

🏗️ Architecture

This SDK uses a layered architecture separating framework-agnostic logic from framework-specific implementations:

┌─────────────────────────────────────────────────────────────────┐
│                       Transport Layer                           │
│   ┌────────────────────────┐    ┌──────────────────────┐        │
│   │ JsonRpcTransportHandler│    │ RestTransportHandler │        │
│   └──────────┬─────────────┘    └──────────┬───────────┘        │
│              └───────────────┬─────────────┘                    │
│                              ▼                                  │
│             ┌────────────────────────────────┐                  │
│             │      A2ARequestHandler         │                  │
│             │   (Framework-Agnostic Logic)   │                  │
│             └────────────────────────────────┘                  │
└─────────────────────────────────────────────────────────────────┘
                               │
            ┌──────────────────┼──────────────────┐
            ▼                  ▼                  ▼
    ┌───────────────┐  ┌───────────────┐  ┌───────────────┐
    │  server/core  │  │ server/hono   │  │server/express │
    │(Web Standard) │  │ server/elysia │  │  (Original)   │
    │               │  │    etc...     │  │               │
    └───────────────┘  └───────────────┘  └───────────────┘

Import Paths

// Core utilities (logging, routes, streaming)
import { 
  ConsoleLogger, JsonLogger, NoopLogger,
  HTTP_STATUS, REST_ROUTES, AGENT_CARD_ROUTE,
  processStream, createSSEEvent,
} from '@drew-foxall/a2a-js-sdk/server/core';

// Framework implementations
import { A2AExpressApp } from '@drew-foxall/a2a-js-sdk/server/express';           // Original Express
import { A2AExpressApp } from '@drew-foxall/a2a-js-sdk/server/express-adapter';   // Core-based Express
import { A2AHonoApp } from '@drew-foxall/a2a-js-sdk/server/hono';
import { A2AElysiaApp } from '@drew-foxall/a2a-js-sdk/server/elysia';
import { A2AIttyRouterApp } from '@drew-foxall/a2a-js-sdk/server/itty-router';
import { A2AFreshApp } from '@drew-foxall/a2a-js-sdk/server/fresh';
import { A2AWebStandardApp } from '@drew-foxall/a2a-js-sdk/server/web-standard';

Available Frameworks

| Framework | Import Path | Best For | |-----------|-------------|----------| | Express (Original) | server/express | Node.js servers (reference implementation) | | Express (Core-based) | server/express-adapter | Parity testing with edge implementations | | Hono | server/hono | Cloudflare Workers, Deno, Bun | | Elysia | server/elysia | Bun-native with excellent TypeScript | | itty-router | server/itty-router | Lightweight Cloudflare Workers | | Fresh | server/fresh | Deno's web framework | | Web Standard | server/web-standard | Any runtime with Request/Response |


⚡ Edge Runtime Support

This SDK uses web-standard APIs, making it compatible with all modern JavaScript runtimes:

| Runtime | Status | Notes | |---------|--------|-------| | Cloudflare Workers | ✅ Native | No nodejs_compat needed | | Vercel Edge Functions | ✅ Native | Full support | | Deno Deploy | ✅ Native | No npm shims required | | Bun | ✅ Native | Full web API support | | Node.js 15+ | ✅ Native | EventTarget built-in | | Browsers | ✅ Native | Universal JavaScript |

Why Edge?

| Traditional (Express) | Edge (Hono) | |-----------------------|-------------| | Runs on dedicated servers | Runs at the edge, close to users | | Cold starts in seconds | Cold starts in milliseconds | | Requires nodejs_compat on CF Workers | Native edge runtime support | | Full Node.js API access | Web-standard APIs only | | Best for complex backends | Best for low-latency agents |


📚 Core Features

Streaming (SSE)

// Server: Publish events
eventBus.publish({ kind: 'status-update', taskId, status: { state: 'working' }, final: false });
eventBus.publish({ kind: 'artifact-update', taskId, artifact: { ... } });
eventBus.publish({ kind: 'status-update', taskId, status: { state: 'completed' }, final: true });
eventBus.finished();

// Client: Consume stream
const stream = client.sendMessageStream(params);
for await (const event of stream) {
  console.log(event.kind, event);
}

Middleware Support

All framework implementations support middleware:

// Express
a2aApp.setupRoutes(app, '/a2a', [authMiddleware, loggingMiddleware]);

// Hono
a2aApp.setupRoutes(app, '/a2a', [authMiddleware, loggingMiddleware]);

Push Notifications

For long-running tasks, configure push notifications:

const sendParams = {
  message: { ... },
  configuration: {
    pushNotificationConfig: {
      url: 'https://my-app.com/webhook',
      token: 'auth-token',
    },
  },
};

Custom Logging

import { ConsoleLogger, JsonLogger, NoopLogger } from '@drew-foxall/a2a-js-sdk/server/core';

// Human-readable for development
const devLogger = ConsoleLogger.create('debug');

// Structured JSON for production
const prodLogger = JsonLogger.create();

// Silent for testing
const testLogger = NoopLogger.create();

🔄 Upstream Tracking

This fork tracks the official a2aproject/a2a-js repository:

| This Fork | Upstream | |-----------|----------| | v0.4.0 | v0.3.6 |

Staying in Sync

git remote add upstream https://github.com/a2aproject/a2a-js.git
git fetch upstream
git merge upstream/main

🔗 Related

License

Apache 2.0

Contributing

Contributions are welcome! Please open an issue or pull request.

  • Edge/Framework improvements: Submit PRs to this repository
  • A2A Protocol issues: Report to the official repository