docs(discovery): drop displayName from MCP Catalog entries (#14) (#39)

## 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:
https://github.com/Agent-Card/ai-catalog/pull/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 <peter@tadasant.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tadas Antanavicius 2026-07-13 12:23:13 -07:00 • committed by GitHub
commit 72793bb203
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -50,12 +50,24 @@ An MCP Catalog document is a JSON object that MUST contain the following members
Each entry in the `entries` array describes a single MCP server and MUST contain: Each entry in the `entries` array describes a single MCP server and MUST contain:
| Member | Type | Required | Description | | Member | Type | Required | Description |
| :------------ | :----- | :------- | :------------------------------------------------------------------------------------ | | :----------- | :----- | :------- | :------------------------------------------------------------------------------------ |
| `identifier` | string | Yes | A logical discovery URN for this server (e.g., `urn:air:example.com:weather`) | | `identifier` | string | Yes | A logical discovery URN for this server (e.g., `urn:air:example.com:weather`) |
| `displayName` | string | Yes | A human-readable name for the server | | `mediaType` | string | Yes | The media type of the referenced artifact. MUST be `application/mcp-server-card+json` |
| `mediaType` | string | Yes | The media type of the referenced artifact. MUST be `application/mcp-server-card+json` | | `url` | string | Yes | URL where the full [Server Card](#mcp-server-cards) can be retrieved |
| `url` | string | Yes | URL where the full [Server Card](#mcp-server-cards) can be retrieved |
An MCP Catalog entry carries no human-readable-name field. Every entry references a
[Server Card](#mcp-server-cards), and the Server Card's `title` is the source of truth for
a server's name — so a client reads the name from the card at `url` rather than from the
catalog entry. Carrying the name in the entry as well would only duplicate it and risk it
drifting out of sync with the card.
The [AI Catalog](https://github.com/Agent-Card/ai-catalog) specification defines an
OPTIONAL `displayName` on its catalog entries (see
[ADR 0016](https://github.com/Agent-Card/ai-catalog/pull/39)). Because that field is
optional upstream, an MCP Catalog entry that omits it is still a valid drop-in subset of
an AI Catalog entry: MCP simply does not use `displayName`, deferring in every case to the
referenced Server Card's `title`.
The `identifier` is a **logical discovery name** that follows the The `identifier` is a **logical discovery name** that follows the
[AI Catalog](https://github.com/Agent-Card/ai-catalog) domain-anchored URN convention [AI Catalog](https://github.com/Agent-Card/ai-catalog) domain-anchored URN convention
@ -80,7 +92,7 @@ be indexed as-is within a full AI Catalog document.
### Example: Single Server ### Example: Single Server
A domain hosting a single MCP server, using only the required fields: A domain hosting a single MCP server:
```json ```json
{ {
@ -88,7 +100,6 @@ A domain hosting a single MCP server, using only the required fields:
"entries": [ "entries": [
{ {
"identifier": "urn:air:example.com:weather", "identifier": "urn:air:example.com:weather",
"displayName": "Weather Service",
"mediaType": "application/mcp-server-card+json", "mediaType": "application/mcp-server-card+json",
"url": "https://example.com/mcp/server-card" "url": "https://example.com/mcp/server-card"
} }
@ -106,19 +117,16 @@ A domain hosting several MCP servers, each with its own server card:
"entries": [ "entries": [
{ {
"identifier": "urn:air:acme.com:code-review", "identifier": "urn:air:acme.com:code-review",
"displayName": "Code Review Assistant",
"mediaType": "application/mcp-server-card+json", "mediaType": "application/mcp-server-card+json",
"url": "https://acme.com/code-review/server-card" "url": "https://acme.com/code-review/server-card"
}, },
{ {
"identifier": "urn:air:acme.com:docs-search", "identifier": "urn:air:acme.com:docs-search",
"displayName": "Documentation Search",
"mediaType": "application/mcp-server-card+json", "mediaType": "application/mcp-server-card+json",
"url": "https://acme.com/docs-search/server-card" "url": "https://acme.com/docs-search/server-card"
}, },
{ {
"identifier": "urn:air:acme.com:ci-cd", "identifier": "urn:air:acme.com:ci-cd",
"displayName": "CI/CD Pipeline",
"mediaType": "application/mcp-server-card+json", "mediaType": "application/mcp-server-card+json",
"url": "https://acme.com/ci-cd/server-card" "url": "https://acme.com/ci-cd/server-card"
} }