This document defines the AI Catalog, a JSON format for discovering heterogeneous AI artifacts such as MCP servers, A2A agents, Claude Code plugins, datasets, and model cards. Each catalog entry declares the artifact's type via a media type and references or inlines the native artifact metadata, enabling a single discovery mechanism across protocols and platforms. The specification defines three conformance levels — Minimal, Discoverable, and Trusted — allowing implementations to start with a simple list of entries and progressively add host identity, well-known URI discovery, and verifiable trust metadata as needed. Optional independent Trust Manifests group contributor claims, compliance attestations, and provenance; each can carry one signature binding its contents to an artifact release, while a catalog signature authenticates the complete catalog snapshot without wrapping or modifying the artifact's native format. Informative appendices define a substrate-neutral distribution-mapping contract and concrete bindings to OCI distribution registries and xRegistry, plus mappings to the MCP Registry server.json format and the Claude Code Plugins marketplace.
This is a draft document and may be updated at any time.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [[RFC2119]] [[RFC8174]] when, and only when, they appear in all capitals, as shown here.
The AI ecosystem comprises a growing number of protocols, artifact formats, and service types. Model Context Protocol (MCP) servers, Agent-to-Agent (A2A) agents, Claude Code plugins, datasets, model cards, and other AI artifacts each define their own metadata and discovery mechanisms. This fragmentation forces clients and registries to implement bespoke logic for each artifact type, increasing complexity and reducing interoperability.
This document defines the AI Catalog: a typed, nestable JSON container for discovering heterogeneous AI artifacts. Each entry declares its artifact type via a type identifier (which is an IANA media type) and may reference or embed the native artifact metadata. A minimal catalog is simply a list of entries — names, types, and URLs — requiring no additional infrastructure.
For environments that need verifiable identity, compliance evidence, or provenance tracking, this document also defines an optional Trust Manifest object. An entry can carry independent Trust Manifests, each identifying its contributor and containing attestations and provenance without wrapping or modifying the artifact's native format. Each manifest can carry one signature over its contents and a subject identifying the artifact release. An optional catalog signature authenticates the catalog snapshot. Implementations that do not need trust metadata can ignore these features.
The AI Catalog is intentionally agnostic about the artifacts it indexes. It does not define or constrain the schema of MCP server manifests, A2A agent cards, or any other artifact format. Instead, it relies on type identifiers to indicate what each entry is, and delegates the definition of artifact-specific metadata to the respective protocol specifications.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [[RFC2119]] [[RFC8174]] when, and only when, they appear in all capitals, as shown here.
The following terms are used throughout this document:
application/ai-catalog+json
media type that contains an ordered list of catalog entries.trustManifests array. Its
contributor identifies the party to whom the claims are attributed;
its optional signature authenticates that contributor's claims.Artifact Agnosticism: The catalog MUST be capable of indexing any type of AI artifact without requiring knowledge of the artifact's internal schema.
Type Identification: Each catalog entry MUST declare its artifact type using a type identifier, enabling clients to select, filter, and route entries without parsing artifact content.
Composability: The catalog format supports nesting — a catalog entry can reference another AI Catalog, enabling hierarchical organization and multi-artifact packaging.
Progressive Complexity: The simplest catalog is just entries with names and URLs. Trust, identity, and provenance metadata are available as optional extensions that never modify the catalog structure or artifact formats.
Scalable Federation: The catalog format enables partitioning into sub-catalogs to manage size, and supports delegation to sub-catalogs managed by independent publishers. Nested catalog entries support a federated model where each segment of the hierarchy may be authored, hosted, and updated independently.
Location Independence: An AI Catalog MAY be served from any URL. The standard defines a well-known URL convention to enable automated discovery, but catalogs are equally valid when hosted at arbitrary paths, embedded in registries, or distributed as files.
An AI Catalog document is identified by the media type:
application/ai-catalog+json
An AI Catalog document is a JSON object that MUST contain the following members:
specVersionentriesFor example, a minimal catalog listing four AI artifacts:
{
"specVersion": "1.0",
"entries": [
{
"identifier": "urn:air:example.com:skill:code-review",
"displayName": "Code Review Assistant",
"type": "application/agent-skills+zip",
"url": "https://skills.example.com/code-review/skill.zip"
},
{
"identifier": "urn:air:example.com:mcp:weather",
"type": "application/mcp-server-card+json",
"url": "https://api.example.com/mcp/server-card"
},
{
"identifier": "urn:air:example.com:a2a:research",
"type": "application/a2a-agent-card+json",
"url": "https://agents.example.com/researchAssistant"
},
{
"identifier": "urn:air:example.com:agent:productivity-plugin",
"displayName": "Productivity Plugin",
"type": "application/agent-plugins+zip",
"description": "Tools for common productivity workflows.",
"tags": ["productivity", "workflows"],
"url": "https://plugins.example.com/productivity.zip"
}
]
}
The following members are OPTIONAL:
hostextensionssignatureadditionalSignaturesThe Host Info object identifies the operator of the catalog. It MUST contain:
displayNameThe following members are OPTIONAL:
identifierdocumentationUrllogoUrlFor example:
{
"displayName": "Acme Enterprise AI",
"identifier": "did:web:acme-corp.com",
"documentationUrl": "https://docs.acme-corp.com/ai",
"logoUrl": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0c..."
}
A Catalog Entry object describes a single AI artifact in the catalog. It MUST contain the following members:
identifierA string uniquely identifying this artifact. This field is an open text format (e.g., any valid URI or URN is accepted). Consumers that do not recognize an identifier scheme MUST treat the value as opaque. Identifier syntax alone does not verify publisher identity or establish trust. For open or federated systems, a globally unique absolute URI is RECOMMENDED. An artifact publisher that wants an entry identifier to be preserved when the artifact appears in other catalogs SHOULD use the AI Catalog-specific urn:air naming structure with its own domain in the {publisher} segment. A catalog operator incorporating an entry for the first time with a publisher-authorized urn:air identifier MUST preserve that identifier exactly.
urn:air Identifier Format:
urn:air:{publisher}:{namespace}:{name}
{publisher}: The domain name of the organization publishing the artifact (e.g., example.com).{namespace}: The logical namespace, which can contain one or more colon-separated categories (e.g., mcp, skill, agent, finance:agent).{name}: The stable, unique name of the artifact within the publisher's namespace.Examples:
urn:air:example.com:skill:code-reviewurn:air:example.com:mcp:weatherFor closed or local systems where a different identifier format is used, client implementations are responsible for parsing and processing the custom format as appropriate.
See Multi-Version Entries for uniqueness rules when multiple versions are present, and Catalog Projection for identifiers assigned while projecting an existing Catalog Entry or source-system record.
typeA string containing the identifier that specifies the type of the referenced artifact. This field is an open text format, so any string value is accepted. However, to ensure interoperability, it is RECOMMENDED to use one of the following recognized "known types" in the ecosystem when applicable, partitioned by their respective governance boundaries:
Core Protocol Types (Governed by the AI Catalog WG):
application/ai-catalog+json — a nested AI Catalogapplication/agent-card+json — reserved for a generic Agent Card formatIntegrated Ecosystem & Third-Party Types (Governed externally):
application/a2a-agent-card+json — an A2A Agent Cardapplication/mcp-server-card+json — an MCP Server Cardapplication/agent-skills+json — Agent Skill Metadata json fileapplication/agent-skills+md — an Agent Skill defined in a standard Markdown file (the suffix +md is to be registered)application/agent-skills+zip — an Agent Skill bundle (ZIP archive)application/agent-skills+gzip — an Agent Skill bundle (gzipped tarball)application/agent-plugins+zip — an Agent Plugin bundle (ZIP archive)application/agent-plugins+gzip — an Agent Plugin bundle (gzipped tarball)These values are designed to align with official IANA media type registration standards. Standard ecosystem types use registered structured syntax suffixes (+json, +zip, +gzip). For any new or custom types not listed here, it is up to the specific client implementation to handle them correctly.
A Catalog Entry MUST contain exactly one of the following members to provide the artifact content:
urltype field.datatype field and
is opaque to this specification.The following members are OPTIONAL:
displayNameapplication/parquet), a model blob, a skill bundle
(application/agent-skills+zip), or an Agent Plugin bundle
(application/agent-plugins+zip), none of which directly expose a
self-describing name without processing the artifact. When the referenced
artifact does carry such a name — for
example the name field of an A2A Agent Card or the title field of
an MCP Server Card — that artifact is the authoritative source and
displayName SHOULD be omitted to avoid duplicating a value that can
drift out of sync. When displayName is present, however, it takes
precedence: it is the authoritative value for display, and a consumer
SHOULD render it as given even when it differs from a name carried by
the referenced artifact. Setting displayName is how a publisher
deliberately overrides the artifact's own name. See
Resolving an Artifact's Display Name
for the full consumer resolution order.descriptiondisplayName, description is OPTIONAL and follows the same
authoritative-source rule: when the referenced artifact carries its
own canonical description — for example the description field of an
A2A Agent Card or an MCP Server Card — that artifact is the
authoritative source and entry description SHOULD be omitted to
avoid duplicating a value that can drift out of sync. When entry
description is present, however, it takes precedence: a consumer
SHOULD render it as given even when it differs from a description
carried by the referenced artifact, which is how a publisher provides
a listing-specific blurb. See
Resolving an Artifact's Description
for the full consumer resolution order.tagsversionA string containing the version of this artifact.
Semantic Versioning is RECOMMENDED but not
required. See Multi-Version Entries for
how versions interact with identifier.
Like displayName and description, version can restate a value
the referenced artifact already carries (an A2A Agent Card
version, an MCP Server Card version), and when a single entry
references such an artifact the entry version SHOULD be omitted to
avoid drift — the consumer can read it from the artifact. An entry
MAY include that version when it needs to be signed directly. Unlike
displayName and description, however, version is not merely
cosmetic: it is part of the entry's uniqueness key, so it is
REQUIRED when a catalog lists multiple versions of the same
identifier (see Multi-Version Entries).
A present version is used for catalog-level sorting and selection
rather than as a free-form display override, so it SHOULD equal the
version the referenced artifact reports; an entry version that
contradicts the artifact's own version is a publishing error, not a
deliberate override. See
Resolving an Artifact's Version
for the full consumer resolution order.
updatedAtextensionspublisherdigesturl, hash the exact retrieved artifact bytes. For data, hash the
UTF-8 JCS-canonicalized [[RFC8785]] JSON value. Inline data MUST satisfy
JCS's input requirements for artifact verification to succeed. A digest
alone does not authenticate its source; see
Entry Release Coverage.trustManifestsBecause displayName is OPTIONAL, a consumer rendering a catalog entry
cannot assume it is present. To obtain a human-readable name, a consumer
SHOULD resolve one in the following order:
displayName on the entry, if present. A publisher-supplied
displayName always wins, even when it differs from a name carried by
the referenced artifact.name field
of an A2A Agent Card or the title field of an MCP Server Card.identifier as a last
resort — the portion after its final : or / delimiter. For
example, urn:air:example.com:mcp:weather yields weather and
urn:air:anonymous.modelcontextprotocol.io:mcp:brave-search yields
brave-search.A consumer SHOULD NOT dereference an artifact at render time solely to obtain a name. A registry, directory, or other service built on top of a catalog SHOULD resolve the name once at ingestion — alongside any other derived metadata it attaches, such as relevance scores or tags — and cache the result, rather than fetching artifacts on the rendering path.
This order also covers a referenced MCP Server Card whose title is
itself absent: step 2 yields no name, so the consumer falls through to
the identifier segment in step 3. A publisher MAY still set
displayName on such an entry to provide a better name than the bare
identifier segment.
Because description is OPTIONAL, a consumer that wants to show a
description cannot assume the entry carries one. It SHOULD resolve one in
the following order:
description on the entry, if present. A publisher-supplied
description always wins, even when it differs from a description
carried by the referenced artifact.description field of an A2A Agent Card or an MCP Server Card.As with name resolution, a consumer SHOULD NOT dereference an artifact at render time solely to obtain a description. A registry, directory, or other service built on top of a catalog SHOULD resolve the description once at ingestion and cache the result, rather than fetching artifacts on the rendering path.
Because version is OPTIONAL on a single entry — and present only when
the entry disambiguates others that share its identifier (see
Multi-Version Entries) or deliberately restates
the artifact's version — a consumer cannot assume every entry carries
one. To obtain a version, a consumer SHOULD resolve one in the following
order:
version on the entry, if present. Unlike displayName and
description, a present version is not a free-form display
override: it is authoritative for catalog-level sorting and version
selection. Within a multi-version listing it is REQUIRED and, combined
with identifier, uniquely addresses the entry.version field of an
A2A Agent Card, an MCP Server Card, or an MCP Registry server.json.
A single entry that omits version because the artifact already
carries it is resolved here.updatedAt, consistent with
Multi-Version Entries.When both the entry and the referenced artifact carry a version and
they disagree, the entry version is authoritative for catalog-level
sorting and selection; the mismatch is a publishing error (it breaks
latest-selection) that a consumer MAY surface but SHOULD NOT resolve by
silently preferring the artifact's value.
As with name and description resolution, a consumer SHOULD NOT dereference an artifact at render time solely to obtain a version. A registry, directory, or other service built on top of a catalog SHOULD resolve the version once at ingestion and cache the result, rather than fetching artifacts on the rendering path.
A catalog MAY contain multiple entries with the same identifier and
different version values, representing a version history for a
single artifact — similar to a package registry.
When version is present, the combination of identifier and version
MUST be unique within the catalog. When version is absent, identifier
alone MUST be unique. The identifier SHOULD be stable across versions.
Only publisher-authorized urn:air identifiers receive a cross-catalog
preservation requirement, as defined in Catalog Projection.
Clients that need only the latest version SHOULD sort entries
sharing the same identifier by version (when parseable as a semantic
version) or by updatedAt, and select the most recent. Clients
that need a specific version SHOULD match on both identifier and version.
For example, a catalog listing two versions of the same agent:
{
"specVersion": "1.0",
"entries": [
{
"identifier": "urn:air:acme.com:agent:finance",
"version": "2.1.0",
"type": "application/a2a-agent-card+json",
"url": "https://api.acme-corp.com/agents/finance/v2.1.json",
"updatedAt": "2026-03-15T10:00:00Z"
},
{
"identifier": "urn:air:acme.com:agent:finance",
"version": "2.0.0",
"type": "application/a2a-agent-card+json",
"url": "https://api.acme-corp.com/agents/finance/v2.0.json",
"updatedAt": "2026-01-20T08:00:00Z"
}
]
}
Both entries share the same identifier but have distinct version
values, so the combination is unique.
A publisher-authorized urn:air identifier is one assigned by the
artifact publisher or its authorized delegate, with the artifact
publisher's domain in the {publisher} segment.
Catalog projection creates a Catalog Entry from either a source Catalog Entry in another AI Catalog or a source record in another system. When incorporating a projected entry for the first time, a catalog operator MUST select its identifier by applying these rules in order:
urn:air identifier,
the operator MUST preserve it exactly.urn:air source identifier
or replace it. Non-urn:air identifiers have no guaranteed portability
across catalogs.urn:air with its own domain in the {publisher}
segment. An operator acting as an authorized delegate SHOULD use
urn:air with the delegating publisher's domain in that segment. An
operator that is neither the artifact publisher nor its authorized
delegate MUST use a non-urn:air identifier under its own control.Operating a catalog or aggregating an entry does not make its operator the
artifact publisher. A catalog operator MUST NOT infer publisher
authorization from the artifact's URL or an unsigned publisher field.
Adopting a different primary identifier after publication requires an explicit migration mechanism, which this specification does not define.
An identifier assigned by a catalog operator identifies the artifact, not
a particular version or source record. It MUST remain stable across
versions, source-coordinate changes, and retrieval-URL changes, and MUST
NOT be reassigned to another artifact. The catalog operator and artifact
publisher are distinct roles. The operator is the entity identified by the
top-level host field when that field is present.
A catalog operator MAY retain replaced source identifiers or source-system coordinates. If retained, they SHOULD be stored in a namespaced entry extension. They do not participate in catalog uniqueness or establish publisher identity, trust, or equivalence with another identifier.
{
"identifier": "https://registry.example/ids/artifacts/7bf4a8c2",
"type": "application/a2a-agent-card+json",
"url": "https://registry.example/apis/registry/v3/groups/payments/artifacts/fraud-agent",
"publisher": {
"identifier": "did:web:acme.example",
"displayName": "Acme"
},
"extensions": {
"com.example.registry.coordinates": {
"registryUri": "https://registry.example",
"sourceIdentifier": "foo",
"namespace": "payments",
"name": "fraud-agent"
}
}
}
The extension key is illustrative.
The Publisher object identifies the entity responsible for an artifact. It appears on the Catalog Entry and is the canonical location for publisher information. It MUST contain:
identifierdisplayNameThe following members are OPTIONAL:
identityTypeA Trust Manifest is an OPTIONAL collection of one contributor's trust metadata
about the artifact represented by an entry. The entry's trustManifests
array contains these independent contributions. Each manifest MUST contain
contributor and MAY contain the optional members below.
contributor MUST be an absolute URI [[RFC3986]] identifying the contributor
asserting this manifest's references or claims, not necessarily the issuer
of every referenced attestation or provenance statement. Authors SHOULD use
their existing identity URI, such as did:web:assessor.example. The value
MUST be preserved exactly when forwarding a Trust Manifest. Consumers MUST
NOT infer authentication from its spelling or mere presence.
A signed Trust Manifest's signature.signer MUST exactly equal contributor.
Consumers MUST compare these decoded JSON strings case-sensitively, without
URI normalization. Verifying the signature and this equality authenticates
the contributor attribution. Accepting the claims for an entry additionally
requires entry release binding. A signature over
one manifest does not authenticate other manifests or other entry fields.
Contributors can publish and update their manifests without modifying other contributors' manifests or invalidating their signatures. This version supports one signer per manifest and defines no references between manifests.
An entry MAY contain multiple manifests from the same contributor, including manifests using different verification profiles. Array order does not imply trust or precedence. Consumers evaluate each manifest independently.
A contributor MAY publish an updated Trust Manifest for the same release.
Two registries may retrieve that manifest at different times and hold
different signed versions. When choosing among updates for the same
contributor and release, consumers SHOULD prefer the manifest with the most
recent acceptable signature, comparing authenticated issuedAt instants.
An issuance time is the signer's assertion, not an independently trusted clock.
Equal issuance times with different content require local selection policy;
consumers MUST NOT infer an ordering from array order. Registries SHOULD
preserve the chosen manifest and its signature rather than merge separately
signed contents.
A Trust Manifest MUST contain at least one of: a signature, a trustSchema,
a non-empty attestations array, a non-empty provenance array, or a non-empty
extensions object. A manifest containing a signature MUST also contain
subject. A signed manifest MAY endorse only the artifact release identified
by that subject, without additional trust evidence. These members' presence
does not establish verification. Empty manifests MUST be omitted.
subjectsignature is
present. It lets the signed manifest travel independently of the entry.signatureadditionalSignaturestrustSchemaattestationsprovenanceextensionsFor example, this unsigned entry carries independent contributions:
{
"identifier": "urn:air:acme.com:agent:finance",
"type": "application/a2a-agent-card+json",
"url": "https://acme.com/finance.json",
"trustManifests": [
{
"contributor": "did:web:acme.com",
"provenance": [{
"relation": "publishedFrom",
"sourceId": "https://github.com/acme/finance"
}]
},
{
"contributor": "did:web:assessor.example",
"attestations": [{
"type": "SOC2-Type2",
"uri": "https://assessor.example/reports/acme.pdf"
}]
}
]
}
A Subject object binds a Trust Manifest to the artifact release it describes. It MUST contain:
identifieridentifier.typetype.digestdigest, which MUST be present when
an entry carries a signed Trust Manifest. For url, hash the exact retrieved
artifact bytes. For data, hash the UTF-8 JCS-canonicalized JSON value.The following member is conditional:
versionsubject.version MUST
be present exactly when entry.version is present, and its value MUST
exactly equal entry.version.These fields deliberately repeat entry values to make the signed manifest self-contained. Verification of a standalone manifest authenticates its subject and claims; accepting those claims for an entry additionally requires Entry Release Coverage. The subject does not include the retrieval URL, permitting mirrors serving identical artifact bytes.
A Trust Schema object describes the trust framework applied to the artifact. It MUST contain:
identifierversionThe following members are OPTIONAL:
governanceUriverificationMethodsFor example:
{
"identifier": "urn:trust:acme-enterprise-v1",
"version": "1.0",
"governanceUri": "https://acme-corp.com/trust/governance.pdf",
"verificationMethods": ["did", "x509"]
}
An Attestation object provides verifiable proof of a claim. It MUST contain:
typeuriThe following members are OPTIONAL:
digestsizedescriptionFor example, a compliance attestation with integrity verification:
{
"type": "SOC2-Type2",
"uri": "https://trust.acme-corp.com/reports/soc2-2026.pdf",
"digest": "sha256:a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890",
"size": 245760,
"description": "SOC2 Type 2 audit report for Acme Finance Agent (2026)"
}
A Provenance Link records lineage information. It MUST contain:
relationsourceIdThe following members are OPTIONAL:
sourceDigestregistryUristatementUrisignatureRefFor example, a provenance link recording that an artifact was built from a specific source commit and published through an OCI registry:
{
"relation": "publishedFrom",
"sourceId": "https://github.com/acme-corp/finance-agent",
"sourceDigest": "sha256:fedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321",
"registryUri": "oci://registry.acme-corp.com/agents/finance",
"statementUri": "https://trust.acme-corp.com/provenance/finance-agent-v2.1.json",
"signatureRef": "did:web:acme-corp.com#key-1"
}
This section describes how consumers verify Trust Manifests, catalog snapshots, and the evidence referenced by Trust Manifests. Verification is OPTIONAL — consumers that do not need trust assurance can skip this entirely.
The did:web Signer Profile defines an initial
interoperable authentication mechanism. Other signer profiles can use the
same data model. A signer profile MUST define permitted signer identities,
key discovery and authorization, algorithms, JWS header requirements, validity
checks, and any authority it establishes. Consumers MUST NOT authenticate an
identity using an unsupported profile.
Verification procedures direct consumers to fetch artifact URLs, evidence
references (attestation.uri, statementUri, and registryUri), and
identity-resolution endpoints derived from signing metadata. These inputs
may be attacker-controlled before authentication, so these fetches are a
server-side request forgery (SSRF) and denial-of-service surface.
Consumers performing verification MUST:
127.0.0.0/8, ::1,
169.254.0.0/16, fc00::/7, 10.0.0.0/8, 172.16.0.0/12,
192.168.0.0/16), and re-check the resolved address after any
redirect.https scheme (or inline data: URIs) and
refuse to follow redirects that cross into a disallowed address range.attestation.size is present, reject responses that exceed it; in all
cases apply a consumer-defined ceiling.Consumers SHOULD prefer inline data: attestations and Data-URI logos
to avoid leaking verification activity to third-party endpoints.
Digests in this specification use the format algorithm:hex-value,
where algorithm is a hash algorithm identifier and hex-value is
the lowercase hexadecimal encoding of the hash output. For example:
sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
Producers SHOULD use SHA-256 [[RFC6234]] or stronger. Consumers MUST reject digest values using algorithms shorter than SHA-256.
A Trust Manifest or catalog root MAY contain one signature object. A
Signature object MUST contain signer, profile, issuedAt, and jws, and
MAY contain expiresAt. Unrecognized members follow
Version Handling and remain part of the signed payload.
signerprofileissuedAtexpiresAtissuedAt.jwsencodedProtectedHeader..encodedSignature.Consumers MUST select the verification procedure named by profile, and
MUST require that it is both supported and permitted by local policy. They
MUST NOT infer another profile from signer, JWS headers, or other metadata,
or fall back to another procedure if the selected profile is unsupported,
disallowed, or fails verification. Such a signature MUST NOT count as a
verified endorsement; other manifests are evaluated independently.
Profiles defined by this specification use reserved names. Independently defined profiles MUST use absolute URI identifiers [[RFC3986]] under the profile author's control. Authors are encouraged to use a versioned HTTPS URL pointing to a human-readable definition of the profile's verification requirements. Consumers need an implementation of those requirements; retrieving the document does not supply verification behavior. Profile identifiers MUST be compared exactly and case-sensitively, without URI normalization.
A profile identifier names a defined set of verification requirements. It MUST NOT be reused for a different set of requirements. Key rotation under those requirements does not change the profile. A consumer MAY impose stricter local acceptance requirements without defining another profile.
The selected profile MUST authenticate the exact signer value using its
specified key-authorization and verification rules. Consumers MUST also
apply the coverage and authority checks required for the intended endorsement.
The did:web Publisher Profile, for example,
adds publisher authorization and release coverage to the did:web Signer
Profile.
The payload is the containing Trust Manifest or catalog object, with only these two members omitted:
jws member of its immediate signature object.additionalSignatures member, if present.All other members and values MUST be retained, including signature.signer,
signature.profile, signature.issuedAt, optional signature.expiresAt,
and unrecognized members. Ignoring an unrecognized field's meaning MUST NOT
remove it from the payload. The omissions are not recursive: members named
jws or additionalSignatures elsewhere remain included. For example, a
catalog signature includes complete nested Trust Manifests and their signatures.
For example, a signed release-only manifest has this payload:
{
"contributor": "did:web:acme.com",
"subject": {
"identifier": "urn:air:acme.com:agent:finance",
"type": "application/a2a-agent-card+json",
"digest": "sha256:56bbd2ff730d81a52951fc2f58809dfb086b4be7a82766dcc18cfe32ff6acbbd"
},
"signature": {
"signer": "did:web:acme.com",
"profile": "did-web-v1",
"issuedAt": "2026-09-12T10:00:00Z"
}
}
Canonicalize this payload with JCS [[RFC8785]]. Its UTF-8 bytes are the JWS payload. Use ordinary base64url-encoded JWS signing input, then omit only the payload segment from the stored compact serialization, as specified in Appendix F of [[RFC7515]]. Verifiers reconstruct that segment to verify the JWS. The payload MUST satisfy JCS's I-JSON constraints; parsers MUST reject duplicate JSON member names rather than silently discard one. Large integers that cannot round-trip as IEEE 754 doubles SHOULD be encoded as strings.
The protected header MUST contain alg and typ. The typ value MUST
exactly match the kind of containing object:
| Containing object | Protected typ value |
|---|---|
| Trust Manifest | ai-catalog-trust-manifest+jws |
| Catalog root | ai-catalog+jws |
Consumers MUST reject a missing or mismatched typ. This authenticated marker
prevents reusing a manifest signature as a catalog signature or vice versa.
The alg value none MUST NOT be accepted. The protected header MUST NOT
contain b64: the unencoded-payload option of [[RFC7797]] is not used. All
other header parameters, algorithm allowlists, and key-selection rules are
governed by the applicable signer profile and JWS requirements, including
rejection of unsupported critical parameters. A successful cryptographic
check alone establishes neither signer identity nor authority to make the claims.
Consumers MUST validate the Signature object's structure, profile selection,
payload, JWS, and selected signer profile before accepting an
endorsement. They MUST validate timestamp syntax and compare timestamps as
instants, not strings.
Consumers MUST NOT accept an endorsement before issuedAt or at or after
expiresAt, when present. Consumers MAY allow a small clock-skew tolerance
determined by implementation defaults or local policy. A new signature does
not cryptographically invalidate an old one. Endorsement expiry does not
replace freshness or validity checks defined by referenced evidence formats.
An invalid, unsupported, or expired signature MUST NOT count as a verified endorsement. Other manifests are evaluated independently; consumers MAY apply local requirements such as evidence from particular contributors. Consumers MUST limit authentication claims based on a Trust Manifest to its signed contents and successfully verified subject bindings.
Before relying on a Trust Manifest's signature as an endorsement of an entry's artifact release or of claims about that release, consumers MUST require:
signer
exactly equals the manifest's contributor.subject whose identifier, type, and digest exactly equal
the corresponding entry fields. The entry MUST contain digest.subject.version and entry.version absent, or both present
and exactly equal.These comparisons are between decoded JSON strings and MUST be case-sensitive, without URI normalization. Adding, removing, or changing an entry's version without the corresponding subject change makes the manifest unacceptable for that entry, even if the manifest's signature still verifies independently. Consumers MUST NOT combine fields from different manifests to establish binding.
The consumer MUST also verify the artifact bytes against the matching digest using Verifying Artifact Integrity. The retrieval URL is not signed by the Trust Manifest, permitting mirrors serving identical bytes. Other entry fields, including entry extensions, are outside the manifest signature's scope. Referenced evidence retains its own verification requirements.
A catalog signature covers the entire catalog object, omitting only its own
signature.jws and its own reserved additionalSignatures as defined in
Signed Payload and JWS Construction.
This includes specVersion, every entry in order, Host Info, extensions, and
all other present members, including unknown fields.
Nested manifest signatures and nested additionalSignatures members remain
included. Adding, removing, or changing a contribution therefore changes the
catalog snapshot and requires a new catalog signature. Adding the catalog's
own reserved additionalSignatures does not change its signed payload.
Snapshot integrity does not replace checks on referenced artifacts or
establish the authority of entry publishers.
This profile is selected by the exact profile value did-web-v1. It
authenticates a signer using a root did:web DID and an ES256 assertion key.
It can authenticate a publisher, assessor, registry, or other contributor.
Authentication does not by itself grant publisher, host, or catalog authority.
The did:web Publisher Profile adds publisher
namespace authorization.
The Signature object's signer MUST be a root did:web DID. Its domain
MUST be lowercase ASCII, with no port, IP address, trailing root dot, or
Unicode U-label; IDNA A-labels are permitted [[DIDWEB]] [[RFC5890]]
[[RFC5891]].
Other identity mechanisms, delegated controllers, path-based did:web DIDs,
and algorithms require separately defined profiles. Implementations MAY
support additional profiles by agreement; they MUST NOT silently apply these
rules to a different mechanism.
Producers conforming to the did:web Signer Profile MUST use ES256 as
defined by [[RFC7518]]. Consumers implementing the did:web Signer Profile
MUST support ES256 and MUST reject any other alg value when applying that
profile. A different algorithm can be introduced by a future signature
profile; an implementation-specific choice does not extend the did:web
Signer Profile.
The protected JWS header MUST contain kid, identifying the verification
method that authorizes the signature. It MUST NOT contain jku, jwk, x5u,
or x5c; a verifier applying the did:web Signer Profile selects key
material only through the issuer's DID document, never from a key source named
by the signature itself.
The protected kid MUST be an absolute DID URL consisting of the exact
signer value followed by a non-empty fragment, with no path or query.
A mismatch MUST fail verification under this profile. It identifies a
verification method in the signer's DID document.
For example, a signature with signer set to did:web:assessor.example
can use kid set to did:web:assessor.example#assertion-key.
The verifier MUST resolve signer according to the did:web method
[[DIDWEB]] and process the result as a DID document according to DID Core
[[DIDCORE]]. The resolution MUST satisfy the safe-fetching requirements in
Safe Fetching. Resolution fails under the did:web Signer
Profile if the DID document cannot be retrieved and validated or if its id
is not exactly equal to signer.
The verification method selected by kid MUST be authorized by the DID
document's assertionMethod verification relationship. An
assertionMethod entry can contain the verification method directly or can
reference a method in the top-level verificationMethod collection. After
resolving relative DID URLs as defined by DID Core, the verifier MUST select
exactly one verification method whose id exactly equals kid.
A key's presence in the top-level verificationMethod collection does not by
itself authorize the key to sign an AI Catalog endorsement. A key used only
for another relationship, such as authentication or keyAgreement, MUST NOT be accepted.
The selected verification method's controller MUST exactly equal
signer; the did:web Signer Profile does not support a verification method
controlled by another DID.
The selected verification method MUST contain publicKeyJwk [[RFC7517]]. The
JWK MUST describe a P-256 elliptic-curve public key: kty MUST be EC, crv
MUST be P-256, and x and y MUST contain valid curve coordinates. It MUST
NOT contain private key material. When present, alg MUST be ES256, use
MUST be sig, and key_ops MUST permit verify. A kid member inside the
JWK, if present, is not used for verification-method selection; the DID
verification method's id is authoritative.
This profile verifies against the DID document returned at verification time.
If the key identified by kid is no longer authorized by assertionMethod,
verification does not succeed. The Signature object's issuedAt value records a
claim by the issuer; it is not an independently trusted timestamp and cannot
prove that a removed key was authorized in the past.
Historical verification requires a trustworthy record of the DID document and the relevant key authorization at the time of signing. This specification does not define such a record. Applications that require durable historical verification need an additional mechanism, such as a versioned DID method, transparency log, or independently timestamped signature profile.
Signer authentication succeeds only when the Signature object and detached
JWS satisfy Signature Object, the DID document resolves
and authorizes exactly one suitable ES256 key under assertionMethod, and
the signature verifies over the reconstructed payload. The authenticated
identity is the Signature object's signer.
Failure MUST NOT be treated as a verified endorsement. Consumers MAY retain or display unverified content, retry temporarily unavailable resolution, or reject it according to local policy. A successful signature is acceptable as current only after Signature Acceptance and Time.
This profile applies the did:web Signer Profile
with two additional requirements:
urn:air
syntax. Its {publisher} component is the text following urn:air: and
preceding the next colon and MUST satisfy the root did:web domain
restrictions above. The authenticated signer identity MUST exactly match
did:web: followed by that component. Subdomain, suffix, and
organizational-ownership heuristics MUST NOT be used.entry.digest.For urn:air:example.com:agent:billing, the publisher signer is therefore
did:web:example.com. A valid signature by an assessor can endorse claims
about that same release, but does not satisfy publisher authorization.
Matching the publisher domain proves namespace control, not reputation,
claim accuracy, or artifact safety. Consumers choose which publishers and
claims meet their trust policies. A publisher MAY issue a signed manifest
containing only its contributor identity, subject, and signature to endorse
the artifact release.
A Trust Manifest signature does not authenticate the entry's publisher
object or its entry extensions, including the
Policy URLs extension. These fields are outside
its payload. Consumers MUST distinguish publisher-authenticated metadata
from metadata supplied or endorsed by another entity. A catalog signature
covers them as part of its signer's snapshot, subject to
Catalog Authorization; this does not by itself establish
publisher endorsement of those values. This specification does not define
a verification profile for a publisher-identity attestation.
An accepted publisher endorsement of the artifact does not authenticate its policy links. Signing the catalog authenticates the URL strings in its policy extension, not the contents of documents served at those URLs.
To verify the representation bound by an entry endorsement:
entry.url, or use entry.data, observing
Safe Fetching.data value using the algorithm named by entry.digest.entry.digest. A mismatch MUST fail artifact verification.An unsigned digest can detect a content mismatch but cannot authenticate the
source. The optional provenance[].sourceDigest identifies an upstream source
and MUST NOT be substituted for the digest of this entry's artifact.
For each attestation in the attestations array:
uri.digest is present, verify the fetched document matches the
declared digest.type (e.g., verify a JWT
signature, confirm a PDF certificate is current).A Provenance Link MAY reference a signed provenance statement via
statementUri and the key that signed it via signatureRef. The statement's
own format MUST define its signature algorithm, signer authorization,
key-selection rules, and verification procedure. The did:web Publisher
Profile for Entry Trust Manifests does not automatically apply to a provenance
statement, whose issuer may be a builder, transparency service, or other party.
To process such a statement:
statementUri, observing
Safe Fetching.signatureRef can assist key discovery when that format defines how to use
it, but the value is not a trust anchor by itself.entry.digest. Treat an
unverifiable statement as absent, not as a failure of the artifact itself.As catalogs grow, a flat list of entries becomes unwieldy. Because any
catalog entry can have a type of application/ai-catalog+json,
catalogs are naturally composable — an entry can reference or inline
another AI Catalog, creating a hierarchy of any depth.
A catalog entry whose type is application/ai-catalog+json
references (via url) or embeds (via data) another AI Catalog
document. This mechanism supports two complementary use cases:
Organizational hierarchy. An enterprise with thousands of artifacts
can partition its catalog into sub-catalogs by department, product line,
or region. Each sub-catalog is an independent AI Catalog document with
its own host and entries:
{
"specVersion": "1.0",
"host": {
"displayName": "Acme Enterprise AI",
"identifier": "did:web:acme-corp.com"
},
"entries": [
{
"identifier": "urn:air:acme.com:catalog:finance",
"displayName": "Finance Services",
"type": "application/ai-catalog+json",
"url": "https://acme.com/catalogs/finance.json"
},
{
"identifier": "urn:air:acme.com:catalog:ml",
"displayName": "ML Models",
"type": "application/ai-catalog+json",
"url": "https://acme.com/catalogs/ml.json"
},
{
"identifier": "urn:air:acme.com:catalog:devops",
"displayName": "DevOps Tools",
"type": "application/ai-catalog+json",
"url": "https://acme.com/catalogs/devops.json"
}
]
}
Multi-artifact packaging. An entry with a publisher that contains
a nested catalog may be interpreted as a set of items that could be
acquired as a unit. For example, a finance plugin that ships an A2A
agent, an MCP server, and a dataset together:
{
"identifier": "urn:air:acme.com:plugin:finance-suite",
"displayName": "Finance Plugin",
"type": "application/ai-catalog+json",
"url": "https://acme.com/plugins/finance-suite.json",
"publisher": {
"identifier": "did:web:acme-corp.com",
"displayName": "Acme Financial Corp"
}
}
The document at that URL would itself be an AI Catalog containing the A2A agent, MCP server, and dataset entries.
A nested catalog entry is a regular catalog entry — it has an
identifier, may carry trustManifests, and may include a
publisher. An entry inside a nested catalog MAY reuse the same
identifier as an entry elsewhere; this indicates the same logical
artifact.
Clients processing nested catalogs SHOULD impose a maximum nesting depth to prevent circular references. A depth limit of 4 is RECOMMENDED. Implementations MAY support deeper nesting but SHOULD document their limit.
The extensions property appears on the AI Catalog top-level object,
on Catalog Entry objects, and on Trust Manifest objects. It provides
a single, well-defined extension point for custom or vendor-specific
properties.
The extensions field is a JSON object (map). Each key in the object MUST
represent the extension type (namespace), and the corresponding value contains the extension data.
To avoid collisions between independent publishers, the keys MUST be a valid URL or a reverse-DNS string:
com.example.confidenceScore, io.acme.deploymentRegion.https://cisco.com/extensions/security-scan.Consumers that do not recognize an extension key MUST ignore it without throwing an error.
For example, a catalog entry with extensions representing metadata and a custom schema:
{
"specVersion": "1.0",
"entries": [
{
"identifier": "urn:air:treasury.gov:okf:fiscaldata",
"type": "text/vnd.okf+markdown",
"tags": ["finance", "treasury"],
"extensions": {
"https://ai-catalog.org/extensions/metadata": {
"location": "US-West",
"environment": "staging",
"version-compatible": [">=1.0.0"]
},
"https://openknowledgeformat.org/ns#": {
"@context": {
"us-gaap": "https://xbrl.fasb.org/us-gaap/",
"ifrs": "https://xbrl.ifrs.org/taxonomy/"
},
"type": "Financial Dataset",
"taxonomy": "us-gaap",
"conformsTo": ["us-gaap:Revenue", "ifrs:Revenue"]
}
}
}
]
}
While publishers are free to create custom extensions, this specification defines a set of "Official" known types for commonly requested schemas:
https://ai-catalog.org/extensions/metadata)
- Used to store generic, schemaless key-value pairs.https://ai-catalog.org/extensions/policy-urls)
- Links to the policies governing an artifact, defined below.As custom extensions become highly popular, the AI-Catalog TSC may promote them to Official Known Types or core standard fields in future specification versions.
The official extension key https://ai-catalog.org/extensions/policy-urls
identifies links to policies governing the entry's artifact. It is used in
entry.extensions. Its value MUST be a JSON object. The following members
are OPTIONAL:
privacyPolicyUrltermsOfServiceUrlA publisher or catalog operator MAY populate this extension. An operator's own catalog policy is not a substitute for the artifact's governing policy. The extension's presence does not establish who authenticated its values.
A Trust Manifest signature does not authenticate this extension. A catalog signature covers its complete value as part of the catalog snapshot, subject to Catalog Authorization. Signing authenticates the URL strings, not the contents of policy documents that can change at those URLs. Consumers fetching those documents MUST follow Safe Fetching.
For example, this entry excerpt supplies both links:
{
"extensions": {
"https://ai-catalog.org/extensions/policy-urls": {
"privacyPolicyUrl": "https://example.com/privacy",
"termsOfServiceUrl": "https://example.com/terms"
}
}
}
The specVersion field identifies which version of this specification
a catalog conforms to. This section defines how producers and consumers
handle version differences.
The specVersion value is a "Major.Minor" string (e.g., "1.0",
"1.1", "2.0"). Major and minor components are non-negative integers.
Consumers SHOULD:
specVersion field before processing the document.Producers MUST set specVersion to the version of this specification
they implement. Producers SHOULD NOT set specVersion to a version
higher than they actually conform to.
An AI Catalog document MAY be served from any URL. It is identified
by its media type (application/ai-catalog+json) and its specVersion
field, not by its URL path. Catalogs are equally valid when hosted at
an arbitrary path, embedded in a registry response, packaged in an
archive, or distributed as a local file.
When served over HTTP, the document SHOULD be served with the media
type application/ai-catalog+json.
To support automated discovery, hosts MAY serve an AI Catalog at the following well-known URI [[RFC8615]]:
/.well-known/ai-catalog.json
Clients performing domain-level discovery SHOULD attempt to retrieve
this well-known URL. If a valid AI Catalog document is returned, the
client SHOULD use the entries' url values to retrieve individual
artifacts. Trust metadata, when present, is carried inline on the
entries as Trust Manifests.
Use of the well-known URI is OPTIONAL. Hosts that publish catalogs at other locations (e.g., as part of an API response or a package registry) are fully conformant.
Implementing protocols MAY support dynamic catalog generation through their own mechanisms, such as providing different catalog content based on a caller's identity or query parameters. Defining dynamic discovery behavior is out of scope for this specification.
Websites MAY advertise their AI Catalog by including an ai-catalog
link relation in HTTP responses or HTML documents. This enables AI
agents, crawlers, and other automated clients to discover the catalog
associated with any website without prior knowledge of its location.
HTTP Link header. A server MAY include a Link header [[RFC8288]]
in HTTP responses:
Link: <https://example.com/catalog/ai.json>; rel="ai-catalog"
HTML <link> element. An HTML page MAY include a link element in
the document head:
<link rel="ai-catalog" href="/catalog/ai.json"
type="application/ai-catalog+json">
Agent-driven discovery. AI agents that interact with websites
(for example, agents following user instructions to "find tools on
this site" or browsing on behalf of a user) SHOULD check for the
ai-catalog link relation on the target website. The discovery
procedure is:
Link header with rel="ai-catalog".Link header is present and the response is an HTML
document, parse the document for a <link> element with
rel="ai-catalog"./.well-known/ai-catalog.json as described in
Well-Known URI.application/ai-catalog+json is preferred, but a generic
type such as application/json is acceptable, per
Location Independence) and the document
contains a valid specVersion field, treat it as the site's AI
Catalog.This mechanism allows any website to surface its AI tools, agents, and services to visiting agents through a standard, machine-readable pointer — without requiring changes to the site's visible content.
This specification defines three conformance levels. Each level builds on the previous one. Implementations MUST satisfy all requirements of their declared level.
A conformant Minimal Catalog is a JSON document with media type
application/ai-catalog+json that contains:
specVersion — the specification version stringentries — an array of Catalog Entry objects, each containing at
minimum identifier, type, and exactly one of url or
dataAll other defined members are OPTIONAL. This level supports consumers that
only need a simple list of artifacts. Each manifest in trustManifests, when
present at any level, MUST satisfy Manifest Validity.
In addition to Level 1 requirements, a Discoverable Catalog:
host object identifying the catalog operator/.well-known/ai-catalog.json
to enable automated domain-level discoveryIn addition to Level 2 requirements, a Trusted Catalog:
did:web Publisher Profile.entry.digest before relying on signed claims.did:web profiles
from other profiles supported by private agreement. Future profiles can
define additional interoperable authentication and authorization mechanisms.Conformance does not imply that every optional signature is acceptable or that every claim is true. Unverified additional contributions do not by themselves invalidate an independently verified publisher endorsement.
Implementations at any level are fully conformant with this specification. Consumers MAY ignore fields defined at higher conformance levels and SHOULD gracefully handle their absence.
This specification supports a progressive trust model. Each layer builds on the previous one, adding confidence without requiring all consumers to implement every layer. Consumers choose the level appropriate to their threat model.
entry.digest allows consumers to compare fetched or embedded content
with the declared digest. Without an authenticated endorsement, an attacker
controlling the catalog can substitute both the content and the digest.
A provenance source digest describes the source, not the entry's
representation.Consumers that rely on trust metadata for security decisions SHOULD implement at least Layer 2 (signature verification). Consumers that only implement Layer 0 or Layer 1 SHOULD treat Trust Manifest content as advisory, not authoritative.
Clients processing nested catalogs SHOULD enforce a maximum recursion depth to prevent denial-of-service attacks via deeply nested or circular catalog references. A maximum depth of 4 is RECOMMENDED.
Depth limits alone do not prevent circular references at shallow depths (e.g., Catalog A → Catalog B → Catalog A). Clients SHOULD track the set of catalog URLs visited during recursive resolution and reject any catalog URL that has already been fetched in the current traversal path.
An attacker who can modify a catalog document (e.g., through a
compromised hosting account or DNS hijack) can redirect consumers to
malicious artifacts by changing url values or injecting new entries.
The trust layers described above provide progressive defense against this threat:
subject, preventing
artifact substitution or relabeling under a valid signature.Because a Trust Manifest is a peer element of the catalog entry rather than part of the artifact, an attacker who can write the catalog document can attempt to substitute the artifact, the Trust Manifest, or both. This specification defends against substitution with three compounding mechanisms:
Signatures do not prove that a newer manifest, omitted contributor, or revoked evidence does not exist. Consumers requiring freshness beyond acceptable endorsement times need an appropriate update source and evidence policy.
Catalog entries are identified by URIs/URNs. An attacker can register
identifiers similar to legitimate ones (e.g., urn:air:acme.com:agent:financ
vs. urn:air:acme.com:agent:finance) to trick consumers into using a
malicious artifact.
Registries and consumers SHOULD implement similarity checks on identifiers. Publishers SHOULD use identifiers anchored to domains they control (e.g., DIDs or domain-scoped URNs).
Attestation documents referenced in Trust Manifests have no built-in expiry mechanism in this specification. A SOC2 report from a previous year may no longer reflect current practices.
Consumers SHOULD:
updatedAt
is only an advisory listing timestamp.Future versions of this specification MAY add validFrom and
expiresAt fields to the Attestation object.
When the data field contains embedded artifact content, consumers
MUST treat it as untrusted input. In particular:
data content is well-formed
JSON (or the expected format for the declared type) before
processing.Logo URLs SHOULD use Data URIs [[RFC2397]] to avoid leaking client
information through image fetch requests. Publishers SHOULD carefully
consider what information is included in extensions fields.
The following diagram illustrates the relationships between the core objects defined in this specification:
classDiagram
class AICatalog {
specVersion string
entries CatalogEntry[]
host HostInfo
signature Signature
}
class HostInfo {
displayName string
identifier string
}
class CatalogEntry {
identifier string
displayName string
type string
url | data
version string
publisher Publisher
trustManifests TrustManifest[]
digest string
}
class Publisher {
identifier string
displayName string
}
class TrustManifest {
contributor string
subject Subject
signature Signature
trustSchema TrustSchema
attestations Attestation[]
provenance ProvenanceLink[]
extensions object
}
class Subject {
identifier string
type string
digest string
version string
}
class TrustSchema {
identifier string
version string
verificationMethods string[]
}
class Attestation {
type string
uri string
digest string
}
class ProvenanceLink {
relation string
sourceId string
sourceDigest string
}
class Signature {
signer string
profile string
issuedAt string
expiresAt string
jws string
}
AICatalog --> "*" CatalogEntry : entries
AICatalog --> "0..1" HostInfo : host
CatalogEntry --> "0..1" Publisher : publisher
CatalogEntry --> "*" TrustManifest : trustManifests
TrustManifest --> "0..1" TrustSchema : trustSchema
TrustManifest --> "*" Attestation : attestations
TrustManifest --> "*" ProvenanceLink : provenance
AICatalog --> "0..1" Signature : signature
TrustManifest --> "0..1" Signature : signature
TrustManifest --> "0..1" Subject : subject
CatalogEntry --> "0..1" AICatalog : nested
This section registers the application/ai-catalog+json media type
[[RFC6838]] in the "Application" registry.
specVersion and entries fields.This section registers the ai-catalog link relation type in the
IANA "Link Relations" registry [[RFC8288]].
application/ai-catalog+json)
that describes AI artifacts, agents, and services associated with
the context resource. See Link Relation Discovery.This section registers the ai-catalog.json well-known URI in the
IANA "Well-Known URIs" registry [[RFC8615]].
application/ai-catalog+json conforming to the AI Catalog schema
defined in this specification.The following CDDL [[RFC8610]] defines the structural schema. The normative prose additionally constrains contributor URIs, manifest substance, subject binding, timestamp validity, and signature verification. The schema describes recognized members. Under Version Handling, consumers MUST ignore unrecognized members when validating this structure, but MUST retain them when constructing signed payloads.
AICatalog = {
specVersion: text,
? host: HostInfo,
entries: [* CatalogEntry],
? signature: Signature,
? additionalSignatures: any,
? extensions: { * text => any }
}
HostInfo = {
displayName: text,
? identifier: text,
? documentationUrl: text,
? logoUrl: text
}
CatalogEntry = {
identifier: text,
? displayName: text,
type: text,
(url: text // data: any),
? version: text,
? description: text,
? tags: [* text],
? publisher: Publisher,
? digest: text,
? trustManifests: [* TrustManifest],
? updatedAt: tdate,
? extensions: { * text => any }
}
Publisher = {
identifier: text,
displayName: text,
? identityType: text
}
TrustManifest = {
contributor: text,
? subject: Subject,
? signature: Signature,
? additionalSignatures: any,
? trustSchema: TrustSchema,
? attestations: [* Attestation],
? provenance: [* ProvenanceLink],
? extensions: { * text => any }
}
Subject = {
identifier: text,
type: text,
digest: text,
? version: text
}
Signature = {
signer: text,
profile: text,
issuedAt: tdate,
? expiresAt: tdate,
jws: text
}
TrustSchema = {
identifier: text,
version: text,
? governanceUri: text,
? verificationMethods: [* text]
}
Attestation = {
type: text,
uri: text,
? digest: text,
? size: uint,
? description: text
}
ProvenanceLink = {
relation: text,
sourceId: text,
? sourceDigest: text,
? registryUri: text,
? statementUri: text,
? signatureRef: text
}
The value under the https://ai-catalog.org/extensions/policy-urls key in
entry.extensions has the following structure:
PolicyUrls = {
? privacyPolicyUrl: text,
? termsOfServiceUrl: text
}
The following example shows an AI Catalog that contains a mix of artifact types including a nested catalog packaging related artifacts. Digest and JWS strings in illustrative examples are placeholders.
{
"specVersion": "1.0",
"host": {
"displayName": "Acme Services Inc.",
"identifier": "did:web:acme-corp.com",
"documentationUrl": "https://docs.acme-corp.com/ai"
},
"entries": [
{
"identifier": "urn:air:acme.com:agent:finance-a2a",
"version": "2.1.0",
"type": "application/a2a-agent-card+json",
"url": "https://api.acme-corp.com/agents/finance.json",
"description": "A2A agent for financial workflows.",
"tags": ["finance", "a2a"],
"publisher": {
"identifier": "did:web:acme.com",
"displayName": "Acme Financial Corp"
},
"updatedAt": "2026-03-15T10:00:00Z",
"extensions": {
"https://ai-catalog.org/extensions/policy-urls": {
"privacyPolicyUrl": "https://acme.com/legal/privacy",
"termsOfServiceUrl": "https://acme.com/legal/terms"
}
},
"trustManifests": [
{
"contributor": "did:web:acme.com",
"attestations": [
{
"type": "SOC2-Type2",
"uri": "https://trust.acme.com/reports/soc2.pdf",
"digest": "sha256:a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890"
}
]
}
]
},
{
"identifier": "urn:air:acme.com:server:finance-mcp",
"version": "1.4.0",
"type": "application/mcp-server-card+json",
"url": "https://api.acme-corp.com/mcp/server-card",
"description": "MCP server with finance tools.",
"tags": [
"finance",
"mcp"
],
"updatedAt": "2026-03-15T10:00:00Z"
},
{
"identifier": "urn:air:acme.com:plugin:finance-suite",
"displayName": "Acme Finance Suite",
"type": "application/ai-catalog+json",
"description": "A2A agent + MCP server + dataset for finance workflows.",
"tags": [
"finance",
"suite"
],
"data": {
"specVersion": "1.0",
"entries": [
{
"identifier": "urn:air:acme.com:agent:finance-a2a",
"type": "application/a2a-agent-card+json",
"url": "https://api.acme-corp.com/agents/finance.json"
},
{
"identifier": "urn:air:acme.com:server:finance-mcp",
"type": "application/mcp-server-card+json",
"url": "https://api.acme-corp.com/mcp/server-card"
},
{
"identifier": "urn:air:acme.com:data:market-2026q1",
"displayName": "Market Dataset Q1 2026",
"type": "application/parquet",
"url": "https://data.acme-corp.com/market-2026q1.parquet",
"trustManifests": [
{
"contributor": "did:web:acme.com",
"provenance": [
{
"relation": "publishedFrom",
"sourceId": "oci://registry.acme.com/data/market:2026q1",
"sourceDigest": "sha256:99998888..."
}
]
}
]
}
]
},
"updatedAt": "2026-03-20T14:00:00Z",
"digest": "sha256:22223333444455556666777788889999aaaabbbbccccddddeeeeffff00001111",
"trustManifests": [
{
"contributor": "did:web:acme.com",
"subject": {
"identifier": "urn:air:acme.com:plugin:finance-suite",
"type": "application/ai-catalog+json",
"digest": "sha256:22223333444455556666777788889999aaaabbbbccccddddeeeeffff00001111"
},
"signature": {
"signer": "did:web:acme.com",
"profile": "did-web-v1",
"issuedAt": "2026-03-20T14:00:00Z",
"jws": "eyJhbGciOiJFUzI1NiIsImtpZCI6ImRpZDp3ZWI6YWNtZS5jb20jcmVsZWFzZS1zaWduaW5nLWtleSIsInR5cCI6ImFpLWNhdGFsb2ctdHJ1c3QtbWFuaWZlc3QrandzIn0..detached-jws-signature"
}
}
]
}
]
}
The following example shows how an enterprise uses nested catalog entries to organize a large number of artifacts into browsable categories. Each sub-catalog entry points to a separate AI Catalog document:
{
"specVersion": "1.0",
"host": {
"displayName": "Acme Enterprise AI",
"identifier": "did:web:acme-corp.com"
},
"entries": [
{
"identifier": "urn:air:acme.com:agent:assistant",
"version": "3.0.0",
"type": "application/a2a-agent-card+json",
"url": "https://api.acme-corp.com/agents/assistant.json",
"description": "General-purpose corporate assistant agent."
},
{
"identifier": "urn:air:acme.com:catalog:finance",
"displayName": "Finance Services",
"type": "application/ai-catalog+json",
"url": "https://acme-corp.com/catalogs/finance.json",
"description": "Financial agents, MCP servers, and datasets.",
"tags": ["finance", "trading", "compliance"]
},
{
"identifier": "urn:air:acme.com:catalog:engineering",
"displayName": "Engineering Tools",
"type": "application/ai-catalog+json",
"url": "https://acme-corp.com/catalogs/engineering.json",
"description": "CI/CD agents, code review tools, and DevOps servers.",
"tags": ["engineering", "devops", "ci-cd"]
},
{
"identifier": "urn:air:acme.com:catalog:ml-models",
"displayName": "ML Models",
"type": "application/ai-catalog+json",
"url": "https://acme-corp.com/catalogs/ml-models.json",
"description": "Model cards and inference endpoints.",
"tags": ["ml", "models", "inference"]
}
]
}
A catalog MAY contain both direct artifact entries and nested catalog entries. In this example, the corporate assistant agent is listed directly while department-specific artifacts are organized into child catalogs.
A single agent that supports both MCP and A2A protocols can be represented as one catalog entry whose content is a nested catalog containing both protocol-specific entries:
{
"identifier": "urn:air:acme.com:agent:finance",
"displayName": "Acme Finance Agent",
"type": "application/ai-catalog+json",
"description": "Finance agent accessible via both MCP and A2A protocols.",
"tags": [
"finance",
"dual-protocol"
],
"publisher": {
"identifier": "did:web:acme.com",
"displayName": "Acme Financial Corp"
},
"data": {
"specVersion": "1.0",
"entries": [
{
"identifier": "urn:air:acme.com:agent:finance:mcp",
"type": "application/mcp-server-card+json",
"url": "https://api.acme-corp.com/mcp/server-card"
},
{
"identifier": "urn:air:acme.com:agent:finance:a2a",
"type": "application/a2a-agent-card+json",
"url": "https://api.acme-corp.com/agents/finance"
}
]
},
"trustManifests": [
{
"contributor": "did:web:acme.com",
"attestations": [
{
"type": "SOC2-Type2",
"uri": "https://trust.acme-corp.com/reports/soc2.pdf",
"digest": "sha256:a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890"
}
]
}
]
}
The outer entry represents the logical agent as a single discoverable
artifact with its own trust metadata. The data field inlines a
catalog with protocol-specific entries, allowing clients to choose
MCP or A2A based on their capabilities.
This specification was developed through collaboration among members of the A2A and MCP protocol communities under the governance of the Linux Foundation.