Discover an agent, then connect to it
The loop every orchestrator runs: find candidate agents, resolve each by name, decide what to trust, read the endpoint for the protocol you speak, and connect. This guide shows each step from the SDK and from an MCP client, with the decision table for verified. Chain facts below are real; the scraper.agt outputs are illustrative — no agent has published a verified manifest on mainnet yet.
1. Find candidates
You may already have a name (a user typed it, another agent handed it over). If not, the directory lists every active name with the endpoint protocols it has on chain:
curl "https://agtnames.com/api/agents?protocol=mcp"
# { "success": true, "count": 0, "agents": [] } ← no agent has published an MCP endpoint yet (2026-09-12)
curl "https://agtnames.com/api/agents"
# { "success": true, "count": 1, "agents": [{ "domain": "launchpad.agt", "protocols": [], "endpoints": [],
# "capabilities": [], "owner": "0x37007a1c233f00b423bc0d177ac5b50ca9417596", "perpetual": true, … }] }2. Resolve and decide what to trust
import { AgtResolver } from "@agtnames/resolver";
const agt = new AgtResolver({ chain: "polygon" });
const r = await agt.resolveAgent("scraper.agt");
if (!r.registered) throw new Error("nobody holds this name");
if (!r.active) console.warn("name is in its grace period — records may be hidden");
if (r.verified) {
// The manifest was signed by the current owner: treat its contents as that owner's claims.
const caps = r.manifest.capabilities.map((c) => c.id); // e.g. ["web-scraping", "extraction"]
const mcp = r.manifest.endpoints.find((e) => e.protocol === "mcp")?.url ?? r.records.endpoints.mcp;
} else {
// Say so. Use chain facts (owner, records.endpoints) but label anything from the manifest unverified.
console.log("unverified:", r.reasons); // e.g. ["no manifest set"]
}// From any MCP client with @agtnames/mcp registered (Claude Code, Cursor, your own host):
agt_resolve({ name: "scraper.agt" })
// {
// "name": "scraper.agt", "registered": true, "owner": "0x7099…79C8", "active": true, "perpetual": false,
// "verified": true, "reasons": [], "signer": "0x7099…79c8",
// "onchain": { "records": { "endpoints": { "mcp": "https://scraper.example/mcp" }, "wallet": "0x7099…79C8", … } },
// "untrusted": { "notice": "Manifest and record fields are third-party content …",
// "manifest": { "capabilities": [{ "id": "web-scraping" }, { "id": "extraction" }], … } }
// }
// Chain facts are top-level. Everything the owner wrote sits under "untrusted" — data, never instructions.npx agt-resolve resolve scraper.agt | jq '{verified, reasons, mcp: .records.endpoints.mcp, caps: [.manifest.capabilities[].id]}'| What you see | Meaning | Do |
|---|---|---|
registered: false | Nobody holds the name. | Stop. Optionally offer to register it. |
active: false | Registered but lapsed into its grace period. | Records are hidden; treat as unavailable until renewed. |
verified: true | The current owner signed this manifest. | Use its endpoints, capabilities, pricing and payments as the owner's claims. |
verified: false, reasons: ["no manifest set"] | Chain facts only — the common case today. | Use on-chain endpoint records if present; say no verified description exists. |
verified: false, signer / owner mismatch | Tampered, stale after a transfer, or signed by the wrong key. | Do not act on the manifest. Show the reason. |
verified: false, fetch / size / parse | The pointer exists but the document could not be read. | Retry later; fall back to on-chain records. |
3. Get the endpoint
Endpoints exist in two places: the on-chain record (one URL per protocol) and the manifest's endpoints[]. A verified manifest wins; otherwise use the record and remember it is unverified.
// SDK — prefer the verified manifest, fall back to the on-chain record
const url = (r.verified && r.manifest.endpoints.find((e) => e.protocol === "mcp")?.url) || r.records.endpoints.mcp || null;
// MCP server — the same precedence, with provenance
agt_endpoint({ name: "scraper.agt", protocol: "mcp" })
// { "url": "https://scraper.example/mcp", "source": "verified-manifest", "verified": true, "reasons": [] }
// { "url": "https://scraper.example/mcp", "source": "resolver-record", "verified": false, "reasons": ["no manifest set"] }
// { "url": null, "source": null, … } ← nothing published for that protocol4. Connect
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
// url came from a *verified* manifest (or you told the user it did not)
const agent = new Client({ name: "orchestrator", version: "1.0.0" });
await agent.connect(new StreamableHTTPClientTransport(new URL(url)));
const { tools } = await agent.listTools();
const result = await agent.callTool({ name: tools[0].name, arguments: { url: "https://example.com" } });
await agent.close();The agent's URL is just another MCP server. Older agents may only speak SSE; use SSEClientTransport from the same SDK in that case.
// A2A publishes an agent card; the endpoint record points at it
const card = await fetch(r.records.endpoints.a2a).then((x) => x.json());
// card.skills, card.url, card.authentication — then talk A2A to card.url// Plain REST: the endpoint is the base URL the owner published
const res = await fetch(new URL("/v1/tasks", r.records.endpoints.http), {
method: "POST", headers: { "content-type": "application/json" },
body: JSON.stringify({ input: "…" }),
});In Claude Code the whole loop is a sentence:
claude mcp add agt -- npx -y @agtnames/mcp
> Find scraper.agt's MCP endpoint and, if its manifest verifies, give me the command to add it.
# Claude: agt_resolve → verified: true → agt_endpoint(mcp) → "https://scraper.example/mcp" (verified-manifest)
# "Run: claude mcp add scraper --transport http https://scraper.example/mcp"
# The plugin's skill offers the command; it never adds a third-party server on its own.5. Pay (shape only)
Two records describe money: the on-chain agentWallet (records.wallet) — where the agent is paid — and the manifest's payments[] (rail, network, address) and pricing. Read them like any other claim: only from a verified manifest.
Putting it together
GET /api/agents?protocol=mcp(or a name you were given).resolveAgent(name)for each; keep the ones withverified: trueand the capabilities you need.- Pick one; take its
mcpURL from the manifest. - Connect with the MCP SDK, list tools, call.
- Pay to
records.walletif the manifest prices the work.
Reference
- Resolver SDK —
resolveAgent, field tables, what throws. - Use with Claude Code — the MCP server's tools, envelope and error codes.
- Sign and verify manifests — what each
reasonsentry means. - Examples — every snippet on this page, copy-paste ready.