Discovering and Trusting Agentic Resources with ARD
Stand up both halves of Agentic Resource Discovery offline: publish and cryptographically sign a catalog, run a registry and client, and watch trust verification reject an impersonator.
Download starter repoOn this page▾
- What you'll build
- Why this matters (the 5-minute business case)
- Concepts you'll use (2-minute primer)
- Prerequisites
- Setup (3 minutes)
- Exercise 1 — Publish a catalog (author + validate) (12 min)
- Exercise 2 — Sign the catalog (establish verifiable identity) (10 min)
- Exercise 3 — Discover resources (registry + client) (12 min)
- Exercise 4 — Verify trust before connecting (the payoff) (12 min)
- Wrap-up
- Stretch challenges (for the labs series)
- Troubleshooting
- References
What you'll build
By the end of this lab you'll have a small but complete, fully offline simulation of Agentic Resource Discovery (ARD) — the open specification Google and partners announced on June 17, 2026 for publishing, discovering, and verifying AI capabilities across the web. You'll play both sides of the protocol:
- As a publisher: author an
ai-catalog.json, validate it against the official schema, and cryptographically sign it so others can trust it. - As a consumer: run a tiny discovery registry, build a client that searches it with plain-language intent, and — the part that matters most — verify trust before connecting to anything.
Along the way you'll watch the client correctly reject a malicious catalog that impersonates a legitimate publisher. That moment is the whole point of ARD.
Everything runs locally with no API keys and no network calls, so you can focus on the concepts rather than credentials.
Why this matters (the 5-minute business case)
Read this section before handing the lab to your team.
The problem ARD solves is "the agentic web has no address book — and no caller ID." As organizations build agents, those agents increasingly need capabilities (tools, skills, MCP servers, other agents) that live in other teams, other companies, and other platforms. Today there's no standard way to answer three questions across organizational boundaries: Where does the right capability live? Which one should I use? And how do I know it's safe to connect to? Every platform has its own private registry, and none of them talk to each other.
ARD is a proposed standard layer that sits before invocation. It does not run anything — it helps an agent find the right resource and verify who published it, then gets out of the way so the agent connects over that resource's native protocol (MCP, A2A, an API, etc.). Three reasons a business should care:
- It reduces lock-in and integration cost. When capabilities are published under an organization's own domain and indexed by interoperable registries, you stop writing bespoke connectors for every partner and every platform. The breadth of the launch coalition — Google, Microsoft, Hugging Face, GoDaddy, Cisco, Databricks, GitHub, Nvidia, Salesforce, ServiceNow, Snowflake — is itself the signal: this is aimed at being a neutral standard, not one vendor's moat.
- It makes trust a first-class, auditable property. ARD anchors identity in domain ownership (you can only publish a verifiable catalog for a domain you control) and carries trust metadata — cryptographic identity, compliance attestations (SOC 2, HIPAA, GDPR), and signatures. For security, risk, and procurement teams, "can we prove who published this tool and that it wasn't tampered with?" becomes a checkable step instead of a leap of faith.
- It enables dynamic capability without re-shipping software. An agent can discover and load a brand-new tool at runtime based on the task in front of it, instead of having every tool hardcoded at build time. That changes how fast a business can expand what its agents can do.
The honest caveats, because pragmatic adoption means naming them:
- It's brand new and not yet widely deployed. This is a specification and reference implementation, not a mature ecosystem. There aren't (yet) large public registries indexing the whole web. Treat it as strategically important to track and prototype against, not as production infrastructure today.
- Discovery is not endorsement. ARD deliberately carries evidence of trust; it never vouches for a resource. The relevance
scorea registry returns is not a safety rating. Your client (and your policies) still own the trust decision. A naïve integration that connects to whatever ranks first is actively dangerous — which is exactly what Exercise 4 demonstrates. - Enterprise reality differs from the open web. Inside a company, resources are often gathered through an internal registry or curated inventory rather than open-web crawling. Google's own enterprise offering (Agent Registry in the Gemini Enterprise Agent Platform) adds governance like namespaced URNs and egress policies on top of the open spec.
A useful framing for a non-technical stakeholder: "ARD is trying to be DNS-plus-caller-ID for AI tools: a standard way for our agents to find capabilities anywhere, and to verify who really published them before connecting. It's early, but it's backed by most of the industry at once, so it's worth a prototype now."
Concepts you'll use (2-minute primer)
Four ideas carry the whole lab:
- Catalog — a static
ai-catalog.jsonfile a publisher hosts athttps://<domain>/.well-known/ai-catalog.json. It lists their capabilities. Because it lives on their domain, domain ownership is the root of identity. - Registry (a.k.a. discovery service / Agent Finder) — a search engine for the agentic web. It crawls catalogs, indexes them, and answers
POST /searchrequests. - URN identity — every entry has an identifier like
urn:ai:acme.com:server:weather. The domain is baked into the name, which is what lets a client check that an entry's claimed identity matches where it really came from. - Trust manifest — the security envelope on an entry: a cryptographic
identity(e.g. adid:web), optional complianceattestations, and asignature. Verifying it is how a client proves a resource is authentic before connecting.
The golden rule: ARD sits entirely *before* invocation. It tells you which resource and where; you then connect over the resource's own protocol.
Prerequisites
| You need | Notes |
|---|---|
| Python 3.9+ | python3 --version to check |
pip | For three small libraries (cryptography, jsonschema, requests) |
| Two terminal windows | One for the registry, one for the client |
| ~$0 and no accounts | Everything is local and offline |
Get the starter repo. This lab refers to scripts in the accompanyingard-lab/repo. Unzip it andcdinto it before starting. If you'd rather build from scratch, each exercise shows the key code.
Setup (3 minutes)
cd ard-lab
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt # cryptography, jsonschema, requestsThat's it — no keys, no config. The repo ships with three sample catalogs in catalogs/:
acme.com.json— a legitimate publisher (a weather MCP server + a travel A2A agent)globex.io.json— another legitimate publisher (a competing weather server)darkpartner.io.json— a malicious publisher we'll use to prove trust verification works
Exercise 1 — Publish a catalog (author + validate) (12 min)
Goal: Understand the catalog format by reading a real one, then validate it against the official schema — the same quality gate you'd run in CI before deploying.
1a. Read the manifest
Open catalogs/acme.com.json. The shape is small and worth internalizing:
{
"specVersion": "1.0",
"host": { "displayName": "Acme Dev Tools", "identifier": "did:web:acme.com" },
"entries": [
{
"identifier": "urn:ai:acme.com:server:weather",
"displayName": "Acme Weather Telemetry Server",
"type": "application/mcp-server+json",
"url": "https://api.acme.com/mcp/weather.json",
"capabilities": ["WeatherTool", "ForecastTool"],
"description": "An enterprise weather MCP server providing live telemetry.",
"representativeQueries": [
"what is the current wind speed in Chicago",
"get the 5-day forecast for Seattle"
],
"trustManifest": { "identity": "did:web:acme.com", "...": "..." }
}
]
}Three fields do most of the work:
- `identifier` follows the domain-anchored URN standard:
urn:ai:<your-domain>:<namespace>:<name>. The domain is part of the name — remember that; it's the hook for trust in Exercise 4. - `type` is an IANA media type telling the client which native protocol to speak (
application/mcp-server+json,application/a2a-agent-card+json,application/ai-skill, …). - `representativeQueries` (2–5 of them) are natural-language examples that registries use to build semantic search indexes. This is how your resource becomes findable, so write them the way a user would actually ask.
An entry points to its full artifact with either a url or an inline data object — exactly one of the two (the schema enforces it).
Business callout: the catalog is essentially a product listing for a capability. representativeQueries are its SEO. If your team publishes tools, whoever writes these strings is doing marketing as much as engineering — vague queries mean your capability never surfaces for the tasks it's perfect for.1b. Validate against the schema
Publishing an invalid catalog means registries may silently skip you — so validation is the cheapest possible safeguard. Run:
python validate_catalog.pyExpected:
OK acme.com.json (2 entries)
OK darkpartner.io.json (2 entries)
OK globex.io.json (1 entries)Now break it on purpose to see the gate work. In catalogs/acme.com.json, change the first identifier to something that violates the URN pattern (e.g. drop the urn:ai: prefix: "acme.com:server:weather") and re-run. You'll get a precise pointer to the failure. Put it back when you're done.
Note on hosting (you won't do this in the lab, but know it): in the real world you'd serve this file athttps://<your-domain>/.well-known/ai-catalog.jsonover HTTPS, withContent-Type: application/jsonandAccess-Control-Allow-Origin: *so crawlers can fetch it. Publishing makes you discoverable — it doesn't guarantee any given registry indexes you; each one decides what it includes.
Checkpoint: You can read and validate an ARD catalog. That's everything a publisher needs to be findable. Next we make it trustworthy.
Exercise 2 — Sign the catalog (establish verifiable identity) (10 min)
Goal: Give each catalog a cryptographic signature so a consumer can later prove who published it and that it wasn't altered.
The trust model rests on one principle: you can only produce a valid signature for a domain whose private key you hold. Since catalogs live on your domain, controlling the domain is controlling the identity.
2a. Generate publisher keys
python gen_keys.pyThis creates an Ed25519 keypair for each catalog's host domain and publishes the public key as a local well-known/<domain>/did.json — our offline stand-in for did:web resolution. Output:
keypair generated for acme.com -> well-known/acme.com/did.json
keypair generated for darkpartner.io -> well-known/darkpartner.io/did.json
keypair generated for globex.io -> well-known/globex.io/did.jsonNotice the rogue publisher, darkpartner.io, gets its own key — not acme's. Hold that thought.
2b. Sign every catalog with its host key
python sign_catalog.py acme.com.json: signed 2 entries as 'acme.com'
darkpartner.io.json: signed 2 entries as 'darkpartner.io'
globex.io.json: signed 1 entries as 'globex.io'Each entry's trustManifest.signature is now an Ed25519 signature over the entry's content, made with the host domain's private key. Open acme.com.json again and you'll see real signature strings where the placeholders were.
Here's the security crux, and it's worth saying slowly: darkpartner.io.json contains an entry that copies acme's URN (urn:ai:acme.com:server:weather) to look legitimate. But sign_catalog.py can only sign darkpartner's catalog with darkpartner's key — because that's the only private key darkpartner has. The forgery is signed, but signed by the wrong party. In Exercise 4 the client will catch exactly that.
What we simplified (and what's real): real ARD signatures are detached JWS; we use a raw Ed25519 signature over canonical JSON. The cryptographic idea is identical — an asymmetric signature you verify with the publisher's published public key. We kept it simple so the verification code is readable.
Business callout: this is why ARD's identity story is compelling to security teams. Impersonation isn't prevented by hoping nobody lies in a catalog — it's prevented by math. A publisher's claims are only worth anything if they're signed by the key bound to the domain they claim.
Checkpoint: Your catalogs are now both valid and verifiable. Switch hats — you're now the consumer.
Exercise 3 — Discover resources (registry + client) (12 min)
Goal: Stand up a discovery service, then build a client that turns a plain-language task into a ranked list of candidate resources.
3a. Start the registry
In your first terminal:
python registry.pyARD registry indexing 5 entries.
Listening on http://127.0.0.1:8080 (POST /search)registry.py crawled the catalogs/ folder, flattened every entry into an index, and now serves the ARD POST /search contract. (Our scoring is simple keyword overlap; a production registry uses semantic vector search. The contract — request shape, response shape, score 0–100, referrals — is what's standardized, not the ranking algorithm.)
3b. Search by intent
In your second terminal:
python client.py "current wind speed in Chicago"Under the hood the client sends exactly the request the spec describes:
POST http://127.0.0.1:8080/search
{
"query": { "text": "current wind speed in Chicago" },
"pageSize": 5,
"federation": "referrals"
}and reads back ranked results (each carrying the identifier, type, url, a score, and the source registry) plus optional referrals to other registries you could query yourself.
Try a filtered search too — narrowing by media type:
python client.py "book me a flight to Tokyo" --type application/a2a-agent-card+jsonThe filter rule to remember: values within one key are OR'd, and different keys are AND'd. So {"type": ["A", "B"], "tags": ["x"]} means (type A or B) and tag x.
The discovery-first payoff: notice the client only ever loads the selected resource's details into context — not all five. That's the core efficiency argument for runtime discovery: your model sees the handful of tools that matter for the task, not a directory of thousands.
Business callout:federationis the "open web" lever.nonekeeps a search inside one registry;referralslets a registry point you at peers you can choose to query;autolets it merge upstream results for you. An enterprise can run a private registry over internal tools and federate selectively to trusted partners — the same pattern as an intranet search that can also reach the public web.
Checkpoint: You can find resources by intent and read the standardized response. But notice what we have not done yet: trusted any of it.
Exercise 4 — Verify trust before connecting (the payoff) (12 min)
Goal: Make the client refuse to connect to anything it can't cryptographically verify — and watch it catch a real impersonation attempt.
This is the exercise that justifies the whole specification. A relevance score tells you a resource matches; it says nothing about whether it's safe. The spec is explicit: a client MUST NOT read score as a trust, compliance, or safety rating. Verification is a separate, independent step.
4a. The four-step trust check
Look at verify_entry() in ard_common.py. For each candidate it:
- Extracts the publisher domain from the URN —
urn:ai:acme.com:server:weather→acme.com. - Confirms the claimed identity is bound to that domain — the
trustManifest.identity(did:web:acme.com) must resolve to the same domain as the URN. A mismatch is a red flag for impersonation. - Resolves the publisher's public key — via
did:web(here, the localwell-known/<domain>/did.json). - Verifies the signature — confirms the entry was signed by that domain's key and wasn't altered in transit.
Only if all four pass does the client treat the resource as authentic. (In production you'd also audit the attestations array — SOC 2, HIPAA, etc. — but identity + signature is the non-negotiable core.)
4b. Watch it reject the impersonator
You already ran the weather query in Exercise 3. Look again at its output — now read the trust: line under each result:
[100] Acme Weather Telemetry Server
urn:ai:acme.com:server:weather
trust: VERIFIED (verified publisher acme.com)
[100] Acme Weather Telemetry Server (FREE MIRROR)
urn:ai:acme.com:server:weather
trust: REJECTED (signature does not verify (tampered or wrong signer))
[100] Acme Billing Agent (definitely real)
urn:ai:acme.com:agent:billing
trust: REJECTED (identity domain 'darkpartner.io' does not match URN domain 'acme.com' (possible impersonation))
[100] Globex WeatherPro
urn:ai:globex.io:server:weatherpro
trust: VERIFIED (verified publisher globex.io)
Selected (highest-scoring verified): Acme Weather Telemetry ServerSit with this. All four results scored 100 — by relevance alone, the malicious entries looked just as good as the real one. Two distinct attacks were caught by trust, not relevance:
- The forged mirror copies acme's exact URN and even claims acme's identity — but darkpartner could only sign it with darkpartner's key, so the signature fails against acme's real public key. Caught at step 4.
- The fake billing agent claims an
acme.comURN while its identity honestly saysdarkpartner.io— the domains don't match. Caught at step 2, before we even check the signature.
The client connects only to the highest-scoring verified result, and if nothing verifies it refuses to connect at all.
Business callout — this is the slide for your security review. Without verification, an agent doing open-web discovery is one well-optimized malicious catalog away from sending data to (or running code from) an attacker who simply claimed to be your vendor. ARD doesn't make that impossible to attempt — it makes it detectable, automatically, with cryptography. "Verify before connect" should be a hard requirement in any ARD client you build or buy.
Checkpoint: Your client discovers by relevance and connects only by trust. That separation — and never confusing the two — is the single most important habit in the agentic-discovery world.
Wrap-up
You built and ran both halves of Agentic Resource Discovery. You can now:
- Author and validate an
ai-catalog.jsonagainst the official schema - Sign a catalog so its publisher identity is cryptographically verifiable
- Stand up a registry and a client that speak the ARD
POST /searchcontract - Verify trust before connecting — and catch impersonation that relevance scoring would happily wave through
The one idea to carry forward: ARD cleanly separates findability from trust. A registry's job is to help you find candidates; your client's job is to decide what's safe. The protocol carries the evidence and refuses to make the trust decision for you — and any system you build on top of it must take that decision seriously, every single time, before it connects.
Stretch challenges (for the labs series)
- Federation, for real. Run a second registry on port 8081 over a different subset of catalogs, and make the client follow
referrals— issuing the same search to the referred registry and merging the results itself. (The sample registry already advertises a referral; make the client act on it.) - Compliance-gated selection. Extend
verify_entry()so the client only selects resources whosetrustManifest.attestationsinclude a required standard (e.g. requireHIPAAfor a healthcare task). This turns trust verification into policy enforcement. - Tamper detection demo. After signing, edit a verified entry's
urlby hand (point it somewhere else) and re-run the client without re-signing. Watch the signature check fail — proof that the signature binds the endpoint, not just the name.
A natural next lab in the series: connecting an actual MCP server to a verified ARD entry, so discovery flows straight into a live tool call.
Troubleshooting
| Symptom | Likely cause / fix |
|---|---|
Could not reach the registry | Start python registry.py in another terminal first. |
Every result is REJECTED for "no key" | Run python gen_keys.py then python sign_catalog.py before searching. |
| Legit entries rejected as "signature does not verify" | You edited a catalog after signing. Re-run python sign_catalog.py. |
validate_catalog.py import error on old jsonschema | The script auto-selects a validator; for clean draft-2020-12 support use pip install -U jsonschema. |
| Port 8080 already in use | Edit PORT in registry.py and the endpoint in client.py. |
cryptography install fails | Upgrade pip (pip install -U pip) and retry; it ships prebuilt wheels for most platforms. |
References
All technical details are drawn from the announcement and the official ARD specification:
- Announcing the Agentic Resource Discovery specification (Google Developers Blog, June 17, 2026)
- ARD specification and guides
- How to publish a catalog
- How to add ARD support to your agent (client)
- ARD spec & schemas on GitHub
A note on accuracy for your readers: ARD is a young specification and may evolve. This lab uses raw Ed25519 signatures and local did:web resolution as readable stand-ins for detached JWS and networked identity resolution — the verification logic mirrors the spec, but before publishing, point readers at the live spec for the exact wire formats, and note which version you validated against.Written by Wes Goldwater, Director of Engineering at Prosigliere.
Hands-on cloud & pragmatic AI from Goldwater.dev.