Reference
The ard.json manifest, field by field
Everything an ARD entry can carry, what each term is for, and what actually breaks when you get one wrong. Written against specification v0.91.
An ard.json file is the manifest a publisher hosts at
https://yourdomain.com/.well-known/ard.json to advertise agentic resources. It holds an
entries array, and every entry requires four terms: identifier,
displayName, type, and exactly one of url or
data.
A fifth term, representativeQueries, is marked SHOULD rather
than MUST. Leave it out and the entry is still valid, but no registry can rank it, so nobody finds
it. That single omission is the most common reason a published resource stays invisible.
Where the file goes
One path, at the root of the domain:
https://yourdomain.com/.well-known/ard.json
Served over HTTPS, with Content-Type: application/json. Two details that account
for a surprising share of manifests that never get indexed: the well-known prefix is a single
directory named .well-known with a leading dot, and the file must be reachable
without authentication. A crawler arrives with no cookie, no token and no referrer.
The dotfile trap. If your site is behind a framework router, check that it serves the dotfile rather than routing it to a 404 page or to your app shell. A manifest that returns HTML with a 200 status is worse than a 404, because the crawler cannot tell it failed. Paste your domain here and it will tell you which one you have.
The manifest envelope
The outer document is thin on purpose. Everything meaningful is in entries.
| Field | Required | What it is |
|---|---|---|
entries | yes | An array of ARD entries. This is the payload. An empty array is valid and means you publish nothing, which is a legitimate thing to say. |
specVersion | recommended | Which revision of the manifest shape you wrote against. Read it in your own tooling rather than assuming, because the format has already changed once. |
host | recommended | Who is publishing: displayName, an identifier such as a did:web, and a documentationUrl. This is what a registry shows beside your entries, so a missing one costs you presentation, not indexing. |
Hosting a manifest of entries at https://{domain}/.well-known/ard.json. The manifest is a JSON document with an entries array of ARD entries; any other top-level members are transport-defined and ignored by ARD.
ARD specification v0.91, section 5.1, Discovery Mechanisms agenticresourcediscovery.org
Entry fields, one by one
This is the whole vocabulary. Four terms are required, one is the difference between being listed and being found, and the rest are there when you need them.
Required
| Term | Type | What it does | Getting it wrong |
|---|---|---|---|
identifier | string | The globally unique handle for this resource, in the form urn:air:<publisher>:<namespace>:<name>. The publisher segment is a domain you control. | A publisher segment that is not your domain gets the entry rejected by any registry that verifies. A non-unique name silently collides with your own other entry. |
displayName | string | The human-readable name. Shown to a person choosing between results. | Naming it after your company rather than the capability. Nobody searches for your company when they need a thing done. |
type | string | An IANA media type saying what the artifact is, for example application/mcp-server-card+json. This is the envelope's whole job. | Inventing a type. Clients filter on this field, so an unrecognised value removes you from every filtered search. |
url or data | string / object | Exactly one. url points at the artifact document; data inlines it. The artifact is the Server Card or Agent Card, not the ARD entry. | Carrying both is invalid. Pointing url at your homepage instead of the artifact is valid and useless. |
The one that decides whether you are found
representativeQueries is marked SHOULD rather than MUST, which makes it easy to
skip. Skipping it is the single most common reason a correctly published resource is never
returned by a search.
Sample natural-language queries a user might issue that this resource can serve, the signal a registry builds its semantic index from. An entry without it cannot be found by search, which is what distinguishes an ARD entry from a bare catalog entry.
ARD specification v0.91, section 4.2, Entry Terms agenticresourcediscovery.org
Two to five of them. Write the sentence a person types when they have the problem you solve, not a description of your product. The difference in practice:
{
"representativeQueries": [
"convert a PDF invoice into structured JSON",
"pull the line items out of a scanned receipt",
"read a supplier invoice and give me totals and VAT"
]
}
{
"representativeQueries": [
"document processing",
"AI-powered OCR solution",
"enterprise-grade extraction platform"
]
}
The second set fails because a registry embeds these sentences and matches them against a user's actual phrasing. "AI-powered OCR solution" is close to nothing anyone types. It is also close to every competitor who wrote the same words, so even where it matches you are undifferentiated.
Optional, and worth having
| Term | Type | When to use it |
|---|---|---|
capabilities | array of strings | Short tokens such as ["WeatherTool"] for fast structured filtering without fetching the artifact. Cheap to add and it makes you filterable. |
description | string | One or two sentences of prose. Shown in results, and most registries index it as a secondary signal. |
tags | array of strings | Free-form labels. Usable as a filter key. |
version | string | Your artifact's version, not the spec's. |
updatedAt | ISO 8601 date | When the resource last changed. Registries use freshness in ranking and in deciding when to re-crawl you. |
metadata | object | Anything else. Not expanded into the JSON-LD graph, but dot-paths into it (metadata.region) can be used as filters by registries that index them. |
trustManifest | object | Verifiable identity, attestations, provenance, signature. Only trustManifest.identity is constrained by ARD. Skip it until someone asks. |
@context | object or string | v0.91 made an entry a JSON-LD node. Adding a context lets you carry terms from another vocabulary, and those terms become filter dimensions with no change to the spec. |
Complete examples
An MCP server
{
"specVersion": "1.0",
"host": {
"displayName": "Acme Weather",
"identifier": "did:web:acme.com",
"documentationUrl": "https://acme.com/docs"
},
"entries": [
{
"identifier": "urn:air:acme.com:server:weather",
"displayName": "Weather Data Node",
"type": "application/mcp-server-card+json",
"url": "https://api.acme.com/mcp/weather.json",
"description": "Live weather telemetry and forecasts for any coordinate.",
"capabilities": ["WeatherTool", "ForecastTool"],
"tags": ["weather", "geospatial"],
"updatedAt": "2026-08-30",
"representativeQueries": [
"what is the current wind speed in Chicago",
"get the 5-day forecast for Seattle",
"is it going to rain in Berlin tomorrow"
]
}
]
}
A skill, published by one person
No trust manifest, no host block ceremony. This is a complete and conformant entry.
{
"identifier": "urn:air:github.com:alice-dev:pptx-creator",
"displayName": "pptx-creator",
"type": "application/ai-skill+md",
"url": "https://github.com/alice-dev/pptx-creator",
"description": "Create PowerPoint presentations that follow brand guidelines.",
"representativeQueries": [
"turn these bullet points into a branded slide deck",
"make a PowerPoint from this outline"
]
}
Several resources, one domain
The usual real case. One file, one entry per thing, distinct namespaces so the identifiers do not collide.
{
"specVersion": "1.0",
"host": { "displayName": "Acme", "identifier": "did:web:acme.com" },
"entries": [
{
"identifier": "urn:air:acme.com:server:weather",
"displayName": "Weather Data Node",
"type": "application/mcp-server-card+json",
"url": "https://api.acme.com/mcp/weather.json",
"representativeQueries": ["what is the wind speed in Chicago"]
},
{
"identifier": "urn:air:acme.com:agent:support",
"displayName": "Acme Support Agent",
"type": "application/a2a-agent-card+json",
"url": "https://api.acme.com/agents/support.json",
"representativeQueries": ["open a support ticket with Acme"]
},
{
"identifier": "urn:air:acme.com:api:billing",
"displayName": "Acme Billing API",
"type": "application/openapi+json",
"url": "https://api.acme.com/openapi.json",
"representativeQueries": ["fetch an Acme invoice by number"]
}
]
}
With a trust manifest
What enterprise procurement asks for. The identity domain has to match the publisher segment of the identifier, which is the anti-squatting rule in section 4.5.1.
{
"identifier": "urn:air:acme.com:server:payments",
"displayName": "Acme Payments",
"type": "application/mcp-server-card+json",
"url": "https://api.acme.com/mcp/payments.json",
"representativeQueries": ["charge a saved card", "refund an Acme transaction"],
"trustManifest": {
"identity": "did:web:acme.com",
"attestations": [
{ "type": "SOC2-Type2", "uri": "https://acme.com/compliance/soc2.json" }
],
"provenance": { "publishedFrom": "https://github.com/acme/payments-mcp" }
}
}
The other four ways to publish
The well-known file is the one every consumer must check, so it is the one to do first. The specification lists four more, and they matter when a manifest is awkward to host.
| Mechanism | What it looks like | When it earns its keep |
|---|---|---|
| In-page JSON-LD | An entry embedded in a page describing the resource, found by ordinary web crawling. | You already have a docs page per tool and would rather not maintain a second file. |
<link rel="ard"> | <link rel="ard" href="/entries.json"> in the head. | Your manifest cannot live at the well-known path. Consumers must honour this link, so it is a real alternative rather than a hint. |
| Agentmap in robots.txt | Agentmap: https://example.com/entries.json | You already control robots.txt and want one more pointer. Costs one line. |
| DNS service binding | _entries._agents.example.com for a static source, _search._agents.example.com for a registry endpoint. | You are publishing a registry, or the HTTP surface is not yours to change. |
Ten things that break a manifest
From checking published manifests against the spec. Ordered by how often they turn up.
- No
representativeQueries. Valid, invisible. This is most of them. - A 200 response that is HTML. Framework routing served the app shell for an unknown path. The crawler parses it as JSON, fails, and moves on.
- Publisher segment does not match the host.
urn:air:acme.com:...served fromacme-tools.io. A verifying registry drops it. - Both
urlanddata. Explicitly invalid, and easy to do when you refactor from inline to hosted. - Redirect chains. Some crawlers follow one hop, not four. Serve the file where you say it is.
urlpoints at a marketing page. It must point at the artifact, the Server Card or Agent Card, not the page about it.- Invented media type.
application/my-tool+jsonfilters you out of every typed search. - Still on
ai-catalog.json. Consulting that path is optional for consumers now. Moving takes ten minutes. - Authentication in front of the manifest. The manifest is public by definition, even when everything it describes needs a key.
- Never updated. No
updatedAtand no change for months tells a registry to re-crawl you rarely, and freshness feeds ranking.
Once it is correct
Get indexed
A valid manifest that no registry has fetched is a file on a disk. Point one at it.
curl -X POST https://neuronto.com/submit \
-H "Content-Type: application/json" \
-d '{"url": "https://yourdomain.com"}'
Disclosure: Neuronto is run by the people who write this
site, and it is named first for that reason as much as any other. It resolves a bare domain to
your manifest, indexes entries of every type rather than MCP servers only, and answers with what
it found or exactly what it tried. Add "dry_run": true to see the outcome without
being written anywhere.
The other public registries take submissions through their own doors, and submitting to several costs nothing: WellKnown, ARD Registry Hub, Desvela. What actually reaches all of them over time is the manifest on your own domain, which is the part nobody can take away from you. How each one behaves, probed.
Questions
What is the ard.json file?
A JSON document you host at https://yourdomain.com/.well-known/ard.json. It has an entries array, and each entry describes one agentic resource: an MCP server, a skill, an API, an agent, or another registry. Any ARD registry that finds the file may index what is in it.
What fields are required in an ARD entry?
Four. identifier, displayName, type, and exactly one of url or data. Carrying both url and data is invalid. You should also carry representativeQueries, because without it the entry validates but cannot be found by search.
Where exactly does ard.json go?
/.well-known/ard.json at the root of the domain, served over HTTPS with Content-Type: application/json. Not on a subpath, not on a subdomain unless that subdomain is what you want indexed. The well-known prefix is a single directory, so it is example.com/.well-known/ard.json and never example.com/well-known/ard.json.
What is the urn:air identifier format?
urn:air:<publisher>:<namespace>:<agent-name>, where publisher is a domain you control. So urn:air:acme.com:server:weather. The publisher segment is what a verifying registry checks against your trust manifest, and it is how the specification defends against namespace squatting.
Does the manifest need a signature?
No. trustManifest is optional and most published manifests do not carry one. You need it when a consumer has to verify cryptographically who you are, which in practice means enterprise procurement. A solo developer publishing a skill needs none of it.
Can one manifest describe resources on other domains?
Technically yes, the url can point anywhere. But the publisher segment in each identifier is bound to a domain, and a verifying registry rejects an entry claiming a publisher it cannot tie to you. Describe what you actually control.
Last reviewed 2026-09-04. Checked against ARD v0.91 (Proposal, 2026-08-26).