## What
Adapts the **MCP Catalog Entry** in `docs/discovery.md` to [AI Catalog
PR #37](https://github.com/Agent-Card/ai-catalog/pull/37) / ADR 0014,
which renames the `CatalogEntry.mediaType` member to **`type`** and
reframes its description as an open-text *type identifier* rather than a
strict IANA media type.
Changes (docs-only, `docs/discovery.md`):
- Renames the `mediaType` member to `type` in the Catalog Entry table.
- Updates the member description to mirror ADR 0014: "An identifier
specifying the type of the referenced artifact."
- Updates the `type` key in all four example catalog entries.
- Updates the client-validation prose (`type` set to … / "ignore entries
with unrecognized types").
## Rebase / conflict resolution
This branch was rebased onto the current `main` to resolve a merge
conflict in `docs/discovery.md`. The conflict came from changes that
landed on `main` after this branch was cut:
- **#31** — `urn:air:` identifier adaptation (ADR 0015). **Preserved.**
- **#39 / #14** — removal of the `displayName` field from MCP Catalog
entries. **Preserved** — this PR does **not** reintroduce `displayName`;
it only renames the field `mediaType` → `type` on top of main's current
structure.
The resolved diff is exactly the `mediaType` → `type` rename (table row,
four examples, validation prose) applied on top of main — nothing from
either side's intent was dropped.
## Scope decision — value deliberately kept as
`application/mcp-server-card+json`
This PR renames the **field only**. The value stays
`application/mcp-server-card+json` and is **not** changed to ADR 0014's
known-type `application/mcp-server+json`. Rationale:
- ADR 0014 explicitly makes `type` an **open-text** format ("any string
value is accepted"); `application/mcp-server+json` is a non-binding
"known type," and ecosystem types are "governed externally" (i.e., by
MCP). So keeping a more precise MCP-governed value is compatible with
ADR 0014, not a contradiction.
- This repo **deliberately** chose `application/mcp-server-card+json`
over `application/mcp-server+json` (issue #9 / PR #18) to avoid
colliding with the MCP Registry's `server.json` concept — a distinction
the README documents in "Relationship to the MCP Registry."
**Flag for maintainers:** AI Catalog's ADR 0014 known-types list uses
`application/mcp-server+json` for MCP. Whether this repo should also
adopt that value (reversing issue #9 / PR #18 and re-introducing the
`server.json` naming collision) is a separate, more consequential
decision and is intentionally **out of scope** here. Happy to file a
cross-repo issue if maintainers want to pursue it.
## What is intentionally NOT changed
- The **Server Card document's own HTTP media type** (`Accept` /
`Content-Type` negotiation, the reserved `/server-card` location prose).
That is a genuine IANA media type, not the renamed catalog field, and
ADR 0014 does not touch it.
- `schema.ts` / `schema.json` — the Server Card schema has no
`mediaType`/`type` member; this convention lives only in the discovery
doc.
## Verification
- [x] Rebased onto latest `main`; merge conflict in `docs/discovery.md`
resolved, preserving both #31 (`urn:air:`) and #39 (`displayName`
removal). PR now reports `MERGEABLE`.
- [x] `npm run check` — `schema.json` up to date, `tsc --noEmit` clean
- [x] `npm run validate` — all 7 examples pass
- [x] `npm run format:check` — `docs/discovery.md` clean, including
markdown table re-alignment
- [x] Verified zero `mediaType` field tokens remain (`git grep
mediaType` → no matches)
- [x] Verified the Server Card HTTP media-type prose was left intact (no
over-reach)
- [x] **CI green** — `build`, `Analyze (actions)`, and `CodeQL` all pass
on the rebased head
([run](https://github.com/modelcontextprotocol/experimental-ext-server-card/actions/runs/29278815978))
- [x] Independent fresh-eyes subagent review: **APPROVE** (rename
complete & correct; no `displayName` reintroduced; value unchanged;
Server Card media-type prose intact; no stray `mediaType`; no conflict
markers)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: tadasant <bob@tadasant.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
## 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>
## What & why
Adopts the AI Catalog **`urn:air:`** identifier-naming convention
standardized in
[Agent-Card/ai-catalog#36](https://github.com/Agent-Card/ai-catalog/pull/36)
(ADR 0015) for this extension's discovery docs.
This repo's only identifier-naming surface is the **MCP Catalog Entry**
in [`docs/discovery.md`](docs/discovery.md). It previously used a
repo-local `urn:mcp:server:<name>` URN. `docs/discovery.md` describes
the MCP Catalog as *"a minimal, MCP-scoped subset of the AI Catalog
specification"* whose entries *"can be used as-is within a full AI
Catalog document"* — a claim the old format contradicted, since the AI
Catalog now standardizes the domain-anchored
`urn:air:{publisher}:{namespace}:{name}` form.
### Changes (doc-only, `docs/discovery.md`)
- Replace the `urn:mcp:server:<name>` convention with the AI Catalog
`urn:air:` form.
- Document the segments for an MCP server:
- **`publisher`** — the publisher's domain (forward DNS), e.g.
`example.com`, matching ADR 0015's framing that the publisher is a
domain.
- **`namespace`** — optional, populated per the AI Catalog specification
(the examples omit it).
- **`name`** — the server-name suffix (the segment after the `/` in the
referenced Server Card's reverse-DNS `name`), e.g. `weather`.
- So a Server Card named `com.example/weather` can be referenced as
`urn:air:example.com:weather`.
- Update all 4 catalog examples accordingly.
### Design notes for reviewers
- **Forward-DNS publisher**, anchored on the publisher's domain per ADR
0015.
- **Server Card schema deliberately untouched.**
`schema.ts`/`schema.json` have **no `identifier`/`identity` field** —
the card carries `name` (reverse-DNS) only — so this is a discovery-doc
change, not a schema change. Keeps the PR minimal and avoids pre-empting
unresolved SEP-2127 discussion.
- **Related open question:** issue #26 ("Remove the MCP Catalog") — this
aligns the identifier format while the MCP Catalog exists and does not
pre-empt that discussion.
## Verification
- [x] **Self-review (fresh-eyes) done.** Ran independent in-process
reviews of the diff across iterations; findings (an
incorrectly-attributed `urn:air:local:` form; reverse- vs forward-DNS
publisher) were addressed.
- [x] **ADR 0015 cross-checked against source** — verified the
`urn:air:{publisher}:{namespace}:{name}` form, the forward-domain
example `urn:air:example.com:...`, and the optional namespace against
the raw `adr/0015-agent-identifier-naming.md` in PR #36.
- [x] **All 4 examples internally consistent** with the documented
mapping; example `url` hosts match the publisher domains.
- [x] **No stale references** — `grep` confirms zero remaining
`urn:mcp:server:` occurrences.
- [x] **Schema untouched & in sync** — `npm run check` → `✓ schema.json
is up to date`; `tsc --noEmit` passes.
- [x] **Examples validate** — `npm run validate` → `All 7 example(s)
passed.`
- [x] **Formatting** — `npm run format:check` (prettier) passes on all
tracked files.
- [x] **CI green** — confirmed on the pushed branch (`build`, `CodeQL`,
`Analyze` all pass).
Local proof:
```
$ npm run check
✓ schema.json is up to date (+ tsc --noEmit, no errors)
$ npm run validate
All 7 example(s) passed.
$ npm run format:check
All matched files use Prettier code style!
```
Documentation-only change; no UI and no runtime/logic behavior to
exercise beyond the schema toolchain above.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: tadasant <bob@tadasant.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Closes#23.
## What
Adds the missing normative requirement that a Server Card's declared
values must not contradict the server's actual runtime behavior. The
schema already encodes the *omission* half of the threat model
(primitives are deliberately excluded because a static manifest drifts
from runtime); this adds the *complementary* requirement for the fields
the card **does** declare.
### `docs/discovery.md`
- **New "Consistency with Runtime Behavior" subsection** under "MCP
Server Cards":
- A Server Card SHOULD accurately reflect the server's actual runtime
behavior. The `serverInfo` (`name`, `version`) and `supportedVersions`
returned by
[`server/discover`](https://modelcontextprotocol.io/specification/draft/server/discover),
plus the transport actually served at each `remotes[]` endpoint (and
descriptive `title`/`description`/`icons`), SHOULD NOT contradict the
equivalent values declared in the Server Card.
- Clients MUST NOT treat Server Card contents as authoritative for
security or access-control decisions, and SHOULD verify claims against
the live connection — the same posture the spec takes toward primitives,
generalized to the declared fields.
- **New "Server Card Accuracy" subsection** under "Security
Considerations": frames an inaccurate (stale or crafted) card as a mild
confusion/downgrade vector, so the consistency requirement is partly a
security property, not just correctness. It is explanatory and points
back to the single normative statement above rather than re-asserting
the MUST NOT.
### `schema.ts`
- Short pointer comment in the `ServerCard` JSDoc referencing the
discovery-doc requirement, complementing the existing
primitives-omission rationale. `schema.json` regenerated via `npm run
generate` in the same commit (CI `check` enforces sync).
RFC 2119 keywords are used consistently with the rest of
`docs/discovery.md`. The runtime reference is phrased around the draft
spec's
[`server/discover`](https://modelcontextprotocol.io/specification/draft/server/discover)
operation — the pre-`initialize` exchange that actually returns
`serverInfo`/`supportedVersions` — rather than SEP-2127's
`DiscoverResultResponse`, which has no term in this repo.
## Security rationale
Because a Server Card is consumed *before* the client connects, an
inaccurate card can steer a client toward a weaker configuration
(downgrade) or a misidentified server (confusion) before it has observed
the server's actual `server/discover` response. Treating the card as
advisory rather than authoritative contains this risk.
## Scope
Small and focused strictly on the card-vs-runtime consistency
requirement. Distinct from #10 (the inverse — primitives the card omits)
and #13/#9/#11/#12/#14/#21 (none touch card-vs-runtime consistency). No
unrelated changes.
## Verification
- [x] `npm run check` passes — `schema.json` is in sync with `schema.ts`
and `tsc --noEmit` is clean
- [x] `npm run validate` passes — all 7 examples validate against the
regenerated schema
- [x] `npm run format` clean — no formatting changes left
- [x] `schema.json` regenerated and committed alongside the `schema.ts`
change (CI `check` enforces this)
- [x] Fresh-eyes review by a separate agent — feedback addressed
(full-term "Server Card" wording for consistency with the rest of the
doc; de-duplicated the MUST NOT so the security section is explanatory
and points to the single normative statement)
- [x] Maintainer review (Sam) — substance approved; applied the
requested brevity pass, tightening both new subsections with no change
to any normative statement
- [x] `server/discover` spec link verified to resolve to a real
draft-spec page documenting `serverInfo` / `supportedVersions`
- [x] CI green on the final commit (`0d0389b`) — build, Analyze
(actions), and CodeQL all pass
This is a docs/comment-only change (no runtime code paths), so the
verification is the build/schema toolchain rather than e2e tests. Local
toolchain output:
```
✓ Generated schema.json
✓ schema.json is up to date (npm run check)
All 7 example(s) passed. (npm run validate)
```
Opened for human review — **not** merged, per repo policy.
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Resolves#12.
## What & why
Moves the **single-server Server Card** off a `.well-known` path. We
reserve `GET <streamable-http-url>/server-card` as the recommended
location while allowing **any unreserved URI** — the Catalog
(`/.well-known/mcp/catalog.json`) is the discovery entrypoint and
already carries each card's `url`, so clients never need to guess where
a card lives.
Adopts wording close to the resolution discussed in #12 (credit: Darrel
Miller's point that `.well-known` is for *site-wide* metadata, not
application-level metadata like an individual server's card; proposed
wording from @SamMorrowDrums and @tadasant):
> MCP Servers MAY host their Server Card at `GET
<streamable-http-url>/server-card`, which we reserve for this purpose,
though any unreserved URI is valid. MCP Servers SHOULD respect the
agreed media type wherever they choose to host it. After a client
identifies a Server Card URL from an AI Catalog or MCP Catalog, it
SHOULD request that URL expressing the Server Card media type.
### Content negotiation
A client fetching a Server Card requests its preferred representation
with the `Accept` header (`Accept: application/mcp-server-card+json`) —
the request-side content-negotiation header for a GET. The server echoes
the type it actually served back in the response's `Content-Type`.
> **Note on media type:** this PR is scoped to *placement* only and does
**not** perform the `application/mcp-server+json` →
`application/mcp-server-card+json` rename — that is handled in a
separate PR. So the two coexist deliberately here:
> - **Pre-existing strings** (catalog-entry description, the four
example `mediaType` values, validation prose, and the "Server Cards use
the media type" line) are left as `application/mcp-server+json`,
untouched, for the rename PR to sweep.
> - **New prose introduced by this PR** (the reserved-location
blockquote and the `Accept`-header example in the "Server Card Location"
section) names the type explicitly as the **post-rename
`application/mcp-server-card+json`**, since the rename PR's diff is
against `main` and would not touch text that doesn't yet exist there.
>
> The temporary mix resolves to a single consistent type once both PRs
land.
## Rationale for `/server-card` (also captured permanently in
`docs/discovery.md` → "Alternatives considered")
- **Not `.well-known`:** site-wide vs. application-level metadata; the
Catalog already provides the `url`, so `.well-known` adds no value for
the card.
- **Not the bare streamable-HTTP endpoint** (`GET <url>` with no
suffix): a GET there already opens the SSE stream in Streamable HTTP.
Hosting the card there overloads the connection-establishing endpoint
and forces content negotiation to disambiguate. Spec-*allowed*,
explicitly **not recommended** — this is the primary motivation for a
distinct suffix.
- **Not domain-root `/mcp/` nesting:** `/mcp` denotes the *transport
endpoint itself* in MCP's canonical-URI examples; there's no precedent
for `/mcp/` as a metadata sub-namespace, and it collides conceptually
with "the JSON-RPC endpoint."
- **Elegant consequence:** because the suffix is appended to the
streamable-HTTP URL, a server at `https://host/mcp` naturally yields
`https://host/mcp/server-card` — path-namespacing for free.
## Scope guardrail
This applies **only to the single-server Server Card**. `.well-known` is
unchanged and remains correct for the **Catalog**
(`/.well-known/mcp/catalog.json`) and OAuth metadata
(`/.well-known/oauth-protected-resource`, etc.) — those are genuinely
site-wide. The doc calls this out explicitly so it doesn't read as
"abandon `.well-known` everywhere."
## Files changed
- **`docs/discovery.md`** — new "Server Card Location" section with the
reserved convention + `Accept`-header guidance; permanent "Alternatives
considered" subsection; rewritten single- and multi-server example URLs
(`https://example.com/mcp/server-card`;
`https://acme.com/code-review/server-card`, `/docs-search/server-card`,
`/ci-cd/server-card`).
- **`schema.ts`** — updated the two `.well-known` doc comments
(`ServerCard` and `Server`) to the new convention.
- **`schema.json`** — regenerated from `schema.ts` (`npm run generate`).
- **`README.md`** — updated the "What is a Server Card?" line to the new
convention, normalizing the pre-existing README-vs-schema `.well-known`
mismatch.
## Verification
- [x] `npm run check` passes (schema.json in sync with schema.ts + `tsc
--noEmit` clean)
- [x] `npm run generate` run and regenerated `schema.json` committed in
the same change
- [x] `npm run validate` passes — all 7 examples validate against the
regenerated schema
- [x] `npm run format` run (prettier clean)
- [x] No single-server-card `.well-known` references remain in
`README.md`, `schema.ts`, `schema.json`, or `docs/discovery.md`
(verified via grep); remaining `.well-known` references are
Catalog/OAuth/the "Alternatives considered" explainer only
- [x] Pre-existing media-type strings left untouched — `git diff
origin/main` shows zero changes to existing
`application/mcp-server+json` strings (rename owned by a separate PR);
only the new placement prose names the post-rename
`application/mcp-server-card+json`
- [x] Examples updated and internally consistent with the new prose
- [x] Fresh-eyes subagent review performed; its one cosmetic finding was
addressed and CI re-confirmed green
- [x] CI green (see checks on this PR)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Agent (Claude) <peter@tadasant.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The 'A Server Card includes:' list in docs/discovery.md mentioned
'Capabilities — Tools, resources, and prompts the server offers',
which contradicts schema.ts and SEP-2127: Server Cards do not
enumerate primitives. Primitives remain subject to runtime listing
via the protocol's standard list operations.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace application/mcp-server+json with application/mcp-server-card+json
in docs/discovery.md to match the AI Catalog specification, which
discovery.md cites as the standard MCP Catalog entries are a subset of.
Fixes#9
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replaces the prior reconstruction with the canonical content from commit
bb3bd697 on SamMorrowDrums/modelcontextprotocol@sammorrowdrums/mcp-catalog-specification,
adapted from .mdx to plain .md (frontmatter and Mintlify components stripped,
content preserved verbatim).
Covers all of tadasant's review feedback: internal MCP Server Cards subsection,
.json well-known path, reverse-DNS identifiers, identifier MUST constraint,
cross-domain advertising language, SHOULD-publish recommendation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add MCP Server Card subsection defining application/mcp-server+json
and link 'MCP Server Cards' references internally rather than to SEP-2127
- Reframe domain hosting language to support cross-host advertising
(catalog MAY reference servers on different web hosts)
- Switch well-known URI to /.well-known/mcp/catalog.json
- Add SHOULD-publish recommendation for organizations offering MCP services
- Make specVersion OPTIONAL with note about pushing AI Catalog to align
- Tighten identifier definition: MUST begin with urn:mcp:server: and the
remainder MUST exactly match the server card's name
- Update all examples to use reverse-DNS identifiers
- Keep Content-Type: application/json for the catalog itself
- Add cross-host advertising example and trust considerations
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add docs/discovery.md defining the MCP Catalog format for config-free
auto-discovery of MCP server cards via a well-known URI. The catalog is
a minimal, MCP-scoped subset of the AI Catalog specification.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>