A2A Registry TypeScript Client
Typed client and managed lease helper for a2a-registry-server 0.2 and later.
It discovers logical agents with multiple independently leased runtime instances,
using the standard Fetch API and the official @a2a-js/sdk Agent Card type.
Install
npm install @a2a-lib/registry-client-ts
Node.js 22 or newer is required.
Server information
Use getServerInfo() to inspect the connected server without making a
registry mutation. It returns the server version, API version, readiness
status, backing store, documentation URL, and advertised endpoint paths.
const info = await registry.getServerInfo();
console.log(info.version, info.apiVersion, info.status, info.store);
Discover agents
import { RegistryClient } from "@a2a-lib/registry-client-ts";
const registry = new RegistryClient("http://localhost:3003");
const page = await registry.listAgents({
skill: "weather",
capability: "streaming",
limit: 25,
});
for (const agent of page.agents) {
console.log(agent.id, agent.instanceCount);
for (const instance of agent.instances) {
console.log(instance.instanceId, instance.endpoint, instance.metadata);
}
}
For the common single-match case, use findAgentBySkill("weather"). The
top-level agent.endpoint and lease fields remain compatibility projections;
new code should select an active entry from agent.instances.
Maintain an agent registration
maintainA2ARegistryRegistration is based on the helper previously kept in
website/agents/shared/a2a-registry.ts. It registers immediately, renews the
lease every one-third of its TTL, re-registers after expiry, and unregisters on
shutdown.
import type { AgentCard } from "@a2a-js/sdk";
import { maintainA2ARegistryRegistration } from "@a2a-lib/registry-client-ts";
const card: AgentCard = createAgentCard();
const lease = maintainA2ARegistryRegistration({
id: "weather-agent",
instanceId: "eu-west-1a",
endpoint: "http://localhost:3002/v1/tasks",
agentCard: card,
ttlSeconds: 60,
metadata: { role: "weather" },
logPrefix: "[Weather Agent]",
});
await lease.ready;
process.once("SIGTERM", () => {
void lease.stop().finally(() => process.exit(0));
});
The helper reads A2A_REGISTRY_URL (or REGISTRY_URL) and
A2A_REGISTRY_WRITE_TOKEN (or REGISTRY_WRITE_TOKEN) when the corresponding
options are omitted. Pass an existing leaseToken when reclaiming a live
instance after a process restart. Omit instanceId to use the server's
backward-compatible default instance.
Multiple instances
Every instance under one logical agent ID must publish exactly the same Agent Card. Each instance has its own endpoint, metadata, TTL, lease token, heartbeat, and expiry:
const first = await registry.registerAgentInstance("weather-agent", {
instanceId: "eu-west-1a",
endpoint: "https://weather-a.example/a2a",
agentCard: card,
ttlSeconds: 60,
metadata: { zone: "eu-west-1a" },
});
const second = await registry.registerAgentInstance("weather-agent", {
instanceId: "eu-west-1b",
endpoint: "https://weather-b.example/a2a",
agentCard: card,
ttlSeconds: 60,
metadata: { zone: "eu-west-1b" },
});
const { instances } = await registry.listAgentInstances("weather-agent");
const instance = await registry.getAgentInstance("weather-agent", "eu-west-1b");
await registry.heartbeatInstance("weather-agent", "eu-west-1b", {
leaseToken: second.leaseToken,
});
await registry.unregisterAgentInstance("weather-agent", "eu-west-1a", {
leaseToken: first.leaseToken,
});
Use putAgentInstance(id, instanceId, input, options) to update an existing
instance using its lease token. An Agent Card that differs from active sibling
instances is rejected by the server with 409 agent_card_mismatch.
Direct lease operations
const registry = new RegistryClient({
baseUrl: "http://localhost:3003",
writeToken: process.env.A2A_REGISTRY_WRITE_TOKEN,
});
const registration = await registry.registerAgent({
id: "weather-agent",
endpoint: "http://localhost:3002/v1/tasks",
agentCard: card,
ttlSeconds: 60,
});
await registry.heartbeat("weather-agent", {
leaseToken: registration.leaseToken,
});
await registry.unregisterAgent("weather-agent", {
leaseToken: registration.leaseToken,
});
These methods operate on the compatibility default instance. Named instances
use registerAgentInstance, putAgentInstance, heartbeatInstance, and
unregisterAgentInstance.