Skip to content

spec: make Catalog Entry displayName optional (not required) (ADR 0016)#39

Merged
tadasant merged 5 commits into
Agent-Card:mainfrom
tadasant:spec/remove-catalog-entry-displayname
Jun 26, 2026
Merged

spec: make Catalog Entry displayName optional (not required) (ADR 0016)#39
tadasant merged 5 commits into
Agent-Card:mainfrom
tadasant:spec/remove-catalog-entry-displayname

Conversation

@tadasant

@tadasant tadasant commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

What this proposes

Make displayName OPTIONAL on the Catalog Entry rather than required — i.e. move it from the required members of a Catalog Entry (ai-catalog.md §Catalog Entry) into the OPTIONAL members, drop it from the Minimal Catalog (Level 1) conformance requirement, and add guidance that it SHOULD be set only when the referenced artifact does not already carry its own canonical human-readable name.

The intent: when an entry points at an artifact that names itself (an A2A Agent Card, an MCP Server Card), the artifact is the single source of truth and the entry shouldn't duplicate the name. When an entry points at something opaque that has no embedded name (a raw dataset, a model blob, a skill bundle), the entry is the only place a human-readable name can live — so the field stays available for exactly that case.

This change deliberately does not touch displayName on the HostInfo or Publisher objects — those name the catalog host and the publishing org respectively, which is genuinely catalog-authored metadata with no other home.

Alternative considered: removing the field entirely

My first instinct was to remove displayName from the entry level altogether and always defer to the artifact, but I'm not suggesting it because that would mean opaque artifacts have nowhere else to put a name. examples/ai-catalog.json has an application/parquet dataset entry; a Parquet file, a model blob, or a skill .zip doesn't embed a self-describing display name the way a card does. Removing the field outright would leave those artifacts nameless in a catalog. So "optional, with guidance" is the proposal; "remove entirely" is the rejected alternative.

Why make it optional — the duplication / drift problem

A Catalog Entry already points at the full artifact via url or data. For the card-shaped artifact types this spec calls out by media type, the human-readable name is already present in the artifact itself:

  • A2A Agent Cardname is a REQUIRED, human-readable field. From the A2A protobuf spec (specification/a2a.proto, message AgentCard):
    // A human readable name for the agent.
    // Example: "Recipe Agent"
    string name = 1 [(google.api.field_behavior) = REQUIRED];
  • MCP Server Card — already carries a human-readable display name. In the Server Card schema, name is a reverse-DNS machine identifier (^[a-zA-Z0-9.-]+/[a-zA-Z0-9._-]+$), while title is documented as "Optional human-readable title or display name for the MCP server", and description (required) is human-readable too.

So for the two flagship artifact types, requiring displayName on the entry means every catalog publisher copies a value that already exists in the document the client is about to fetch, and then has to keep the two in sync forever. When they drift — and over time they will — a consumer has two conflicting human-readable names for the same thing and no principled way to pick. Making the field optional (and recommending omission for self-naming artifacts) keeps the name fresh and authoritative at its source, while the entry stays a thin pointer.

What's in the diff

  • Normative: displayName moved from required → OPTIONAL members, with a SHOULD-guidance paragraph (set it only when the artifact has no canonical name; omit it for self-naming cards; the artifact's own name wins on conflict). Removed from the Minimal Catalog (Level 1) required-at-minimum list.
  • Examples (all of them, for internal consistency): card-backed entries (A2A cards, MCP Server Cards, registry server.json, plugin manifests) now omit displayName; opaque entries (the application/parquet dataset, application/agentskill+zip skill bundles) and nested application/ai-catalog+json entries — which have no embedded canonical name — keep it. HostInfo/Publisher displayName untouched. The field still exists, so the class diagram and the "logical format" vocabulary lists are unchanged.
  • Conceptual-mapping tables (MCP registry, Claude plugins) updated so the human-readable name maps to the artifact, with entry displayName framed as the fallback for nameless artifacts.

Some history (for transparency)

As far as I can reconstruct from the public record, displayName was required from its first appearance rather than as the outcome of an explicit "should this be mandatory?" debate:

  • It entered the draft as name in commit 0271c14 (2026-03-31), already under "It MUST contain the following members."
  • It was renamed namedisplayName in 1e8c70c9 per the AI Actor Naming Standard (PR #19), still required, and shipped via PR #27.

I went looking for a written rationale for the mandatory status specifically — across the ADRs (0001–0013), issues, and discussions — and couldn't find one. The closest articulations of the field's purpose are PR #19 ("a human-readable name used for discovery in UIs … not required to be unique") and ADR 0013 framing the catalog as "the authoring and discovery format — a human-readable JSON document." I might simply be missing the discussion where requiring it was decided — if there's prior context I've overlooked, please point me to it, since it likely bears directly on the tradeoff.

Counter-argument to landing this

The strongest argument I can construct for keeping it required is browsing UX: a UI that renders a list of N artifacts shouldn't have to fetch N separate cards just to show names, so requiring displayName on the entry makes the catalog self-describing for a cheap list view.

However, that's a steep trade-off for a permanent duplication/sync cost; one we'd like to avoid making on the MCP side. I'm not sure I'm convinced that UIs of AI Catalogs will be a major use case of AI Catalog (please correct me if you foresee otherwise, would love to understand the use case), and the optional form still lets a publisher populate displayName on every entry if they want the self-describing list view. It just doesn't force the card-backed entries to carry a redundant copy.

If there's a use case beyond browsing that makes the field load-bearing enough to mandate, would love to understand.

@tadasant
tadasant force-pushed the spec/remove-catalog-entry-displayname branch from e23aed1 to ede6f35 Compare June 8, 2026 01:26
Move `displayName` from the required members of a Catalog Entry to the
OPTIONAL members, and drop it from the Minimal Catalog (Level 1)
conformance requirement. Add guidance that `displayName` SHOULD be set
only when the referenced artifact does not already carry its own
canonical human-readable name (e.g. a raw dataset, model blob, or skill
bundle), and SHOULD be omitted when the artifact carries one (A2A Agent
Card `name`, MCP Server Card `title`) so the catalog does not duplicate a
value that can drift out of sync. When both are present and disagree,
the artifact's own name is authoritative.

- Examples: card-backed entries (A2A cards, MCP Server Cards, registry
  server.json, plugin manifests) omit displayName; opaque artifacts
  (parquet datasets, skill zips) and nested catalogs keep it, since they
  have no embedded canonical name. HostInfo and Publisher displayName are
  unaffected -- they name the host/publisher org.
- Conceptual-mapping tables (MCP registry, Claude plugins) updated so the
  human-readable name maps to the artifact, with displayName as the
  fallback only when the artifact lacks a name.

An earlier draft of this change removed `displayName` from the entry
level entirely; that was dismissed because opaque artifacts (e.g. the
Parquet dataset in examples/ai-catalog.json) have no other home for a
human-readable name. Draft for discussion -- see PR description.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Signed-off-by: Tadas Antanavicius <[email protected]>
@tadasant
tadasant force-pushed the spec/remove-catalog-entry-displayname branch from ede6f35 to 0798bcc Compare June 8, 2026 02:27
@tadasant tadasant changed the title spec: drop displayName from the Catalog Entry level (draft for discussion) spec: make Catalog Entry displayName optional (not required) Jun 8, 2026
@tadasant
tadasant marked this pull request as ready for review June 8, 2026 04:13
@muscariello
muscariello requested review from a team, darrelmiller, dsp-ant, mindpower and muscariello and removed request for muscariello June 9, 2026 21:07
@muscariello muscariello moved this to In Progress in AI Catalog Jun 11, 2026
Documents the decision already implemented by this PR: displayName moves
from a REQUIRED to an OPTIONAL member of a Catalog Entry and is dropped
from the Minimal Catalog (Level 1) required-at-minimum set. Pairs each
substantive spec PR with an ADR, matching ADR-0014 (Agent-Card#37) / ADR-0015 (Agent-Card#36).
Status is Proposed pending the 2026-06-18 working-group call.

Signed-off-by: Tadas Antanavicius <[email protected]>
Co-Authored-By: Claude Opus 4.8 <[email protected]>
@tadasant tadasant changed the title spec: make Catalog Entry displayName optional (not required) spec: make Catalog Entry displayName optional (not required) (ADR 0016) Jun 18, 2026
Tadas Antanavicius and others added 2 commits June 18, 2026 22:37
Refines the displayName-optional change with the consumer-vs-producer
guidance agreed at the 2026-06-18 AI Catalog TSC working-group call.

- Catalog Entry displayName is now an explicit *master override*: when a
  publisher sets it, it is authoritative for display and a consumer
  renders it as given, even if it differs from the artifact's own name.
- Add a "Resolving an Artifact's Display Name" section with the consumer
  fallback order the WG agreed on: displayName -> the referenced
  artifact's own canonical name (A2A `name` / MCP Server Card `title`)
  -> the trailing segment of the `identifier` URN (the last-segment hack
  raised on the call).
- Steer name resolution to ingestion-time caching rather than
  render-time dereferencing, reflecting the point that registries
  already normalize/cache at ingestion.
- Update ADR-0016 to match.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
…isplayName')

The lead-in said 'For an entry without displayName' but step (1) is
'displayName if present' — reword to the general rendering case.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@darrelmiller

Copy link
Copy Markdown
Contributor

My perspective on this is that with the identifier and description property, a registry can synthesize a friendly display name for their registry. Picking the last segment of the URN identifier would likely be a reasonable substitute

@mindpower

Copy link
Copy Markdown
Member

Agree that for browsing/indexing, the displayName is useful to avoid the traffic to the A2A/MCP service, but it doesn't need to be a mandatory field. Making it optional makes perfect sense and should work well.

…ntry-displayname

# Conflicts:
#	specification/ai-catalog.md
@tadasant
tadasant merged commit 6a75c6e into Agent-Card:main Jun 26, 2026
4 checks passed
@github-project-automation github-project-automation Bot moved this from In Progress to Done in AI Catalog Jun 26, 2026
tadasant pushed a commit that referenced this pull request Jun 30, 2026
… ADR-0016)

ADR-0016 (#39) made displayName OPTIONAL on Catalog Entry; the prose, the
Level-1 conformance definition, and the ADR all agree, but the normative
CDDL still listed displayName: text as required. This aligns the CDDL.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
tadasant pushed a commit to modelcontextprotocol/experimental-ext-server-card that referenced this pull request Jul 7, 2026
Rather than making the MCP Catalog entry field displayName optional, drop
it from the MCP Catalog entirely. Every MCP Catalog entry references a
Server Card, and the Server Card's `title` is the source of truth for the
server's human-readable name. Documenting displayName on the entry — even
as optional — only invites publishers to duplicate a name that already
lives in the card and risks it drifting out of sync.

An MCP Catalog entry now requires only identifier, mediaType, and url. The
doc notes that AI Catalog defines an OPTIONAL displayName (ADR 0016,
Agent-Card/ai-catalog#39); because it is optional upstream, an MCP entry
that omits it remains a valid drop-in subset of an AI Catalog entry.

Removes displayName from the field table and from all catalog examples.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
SamMorrowDrums pushed a commit to modelcontextprotocol/experimental-ext-server-card that referenced this pull request Jul 13, 2026
## Summary

Removes the `displayName` field from **MCP Catalog** entries in
`docs/discovery.md`. An MCP Catalog entry now requires only
`identifier`, `mediaType`, and `url` — there is no human-readable-name
field on the entry at all.

Resolves #14.

## Rationale

Issue #14 originally proposed making `displayName` **optional**, gated
on the upstream AI Catalog spec doing the same. That gate resolved —
**Agent-Card/ai-catalog#39** ("make Catalog Entry displayName optional
(not required), ADR 0016") **merged** 2026-06-26:
Agent-Card/ai-catalog#39.

But for the **MCP-scoped** catalog we can go one step further and drop
the field entirely, which is cleaner:

- Every MCP Catalog entry references a **Server Card**, and the Server
Card's `title` is the source of truth for the server's human-readable
name. A client fetches that card anyway (the discovery flow retrieves
the card at `url` for connection details), so it can read the name
straight from the card.
- Documenting `displayName` on the entry — even as optional — only
invites publishers to duplicate a name that already lives in the card,
where it can drift out of sync. This is the general-AI-Catalog concern
(some non-MCP/non-A2A artifacts have no baked-in name) not applying to
us: an MCP entry *always* points at a card that carries its own `title`.

This still **preserves the drop-in-subset guarantee**. AI Catalog makes
`displayName` optional (ADR 0016), so an MCP Catalog entry that omits it
remains valid as-is inside a full AI Catalog document. The two specs
agree; MCP simply declines to use the field and defers to the Server
Card's `title`. The doc states this explicitly so the intentional
omission is clear rather than looking like an oversight.

## What changed (`docs/discovery.md` only)

- **Catalog Entry table**: removed the `displayName` row. Entry now
lists only `identifier`, `mediaType`, `url` (all required).
- **Prose**: replaced the required/optional language with a paragraph
explaining that the entry carries no name field and clients read the
name from the referenced Server Card's `title`, plus a paragraph
documenting the AI-Catalog compatibility (optional `displayName`
upstream → MCP entry is still a drop-in subset).
- **Examples**: removed `displayName` from the single-server example and
from all three entries in the multiple-servers example.

Docs/spec-text only. No TypeScript or JSON Schema changes were needed —
the catalog entry shape lives entirely in `discovery.md`;
`schema.ts`/`schema.json` describe the Server Card itself and never
encoded the catalog entry's `displayName`, so there was no schema
coupling to update.

## Verification

- [x] `npm run check` passes (schema.json up to date; `tsc --noEmit`
clean) — docs-only diff
- [x] `npm run validate` passes (all 7 Server Card examples validate as
expected)
- [x] `npm run format:check` clean for `docs/discovery.md` (ran
`prettier --write`; remaining warnings are AO-injected untracked files
not present in CI)
- [x] Whole-file `displayName` sweep: the field is gone from the table
and every example; the only remaining mentions are the deliberate
AI-Catalog compatibility note explaining why MCP omits it — no
contradictory "required"/"optional-field" language remains
- [x] CI green on this PR (build, CodeQL, Analyze — see checks)
- [x] Independent fresh-eyes review performed via in-session subagent;
feedback addressed

---------

Co-authored-by: tadasant <[email protected]>
Co-authored-by: Claude Opus 4.8 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants