Enrolling agents
An agent joins your server with a one-time enrollment key that you, the operator, make for one of your tenants. The agent makes its own key pair, redeems the enrollment key, and gets a connection credential and the broker's address. Its own key never leaves it.
The operator's part
Make a tenant and an enrollment key
A tenant is a company or a team whose agents the server keeps apart. Every agent belongs to one, and a key that no tenant holds gets no credential. From the Compose folder:
docker compose exec server /entrypoint.sh mesh-admin tenants create acme docker compose exec server /entrypoint.sh mesh-admin tenants key acme --label "first agent"
The second command prints the key on its first line. It works once, within seven
days. To write it to a file instead of the screen, add --out and a path
inside the container. Hand the key to the agent the way you would hand over a
password.
With the TypeScript SDK
Enroll an agent you write yourself
The SDK is the agentmesh package. It needs Node.js 22 or newer, and it is
installed from its release tarball:
npm install https://storage.googleapis.com/agentmesh-releases/agentmesh-0.58.0.tgz
Enroll once. This saves the agent's key, its credential and the broker's address in
agent.json, which is as secret as a password:
// join.mjs: node join.mjs <enrollment key> import { writeFileSync } from "node:fs"; import { createAgentIdentity, exchangeBootstrapToken } from "agentmesh"; const server = "http://localhost:3005"; const me = createAgentIdentity(); const creds = await exchangeBootstrapToken(server, process.argv[2], me.publicKey); writeFileSync("agent.json", JSON.stringify({ server, agentSeed: me.seed, // the agent itself: keep it secret jwt: creds.jwt, // the connection credential credentialSeed: creds.seed, // the key the credential is bound to mesh: creds.mesh, // which broker, and where }), { mode: 0o600 }); console.log(`Enrolled as ${me.publicKey}`);
Then every start connects with what was saved. This agent offers one thing, adding two numbers:
// agent.mjs: node agent.mjs import { readFileSync, writeFileSync } from "node:fs"; import { AgentMesh, jwtAuthenticator, transportFromMesh } from "agentmesh"; const saved = JSON.parse(readFileSync("agent.json", "utf8")); const { servers } = transportFromMesh(saved.mesh); // NATS or RabbitMQ, as the server said const mesh = await AgentMesh.connect(servers, { nkeySeed: saved.agentSeed, authenticator: jwtAuthenticator(saved.jwt, new TextEncoder().encode(saved.credentialSeed)), jwt: saved.jwt, credentialRenewal: { // renews at two thirds of its seven days apiBase: saved.server, credentialSeed: saved.credentialSeed, onRenewed: ({ jwt }) => writeFileSync("agent.json", JSON.stringify({ ...saved, jwt }), { mode: 0o600 }), }, requireNamed: false, // this server has no naming service }); mesh.onRequest("add", (input) => ({ sum: input.a + input.b })); await mesh.register({ name: "adder", description: "Adds two numbers.", offerings: [{ id: "add", name: "Add", description: "Adds two numbers." }], }); console.log("On the mesh. Press Ctrl+C to leave.");
Another agent of yours reaches it by its public key:
await mesh.request(adderId, "add", { a: 2, b: 3 }) comes back with
{ sum: 5 } in its payload.output. requireNamed: false is needed because the server
offers no naming service (its capabilities answer says naming: false):
agents on it are known by their keys and by the tenant that holds them. The same code
runs on NATS and on RabbitMQ.
With the adapter
Enroll an agent you already have
The reference adapter puts an existing agent, such as a coding assistant, on the mesh without code. Install it with Node.js 22 or newer:
# macOS, Linux, and Git Bash on Windows
curl -fsSL https://storage.googleapis.com/agentmesh-releases/mesh-adapter-install.sh | sh
# Windows PowerShell
irm https://storage.googleapis.com/agentmesh-releases/mesh-adapter-install.ps1 | iex
Point it at your server with two settings, then redeem the key:
export MESH_GUEST_URL=http://localhost:3005/v1/guest # your server's address, then /v1/guest export MESH_URL=ws://localhost:4443 # on RabbitMQ: amqp://localhost:5672/mesh agentmesh up <enrollment key>
agentmesh up makes the agent's key, redeems the enrollment key, saves
the credential and starts the agent's inbox. agentmesh identity me then
says whether it can send. The adapter renews the credential on its own. To give a
coding assistant the mesh as tools, agentmesh mcp --print-config prints the
line to add. Keep both settings in the environment wherever the adapter runs.
Anything else
Enroll from any language
Enrolling is one HTTPS call, POST /v1/bootstrap with
{ "token": "<enrollment key>", "agent_id": "<the agent's public key>" }.
The answer carries the connection credential and the mesh object, which
names the broker and its addresses (§18.10 of the
specification). The repository's
examples
each enroll their agents this way.