--- a/base/index.html +++ b/head/index.html @@ -13,6 +13,12 @@ "shortName": "ai-catalog", "edDraftURI": "https://ai-catalog.io/", "localBiblio": { + "xRegistry": { + "title": "xRegistry: A Universal Registry Specification", + "href": "https://github.com/xregistry/spec", + "status": "Draft", + "publisher": "CNCF" + }, "RFC8785": { "title": "JSON Canonicalization Scheme (JCS)", "href": "https://www.rfc-editor.org/rfc/rfc8785", @@ -23,6 +29,18 @@ "title": "JSON Web Key (JWK)", "href": "https://www.rfc-editor.org/rfc/rfc7517", "status": "RFC", + "publisher": "IETF" + }, + "RFC7518": { + "title": "JSON Web Algorithms (JWA)", + "href": "https://www.rfc-editor.org/rfc/rfc7518", + "status": "RFC", + "publisher": "IETF" + }, + "RFC8725": { + "title": "JSON Web Token Best Current Practices", + "href": "https://www.rfc-editor.org/rfc/rfc8725", + "status": "BCP 225", "publisher": "IETF" }, "RFC6234": { @@ -57,7 +75,7 @@

Abstract

-

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. An optional Trust Manifest extension provides identity binding, compliance attestations, provenance tracking, and cryptographic signatures without wrapping or modifying the artifact's native format. Informative appendices describe mappings to OCI distribution registries, the MCP Registry server.json format, and the Claude Code Plugins marketplace.

+

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. An optional Trust Manifest extension provides identity binding, compliance attestations, provenance tracking, and cryptographic signatures 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.

@@ -199,11 +217,13 @@ }, { "identifier": "urn:air:example.com:mcp:weather", + "displayName": "Weather Service", "type": "application/mcp-server-card+json", "url": "https://api.example.com/.well-known/mcp/server-card.json" }, { "identifier": "urn:air:example.com:a2a:research", + "displayName": "Research Assistant", "type": "application/a2a-agent-card+json", "url": "https://agents.example.com/researchAssistant" } @@ -219,6 +239,13 @@
An open map of string keys to arbitrary values for custom or non-standard metadata. See Metadata Extensibility for key naming conventions.
+
signature
+
A string containing a detached JWS [[RFC7515]] signature computed over + the JCS-canonicalized [[RFC8785]] catalog document (excluding the + signature member itself), providing catalog-level integrity over the + entries array and host. It is verified exactly as a Trust Manifest + signature (see Trust Manifest Signatures). + See Trust Manifest Substitution.
@@ -275,6 +302,8 @@

For 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.

+
displayName
+
A string containing a human-readable name for the artifact.
type

A string containing the identifier that specifies the type of the @@ -310,23 +339,6 @@

The following members are OPTIONAL:

-
displayName
-
A string containing a human-readable name for the artifact. - This field SHOULD be set only when the referenced artifact does not - already carry its own canonical human-readable name — for example a - raw dataset (application/parquet), a model blob, or a skill bundle - (application/agent-skills+zip), none of which embed a self-describing - name. 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.
description
A string containing a short description of the artifact.
tags
@@ -351,35 +363,6 @@ providing verifiable identity and trust metadata for this artifact. See Trust Manifest for details.
-
-

Resolving an Artifact's Display Name

-

Because 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:

-
    -
  1. displayName on the entry, if present. A publisher-supplied - displayName always wins, even when it differs from a name carried by - the referenced artifact.
  2. -
  3. The referenced artifact's own canonical name, if the consumer has - already fetched or cached the artifact — for example the name field - of an A2A Agent Card or the title field of an MCP Server Card.
  4. -
  5. The trailing segment of the entry's 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.
  6. -
-

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.

-

Multi-Version Entries

@@ -401,6 +384,7 @@ "entries": [ { "identifier": "urn:air:acme.com:agent:finance", + "displayName": "Acme Finance Agent", "version": "2.1.0", "type": "application/a2a-agent-card+json", "url": "https://api.acme-corp.com/agents/finance/v2.1.json", @@ -408,6 +392,7 @@ }, { "identifier": "urn:air:acme.com:agent:finance", + "displayName": "Acme Finance Agent", "version": "2.0.0", "type": "application/a2a-agent-card+json", "url": "https://api.acme-corp.com/agents/finance/v2.0.json", @@ -463,17 +448,44 @@ identity schemes is open.

When a Trust Manifest appears within a Catalog Entry, the identity -field's authority or trust domain MUST align with the publisher domain segment of -the entry's URN identifier field. This binding ensures trust claims are -cryptographically bound to the authorized publisher of the catalog entry. -Consumers MUST reject a Trust Manifest whose identity domain does not -align with the publisher domain of the entry's identifier.

+field MUST match the entry's identifier field. This binding ensures trust +claims are unambiguously associated with the catalog artifact. +Consumers MUST reject a Trust Manifest whose identity does not +match the containing entry's identifier. The identity is restated +here — rather than read from the entry's identifier — so that it falls +within the signed payload; this is an intentional duplication, not +redundant metadata, and removing it would leave the signature uncommitted +to which identifier the trust claims apply.

When a Trust Manifest appears on a Host Info object, identity SHOULD match the host's identifier field when present.

When multiple entries share the same identifier (with different version values), each entry MAY carry its own Trust Manifest. There is no requirement that all versions carry identical trust metadata — trust properties may evolve across versions.

+
+
+

Manifest Validity

+

A Trust Manifest exists to carry verifiable trust evidence; an empty one +adds nothing and misleads consumers into believing trust metadata is +present. Beyond the required identity, a Trust Manifest MUST therefore +contain at least one substantive trust member:

+ +

The members identity and identityType (which restate or describe the +entry identifier) and the informational members privacyPolicyUrl, +termsOfServiceUrl, and metadata do NOT satisfy this requirement. +subject, issuedAt, and expiresAt are not substantive on their own: +an unsigned subject digest is attacker-settable and unverifiable, so +they count only as part of a signature.

+

A Trust Manifest that would carry only non-substantive members MUST be +omitted entirely rather than included empty — the trustManifest member +is itself OPTIONAL, so no information is lost. Consumers SHOULD treat a +Trust Manifest that violates this rule as if no Trust Manifest were +present.

Optional Members

@@ -498,13 +510,33 @@ artifact.
termsOfServiceUrl
A string containing a URL to the terms of service.
+
subject
+
A Subject object as defined in Subject Binding that + cryptographically binds this Trust Manifest to the specific artifact it + describes. A Trust Manifest that carries a signature MUST include a + subject.
+
issuedAt
+
A string containing an ISO 8601 [[RFC3339]] timestamp indicating when + the Trust Manifest was created and signed. A Trust Manifest that + carries a signature MUST include issuedAt.
+
expiresAt
+
A string containing an ISO 8601 [[RFC3339]] timestamp after which the + Trust Manifest MUST be considered stale. Consumers SHOULD reject a + Trust Manifest whose expiresAt is in the past.
signature
-
A string containing a detached JWS [[RFC7515]] signature computed - over the Trust Manifest content. This enables integrity verification - of the trust metadata independent of the artifact.
+
A string containing a detached JWS [[RFC7515]] signature computed over + the canonicalized Trust Manifest content, including the subject and + issuedAt members. Because the signed payload commits to the artifact + digest carried in subject, neither the trust claims nor the artifact + reference can be substituted without detection. See + Trust Manifest Signatures.
metadata
An open map of string keys to arbitrary values for extending trust - metadata.
+ metadata. Unlike the Catalog Entry's metadata (which is + informational and unsigned), this map is part of the signed payload + when the Trust Manifest carries a signature; use it for extensions + that must be cryptographically bound to the manifest, and use the + entry's metadata for unsigned, informational extensions.

For example, a Trust Manifest with identity, attestations, and provenance:

@@ -538,9 +570,53 @@ ], "privacyPolicyUrl": "https://acme-corp.com/legal/privacy", "termsOfServiceUrl": "https://acme-corp.com/legal/terms", + "subject": { + "url": "https://api.acme-corp.com/agents/finance/v2.1.json", + "mediaType": "application/a2a-agent-card+json", + "digest": "sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" + }, + "issuedAt": "2026-03-15T10:00:00Z", "signature": "eyJhbGciOiJFUzI1NiJ9..detached-jws-signature" } +
+
+

Subject Binding

+

The Subject object binds a Trust Manifest to the specific artifact it +describes, closing the substitution gap in which an attacker who +controls the catalog document leaves a validly-signed Trust Manifest in +place but repoints the entry to a different artifact. Because the +Subject is part of the signed payload, the artifact reference and its +content digest cannot be changed without invalidating the signature.

+

A Subject object MUST contain:

+
+
mediaType
+
A string containing the media type of the bound artifact. This MUST + equal the containing Catalog Entry's mediaType.
+
digest
+
A string containing the cryptographic digest of the artifact content, + in the format defined in Digest Format. For an + artifact referenced by url, the digest is computed over the exact + bytes served. For an artifact embedded in data, the digest is + computed over the JCS-canonicalized [[RFC8785]] JSON value.
+
+

The following member is OPTIONAL:

+
+
url
+
A string containing the URL of the bound artifact. When present, it + MUST equal the containing Catalog Entry's url. Consumers MUST reject + a Trust Manifest whose subject.url does not match the entry's url.
+
+

A Trust Manifest that carries a signature MUST include a subject. +When verifying such a manifest, consumers MUST confirm that the fetched +artifact's media type and digest match the subject before relying on +any claim in the Trust Manifest. See +Verifying Artifact Integrity.

+

The subject.mediaType and subject.url intentionally restate the +entry's mediaType and url so that those values fall within the signed +payload. This is a deliberate duplication, not redundant metadata: +without it, an attacker who controls the catalog document could change +the entry's media type or location without invalidating the signature.

Trust Schema Object

@@ -639,6 +715,30 @@

This section describes how consumers verify the trust metadata carried by a Trust Manifest. Verification is OPTIONAL — consumers that do not need trust assurance can skip this entirely.

+
+

Safe Fetching

+

Verification procedures direct consumers to fetch URLs that originate in +the Trust Manifest itself (attestation.uri, statementUri, +registryUri, and key-resolution endpoints). Because a manifest may be +attacker-controlled before its identity is anchored, these fetches are a +server-side request forgery (SSRF) and denial-of-service surface. +Consumers performing verification MUST:

+ +

Consumers SHOULD prefer inline data: attestations and Data-URI logos +to avoid leaking verification activity to third-party endpoints.

+

Digest Format

Digests in this specification use the format algorithm:hex-value, @@ -651,20 +751,53 @@

Trust Manifest Signatures

-

The signature field carries a detached JWS [[RFC7515]] computed -over the Trust Manifest content. To create or verify a signature:

+

The signature field carries a detached JWS [[RFC7515]] computed over +the Trust Manifest content, including the subject and issuedAt +members. To create or verify a signature:

  1. Canonicalize the Trust Manifest JSON using JCS (JSON - Canonicalization Scheme) [[RFC8785]]. Remove the signature - field itself before canonicalization.
  2. -
  3. Sign (or verify) the canonical bytes as a detached JWS - payload using the publisher's private (or public) key.
  4. -
  5. Encode the resulting JWS in compact serialization and store - it in the signature field.
  6. + Canonicalization Scheme) [[RFC8785]]. Remove the signature field + itself before canonicalization; all other members — including + subject and issuedAt — remain in the signed payload. +
  7. Select an algorithm from the allowlist in + Signature Algorithms. The JWS alg header + parameter MUST identify the algorithm used.
  8. +
  9. Sign (or verify) the canonical bytes as a detached JWS payload + using the publisher's private (or public) key.
  10. +
  11. Encode the resulting JWS in compact serialization and store it + in the signature field.
-

This approach ensures the signature is stable regardless of JSON -key ordering or whitespace, and can be verified independently of the -artifact content.

+

This approach ensures the signature is stable regardless of JSON key +ordering or whitespace. Because the signed payload includes the +subject binding, a verified signature commits the publisher to a +specific artifact digest, not merely to the trust claims.

+

Producers SHOULD avoid placing numeric values that do not round-trip +under JCS serialization (e.g., integers outside the range exactly +representable as IEEE 754 doubles) in a signed Trust Manifest, as such +values can cause a verifier's canonicalization to differ from the +producer's. Where large integers are required, encode them as strings.

+
+
+

Signature Algorithms

+

To prevent signature-forgery attacks, producers and consumers MUST +constrain the JWS algorithms used for Trust Manifest signatures.

+ +

These constraints follow the JSON Web Token current best practices +[[RFC8725]].

Key Resolution

@@ -686,6 +819,29 @@ or look up a DNSKEY/TXT record containing the JWK thumbprint.
+
+

Trust Anchoring

+

Verifying a Trust Manifest signature proves that the manifest was signed +by the holder of the key associated with its identity. It does NOT, by +itself, prove that the identity is the legitimate publisher of the +artifact. An attacker who controls the catalog document can replace both +the identity and the key it resolves to, then sign the forged manifest +with their own key — every internal check would still pass.

+

Consumers MUST therefore anchor the identity (or signing key) to a +trust root established out of band, independent of the catalog document. +Acceptable anchors include:

+ +

A verified signature without an anchored identity establishes integrity +and internal consistency only; consumers MUST NOT treat it as proof of +publisher authenticity.

+

Verifying Host Identity

To verify the host of a catalog:

@@ -710,17 +866,37 @@
  • Confirm the JWT claims bind the publisher.identifier to the Trust Manifest's identity.
  • +

    The publisher object resides on the Catalog Entry, outside the Trust +Manifest signature. Consumers MUST treat publisher fields as advisory +unless a verified publisher-identity attestation cryptographically +binds publisher.identifier to the signed manifest's identity.

    Verifying Artifact Integrity

    -

    When a Trust Manifest includes provenance entries with sourceDigest:

    +

    When a Trust Manifest carries a signature, it MUST include a subject +that binds it to the artifact (see Subject Binding). +To verify artifact integrity:

      -
    1. Fetch the artifact content from the entry's url.
    2. -
    3. Compute the digest using the algorithm specified in the - sourceDigest field.
    4. -
    5. Compare the computed digest to the declared value. Reject the - artifact if they differ.
    6. +
    7. Verify the Trust Manifest signature + (Trust Manifest Signatures) and anchor + the identity (Trust Anchoring).
    8. +
    9. Confirm subject.mediaType equals the entry's mediaType, and, when + subject.url is present, that it equals the entry's url.
    10. +
    11. Fetch the artifact content from the entry's url, or take it from + the entry's data, observing the limits in + Safe Fetching.
    12. +
    13. Compute the digest of the fetched bytes (for url) or of the + JCS-canonicalized value (for data) using the algorithm named in + subject.digest.
    14. +
    15. Compare the computed digest to subject.digest. Reject the artifact + if they differ.
    +

    Because the subject is part of the signed payload, this check binds +the publisher's signature to the exact artifact, defeating catalog-level +substitution of the artifact URL or content. The OPTIONAL +provenance[].sourceDigest records the digest of an upstream source +(e.g., a Git commit) and is complementary to — not a substitute for — +the subject digest.

    Verifying Attestations

    @@ -731,6 +907,24 @@ declared digest.
  • Validate the attestation per its type (e.g., verify a JWT signature, confirm a PDF certificate is current).
  • + +
    +
    +

    Provenance Statements

    +

    A Provenance Link MAY reference a signed provenance statement via +statementUri and the key that signed it via signatureRef. To verify +such a statement:

    +
      +
    1. Fetch the statement document from statementUri, observing + Safe Fetching.
    2. +
    3. Resolve the key indicated by signatureRef using the procedure in + Key Resolution and anchor it per + Trust Anchoring.
    4. +
    5. Verify the statement's signature using an algorithm from + Signature Algorithms.
    6. +
    7. Confirm the statement's subject matches the artifact's subject + digest. Treat an unverifiable statement as absent, not as a failure + of the artifact itself.
    @@ -970,13 +1164,14 @@

    All other fields (host, publisher, trustManifest, metadata) are OPTIONAL. This level is sufficient for use cases that only need a simple list of AI artifacts — for example, a catalog of -MCP servers or A2A agents.

    +MCP servers or A2A agents. A trustManifest, when present at any level, +MUST be substantive (see Manifest Validity).

    Level 2: Discoverable Catalog

    @@ -991,8 +1186,19 @@

    Level 3: Trusted Catalog

    In addition to Level 2 requirements, a Trusted Catalog:

    +
    +
    +

    Trust Manifest Substitution

    +

    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:

    +
    @@ -1133,6 +1370,7 @@ specVersion string entries CatalogEntry[] host HostInfo + signature string } class HostInfo { displayName string @@ -1154,10 +1392,17 @@ } class TrustManifest { identity string + subject Subject trustSchema TrustSchema attestations Attestation[] provenance ProvenanceLink[] + issuedAt string signature string + } + class Subject { + url string + mediaType string + digest string } class TrustSchema { identifier string @@ -1180,6 +1425,7 @@ CatalogEntry --> "0..1" Publisher : publisher CatalogEntry --> "0..1" TrustManifest : trustManifest HostInfo --> "0..1" TrustManifest : trustManifest + TrustManifest --> "0..1" Subject : subject TrustManifest --> "0..1" TrustSchema : trustSchema TrustManifest --> "*" Attestation : attestations TrustManifest --> "*" ProvenanceLink : provenance @@ -1354,6 +1600,7 @@ "entries": [ { "identifier": "urn:air:acme.com:agent:finance-a2a", + "displayName": "Acme Finance A2A Agent", "version": "2.1.0", "type": "application/a2a-agent-card+json", "url": "https://api.acme-corp.com/agents/finance.json", @@ -1385,6 +1632,7 @@ }, { "identifier": "urn:air:acme.com:server:finance-mcp", + "displayName": "Acme Finance MCP Server", "version": "1.4.0", "type": "application/mcp-server-card+json", "url": "https://api.acme-corp.com/.well-known/mcp/server-card.json", @@ -1403,11 +1651,13 @@ "entries": [ { "identifier": "urn:air:acme.com:agent:finance-a2a", + "displayName": "Finance A2A Agent", "type": "application/a2a-agent-card+json", "url": "https://api.acme-corp.com/agents/finance.json" }, { "identifier": "urn:air:acme.com:server:finance-mcp", + "displayName": "Finance MCP Server", "type": "application/mcp-server-card+json", "url": "https://api.acme-corp.com/.well-known/mcp/server-card.json" }, @@ -1454,6 +1704,7 @@ "entries": [ { "identifier": "urn:air:acme.com:agent:assistant", + "displayName": "Acme Corporate Assistant", "version": "3.0.0", "type": "application/a2a-agent-card+json", "url": "https://api.acme-corp.com/agents/assistant.json", @@ -1511,11 +1762,13 @@ "entries": [ { "identifier": "urn:air:acme.com:agent:finance:mcp", + "displayName": "Acme Finance MCP Server", "type": "application/mcp-server-card+json", "url": "https://api.acme-corp.com/.well-known/mcp/server-card.json" }, { "identifier": "urn:air:acme.com:agent:finance:a2a", + "displayName": "Acme Finance A2A Agent", "type": "application/a2a-agent-card+json", "url": "https://api.acme-corp.com/agents/finance" } @@ -1539,46 +1792,154 @@ catalog with protocol-specific entries, allowing clients to choose MCP or A2A based on their capabilities.

    -
    -

    Mapping to OCI Distribution

    -

    This appendix describes how AI Catalog documents can be distributed -through OCI registries, enabling content-addressed storage, signing, -and replication using existing container infrastructure.

    -
    -

    Logical Format vs. Physical Distribution

    +
    +

    Mapping to Distribution Substrates

    The AI Catalog specification defines a logical format: a JSON document with entries, displayName, type, and trustManifest fields that are immediately meaningful to anyone working with AI artifacts. Authors write simple JSON. APIs serve simple JSON. Clients consume simple JSON.

    -

    OCI provides a physical distribution layer: content-addressed -storage, cryptographic signing via Cosign/Notation, global replication -through registries, and referrer-based metadata association. These are -valuable infrastructure capabilities, but OCI's data model uses -container-oriented vocabulary (manifests, layers, config, -digest) that does not naturally describe a catalog of AI artifacts.

    -

    This specification treats OCI as one distribution option, not as the -canonical data model. The logical AI Catalog format remains the -authoring and consumption interface. Tooling bridges the two:

    -
    Authoring                         Distribution                    Consumption
    -─────────                         ────────────                    ───────────
    -ai-catalog.json    ──pack──►    OCI Registry     ──unpack──►   ai-catalog.json
    -  entries[]                       Index/Manifests                  entries[]
    -  trustManifest                   Referrers                        trustManifest
    -
    -

    This separation means:

    -
      -
    • Simplicity for authors: Publishers write AI Catalog JSON using - domain vocabulary. No knowledge of OCI manifests, digests, or layer - descriptors is required.
    • -
    • Simplicity for consumers: Clients that fetch from - /.well-known/ai-catalog.json or a registry API receive the logical - JSON format. They never need to parse OCI structures.
    • -
    • Power for infrastructure: Registries that want content-addressed - integrity, signing, and replication can store catalogs as OCI - artifacts using the mapping defined below.
    • -
    -
    +

    That logical format can be physically distributed over more than one +substrate — an OCI registry, an [[xRegistry]] registry, or a plain HTTP +server. Each substrate has its own data model and its own native +capabilities. To keep the logical format authoritative and to avoid +diverging, substrate-specific dialects, every binding defined by this +specification MUST satisfy the same contract: packing a logical document +into the substrate and unpacking it again MUST reproduce an equivalent +logical document.

    +
    Authoring                      Distribution                    Consumption
    +─────────                      ────────────                    ───────────
    +ai-catalog.json   ──pack──►   OCI / xRegistry / HTTP  ──unpack──►   ai-catalog.json
    +  entries[]                     substrate-native form                entries[]
    +  trustManifest                                                      trustManifest
    +
    +

    This separation keeps authoring and consumption simple: publishers and +clients work with domain vocabulary (entries, displayName, +mediaType, trustManifest), while infrastructure that wants +content-addressing, signing, replication, or registry APIs uses whichever +binding below matches its substrate.

    +
    +

    Binding Invariants

    +

    A conforming binding MUST preserve each of the following invariants. This +list — not any single substrate's vocabulary — is the conformance bar for +a pack/unpack round-trip.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Logical conceptInvariant a binding MUST preserve
    Entry identity (identifier)A stable, addressable identity for each entry
    Artifact content + mediaTypeThe artifact bytes are retrievable together with their media type
    Catalog structure / nestingNested catalogs remain navigable as a hierarchy
    Trust Manifest associationAn entry's Trust Manifest is discoverable from that entry
    Content integrityThe served bytes are verifiably bound to trustManifest.subject.digest
    SigningThe Trust Manifest's authenticity is cryptographically verifiable
    +
    +
    +

    Delegate, Don't Duplicate

    +

    Substrates differ in what they can express natively. OCI is +content-addressed and has first-class signing (Cosign/Notation); +xRegistry is a hierarchical resource API with versioning and +cross-referencing but no native digest or signature primitive.

    +

    To avoid expressing the same guarantee twice, a binding delegates an +invariant to a native substrate primitive when one exists, and otherwise +carries it in the logical Trust Manifest. A binding MUST NOT restate, +in substrate vocabulary, a guarantee it has delegated, and MUST NOT drop +a guarantee the substrate cannot express.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    InvariantOCI primitive (delegate)xRegistry primitive (delegate)Carried fallback
    IdentityRepository path + digestresourceid / xidentry.identifier
    Content + media typelayers[0] + artifactTypeResource document + contenttypeEntry artifact + mediaType
    NestingNested Image IndexNested Group / xrefNested entry
    Manifest associationReferrers API (subject)xref / extension attributeInline trustManifest
    Content integrityContent-addressed digest(none — carried)subject.digest
    SigningCosign / Notation referrer(none — carried)Detached JWS in Trust Manifest
    +

    The two sections that follow are concrete bindings of this contract. The +OCI binding delegates the most (identity, content integrity, signing); +the xRegistry binding delegates structure, identity, and discovery but +carries content integrity and signing because xRegistry has no native +primitive for them.

    +
    +
    +
    +

    Mapping to OCI Distribution

    +

    This appendix binds the Mapping to Distribution +Substrates contract to OCI +registries, enabling content-addressed storage, signing, and replication +using existing container infrastructure. OCI's data model uses +container-oriented vocabulary (manifests, layers, config, digest) +that does not naturally describe a catalog of AI artifacts, so tooling +bridges the logical format and the OCI representation.

    +

    Of the binding invariants, the OCI binding delegates identity, +content integrity, and signing to OCI's own primitives. Consequently +trustManifest.subject.digest is expected to equal the OCI descriptor +digest of the served artifact, and the detached JWS in the Trust Manifest +MAY be omitted from the packed representation because Cosign/Notation +referrers carry signing instead. Unpacking reconstitutes (or re-signs) +the logical Trust Manifest from those referrers.

    Conceptual Mapping

    The OCI image specification (v1.1+) supports arbitrary artifact types @@ -1800,6 +2161,182 @@ while infrastructure-oriented deployments leverage OCI distribution.

    +
    +

    Mapping to xRegistry

    +

    This appendix binds the Mapping to Distribution +Substrates contract to [[xRegistry]], +a hierarchical registry model organized as Registry → Groups → Resources +→ Versions. xRegistry contributes structure, identity, versioning, +cross-referencing, and a registry API; it has no native content-addressing +or signature primitive.

    +

    Of the binding invariants, the xRegistry binding delegates entry +identity, catalog structure, artifact content, and manifest discovery to +xRegistry's own primitives, but carries content integrity and signing +in the Trust Manifest. The detached JWS and subject.digest remain +authoritative exactly as in plain-HTTP distribution, because xRegistry +cannot express either guarantee natively.

    +
    +

    Conceptual Mapping

    +

    An AI Catalog document maps to an xRegistry Group whose Resources +are the catalog entries; each entry's artifact is the Resource document.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AI Catalog (Logical)xRegistry (Physical)
    AI Catalog documentA Group instance (e.g. in a aicatalogs Group type), or the Registry root when serving a single catalog
    Catalog EntryA Resource within that Group
    Entry identifierResource <SINGULAR>id and xid
    Entry mediaTypeVersion contenttype (with format when a named format applies)
    Entry artifact contentResource document — inline (<RESOURCE> / <RESOURCE>base64) or external (<RESOURCE>url)
    Entry metadata (displayName, description, tags)name, description, labels
    Entry versionVersion versionid
    Nested Catalog EntryA nested Group referenced from the entry's Resource via meta.xref
    Trust ManifestAn extension attribute on the Resource (an object), or a related Resource referenced by xref
    Content integrity (subject.digest)Carried in the Trust Manifest (xRegistry has no native digest)
    SigningDetached JWS retained in the Trust Manifest (xRegistry has no native signature)
    +
    +
    +

    Packing: AI Catalog to xRegistry

    +

    Tooling converts an AI Catalog JSON document into xRegistry resources:

    +
      +
    1. +

      The catalog becomes a Group instance. Catalog-level metadata maps + to Group attributes: displayName to name, host identity and other + metadata to labels or extension attributes.

      +
    2. +
    3. +

      Each catalog entry becomes a Resource in that Group. The entry's + artifact content is stored as the Resource document — inline via + <RESOURCE> / <RESOURCE>base64, or by reference via <RESOURCE>url. + mediaType maps to contenttype; entry metadata maps to name, + description, and labels. Multiple entry versions map to Versions.

      +
    4. +
    5. +

      Trust Manifests are carried as an extension attribute on the + Resource (for example aicatalog_trustmanifest), or as a related + Resource referenced from meta.xref. The detached JWS and + subject.digest are retained unchanged because xRegistry provides no + native signing or content-addressing to delegate to.

      +
    6. +
    7. +

      Nested catalog entries become nested Groups; the parent entry's + Resource references the nested Group through meta.xref.

      +
    8. +
    +
    +
    +

    Unpacking: xRegistry to AI Catalog

    +

    Tooling converts xRegistry resources back to an AI Catalog JSON document:

    +
      +
    1. Retrieve the Group in document view (the xRegistry ?doc projection), + which returns a single self-contained JSON document analogous to + ai-catalog.json.
    2. +
    3. For each Resource, read its document (inline or via <RESOURCE>url) + and contenttype to recover the entry's artifact content and + mediaType; map name, description, and labels back to entry + metadata.
    4. +
    5. Read the Trust Manifest from the extension attribute or xref'd + Resource, and verify its detached JWS and subject.digest against the + served bytes.
    6. +
    7. Resolve xref'd nested Groups into nested catalog entries.
    8. +
    9. Assemble the logical application/ai-catalog+json document.
    10. +
    +
    +
    +

    xRegistry Document Example

    +

    The following shows the xRegistry document-view representation of a Group +holding two entries. This is generated by tooling, not authored by hand:

    +
    {
    +  "aicatalogid": "acme-services",
    +  "self": "https://registry.acme.com/aicatalogs/acme-services",
    +  "xid": "/aicatalogs/acme-services",
    +  "epoch": 1,
    +  "name": "Acme Services Inc.",
    +  "entriesurl": "https://registry.acme.com/aicatalogs/acme-services/entries",
    +  "entriescount": 2,
    +  "entries": {
    +    "finance-a2a": {
    +      "entryid": "finance-a2a",
    +      "xid": "/aicatalogs/acme-services/entries/finance-a2a",
    +      "name": "Acme Finance A2A Agent",
    +      "contenttype": "application/a2a-agent-card+json",
    +      "labels": {
    +        "ai-catalog.identifier": "urn:acme:agent:finance-a2a"
    +      },
    +      "entryurl": "https://cards.acme.com/finance/a2a-card.json",
    +      "aicatalog_trustmanifest": {
    +        "issuedAt": "2025-01-01T00:00:00Z",
    +        "subject": {
    +          "mediaType": "application/a2a-agent-card+json",
    +          "digest": "sha256:aaa111..."
    +        },
    +        "signature": "eyJhbGciOiJFUzI1NiJ9..detached-JWS.."
    +      }
    +    },
    +    "finance-mcp": {
    +      "entryid": "finance-mcp",
    +      "xid": "/aicatalogs/acme-services/entries/finance-mcp",
    +      "name": "Acme Finance MCP Server",
    +      "contenttype": "application/mcp-server-card+json",
    +      "labels": {
    +        "ai-catalog.identifier": "urn:acme:server:finance-mcp"
    +      },
    +      "entryurl": "https://cards.acme.com/finance/mcp-server.json"
    +    }
    +  }
    +}
    +
    +
    +
    +

    Content Integrity and Signing

    +

    Because xRegistry has no native content-addressing or signature +primitive, this binding does not delegate those invariants: the Trust +Manifest's detached JWS and subject.digest remain the source of truth, +verified against the served Resource document during unpacking — the same +model as plain-HTTP distribution. An implementation MAY additionally +expose the digest as an extension attribute for discovery convenience, but +that copy is advisory; the Trust Manifest remains authoritative.

    +
    +

    Mapping to MCP Registry server.json

    This appendix describes how the MCP Registry server.json format @@ -1830,7 +2367,7 @@ Instead, it provides the discovery and trust layer that server.json does not address.

    -
    +

    Conceptual Mapping

    @@ -1850,7 +2387,7 @@ - + @@ -1921,6 +2458,7 @@ reflects the Registry format:

    {
       "identifier": "urn:air:anonymous.modelcontextprotocol.io:mcp:brave-search",
    +  "displayName": "Brave Search",
       "version": "1.0.2",
       "type": "application/mcp-server-card+json",
       "url": "https://registry.modelcontextprotocol.io/servers/brave-search/server.json",
    @@ -1980,6 +2518,7 @@
       "entries": [
         {
           "identifier": "urn:air:anonymous.modelcontextprotocol.io:mcp:brave-search",
    +      "displayName": "Brave Search",
           "version": "1.0.2",
           "type": "application/mcp-server-card+json",
           "url": "https://registry.modelcontextprotocol.io/servers/brave-search/server.json",
    @@ -1988,6 +2527,7 @@
         },
         {
           "identifier": "urn:air:modelcontextprotocol.github.io:mcp:filesystem",
    +      "displayName": "Filesystem",
           "version": "1.0.2",
           "type": "application/mcp-server-card+json",
           "url": "https://registry.modelcontextprotocol.io/servers/filesystem/server.json",
    @@ -1996,6 +2536,7 @@
         },
         {
           "identifier": "urn:air:example.github.io:mcp:weather-mcp",
    +      "displayName": "Weather",
           "version": "0.5.0",
           "type": "application/mcp-server-card+json",
           "url": "https://registry.modelcontextprotocol.io/servers/weather/server.json",
    @@ -2073,6 +2614,7 @@
     server can reference the Server Card as its artifact content:

    {
       "identifier": "urn:air:example.com:mcp:finance-server",
    +  "displayName": "Acme Finance MCP Server",
       "type": "application/mcp-server-card+json",
       "url": "https://api.acme-corp.com/.well-known/mcp/server-card.json",
       "description": "MCP server for financial data and trading tools",
    @@ -2142,7 +2684,7 @@
         README.md
     
    -
    +

    Conceptual Mapping

    titleStays in the artifact (server.json carries its own title); entry displayName is omitted unless the artifact lacks a nameEntry displayName
    description
    @@ -2174,7 +2716,7 @@ - + @@ -2255,6 +2797,7 @@ "entries": [ { "identifier": "urn:claude-plugin:anthropic:agent-sdk-dev", + "displayName": "agent-sdk-dev", "type": "application/vnd.anthropic.claude-plugin+json", "url": "https://github.com/anthropics/claude-plugins-official/tree/main/plugins/agent-sdk-dev", "description": "Development kit for working with the Claude Agent SDK", @@ -2269,6 +2812,7 @@ }, { "identifier": "urn:claude-plugin:adspirer:ads-agent", + "displayName": "adspirer-ads-agent", "type": "application/vnd.anthropic.claude-plugin+json", "url": "https://github.com/amekala/adspirer-mcp-plugin.git", "description": "Cross-platform ad management for Google Ads, Meta Ads, TikTok Ads, and LinkedIn Ads.", @@ -2289,6 +2833,7 @@ }, { "identifier": "urn:claude-plugin:aikido:security", + "displayName": "aikido", "type": "application/vnd.anthropic.claude-plugin+json", "url": "https://github.com/AikidoSec/aikido-claude-plugin.git", "description": "Aikido Security scanning — SAST, secrets, and IaC vulnerability detection.", @@ -2333,6 +2878,7 @@ "entries": [ { "identifier": "urn:claude-plugin:anthropic:example-plugin:mcp", + "displayName": "Example Plugin MCP Server", "type": "application/mcp-server-card+json", "url": "https://github.com/anthropics/claude-plugins-official/blob/main/plugins/example-plugin/server-card.json" },
    Plugin nameEntry identifier (derived as URN); the plugin manifest carries its own name, so entry displayName is omittedEntry displayName and identifier (derived as URN)
    Plugin description