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

@wyrd-company/a2a-nats

v0.1.0

Published

Agent2Agent (A2A) custom protocol binding for NATS.

Readme

a2a-nats

Agent2Agent (A2A) custom protocol binding for NATS.io.

This repository is structured for multiple A2A language SDK bindings. The shared NATS wire contract lives in protocol/; SDK-specific implementations live under sdks/<language>/.

Packages

The initial package is the TypeScript binding:

  • package: @wyrd-company/a2a-nats
  • A2A SDK: @a2a-js/sdk
  • NATS client: @nats-io/transport-node
  • core transport protocol name: NATS
  • durable JetStream transport protocol name: NATS+JS

Layout

protocol/
  src/                 Shared subject naming and NATS frame contracts.
sdks/
  typescript/src/      A2A JS client transport factory and server listener.
test/                  TypeScript binding tests with an in-memory NATS broker.

Future SDKs should reuse the protocol frame shapes and subject conventions rather than inventing language-specific wire formats.

Wire Contract

Unary calls publish an a2a-nats/1 request frame to an agent subject and receive one JSON-RPC response on the NATS reply subject.

Streaming calls publish the same request frame with a generated reply inbox. The server publishes stream frames to that inbox:

  • response: contains one A2A JSON-RPC response event.
  • complete: marks normal stream completion.
  • transport-error: reports a transport-level stream failure.

Agent subjects can be generated with a2aNatsAgentSubject():

import { a2aNatsAgentSubject } from '@wyrd-company/a2a-nats';

const subject = a2aNatsAgentSubject({ namespace: 'a2a', agentId: 'agent-a' });
// a2a.agent.agent-a.rpc

Agent cards should advertise NATS with preferredTransport or additionalInterfaces:

const agentCard = {
  // ...
  url: 'nats://a2a.agent.agent-a.rpc',
  preferredTransport: 'NATS',
};

AgentCard Registry

For NATS-native discovery, publish AgentCards to a dedicated JetStream KV bucket. The bucket is intentionally not part of the key; operators choose the bucket as the registry boundary. Keys use this shape:

<namespace>.agents.<agentId>

Use namespace as the collision boundary for an A2A server group, deployment, tenant, environment, or other scope where agentId values are unique. A single bucket can therefore hold cards for multiple A2A server groups without key collisions.

import { JetStreamKvAgentCardRegistry } from '@wyrd-company/a2a-nats';

const registry = new JetStreamKvAgentCardRegistry({
  connection: nc,
  bucket: 'A2A_AGENT_CARDS',
  namespace: 'server-a',
});

await registry.publish({ agentId: 'agent-a', card: agentCard });

const entry = await registry.resolve('agent-a');
const cardsInNamespace = await registry.list();

This registry requires JetStream. The core NATS transport only requires core NATS request/reply.

Durable JetStream Transport

The core NATS transport uses request/reply and is intentionally ephemeral. For durable enterprise message traffic, use the NATS+JS transport. It persists A2A requests and responses through JetStream streams:

  • request stream: stores frames on subjects such as <namespace>.agent.<agentId>.requests
  • response stream: stores frames on subjects such as <namespace>.client.<clientId>.responses
  • server durable consumer: pulls requests from the request stream
  • client request consumers: pull matching persisted response frames
import {
  JetStreamA2AClientTransport,
  JetStreamA2AServer,
  a2aJetStreamRequestSubject,
} from '@wyrd-company/a2a-nats';

const namespace = 'server-a';
const requestSubject = a2aJetStreamRequestSubject({
  namespace,
  agentId: 'agent-a',
});

const server = new JetStreamA2AServer({
  connection: nc,
  requestSubject,
  requestStream: 'A2A_REQUESTS',
  responseStream: 'A2A_RESPONSES',
  responseSubjects: [`${namespace}.client.*.responses`],
  requestHandler,
});

const client = new JetStreamA2AClientTransport({
  connection: nc,
  namespace,
  clientId: 'client-a',
  requestSubject,
  requestStream: 'A2A_REQUESTS',
  responseStream: 'A2A_RESPONSES',
});

await server.ready();
await client.ready();

Agent cards can advertise this as a separate interface:

const agentCard = {
  // ...
  additionalInterfaces: [
    {
      transport: 'NATS+JS',
      url: 'nats+js://server-a/agent/agent-a/requests',
    },
  ],
};

JetStream stream creation is automatic by default. Set createStreams: false when streams are provisioned by operations.

TypeScript Client

import { ClientFactory, ClientFactoryOptions } from '@a2a-js/sdk/client';
import { connect } from '@nats-io/transport-node';
import { NatsTransportFactory } from '@wyrd-company/a2a-nats';

const nc = await connect({ servers: 'nats://localhost:4222' });

const factory = new ClientFactory(
  ClientFactoryOptions.createFrom(ClientFactoryOptions.default, {
    transports: [new NatsTransportFactory({ connection: nc })],
    preferredTransports: ['NATS'],
  })
);

const client = await factory.createFromAgentCard(agentCard);
const response = await client.sendMessage({
  message: {
    kind: 'message',
    role: 'user',
    messageId: crypto.randomUUID(),
    parts: [{ kind: 'text', text: 'hello' }],
  },
});

TypeScript Server

import { DefaultRequestHandler, InMemoryTaskStore } from '@a2a-js/sdk/server';
import { connect } from '@nats-io/transport-node';
import { NatsA2AServer, a2aNatsAgentSubject } from '@wyrd-company/a2a-nats';

const nc = await connect({ servers: 'nats://localhost:4222' });
const subject = a2aNatsAgentSubject({ agentId: 'agent-a' });

const requestHandler = new DefaultRequestHandler(
  agentCard,
  new InMemoryTaskStore(),
  agentExecutor
);

const server = new NatsA2AServer({
  connection: nc,
  subject,
  requestHandler,
});

await server.ready();

Development

npm install
npm run verify

npm run verify runs typecheck, tests, and build.

Release

CI runs on pushes and pull requests to main. The default verification job runs the Node matrix. A separate integration job starts nats:2-alpine with JetStream enabled and runs the NATS_URL-gated real NATS test once on Node 22.

Publishing runs on SemVer git tags without a v prefix:

  • 1.2.3
  • 1.2.3-alpha.1

The publish workflow verifies that the tag exactly matches package.json version, then publishes to npmjs.org and GitHub Package Registry. npmjs.org publishing requires NPM_TOKEN; GitHub Packages uses GITHUB_TOKEN.