ext-server-card/docs/discovery.md
Tadas Antanavicius e42749bfc2
docs(discovery): adopt AI Catalog urn:air: identifier convention (ADR 0015) (#31)
## 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>
2026-06-19 13:17:11 +01:00

14 KiB

Discovery

Protocol Revision: draft

MCP defines a discovery mechanism that enables clients to find available MCP servers on a domain without prior configuration. This mechanism complements the lifecycle handshake by answering where to connect, before the protocol establishes how to communicate.

MCP Catalog

An MCP Catalog is a JSON document published by an organization to advertise the MCP Server Cards relevant to its services.

The catalog MAY reference servers on different domains than the catalog itself — for example, acme.org/.well-known/... MAY advertise servers operated by mcp-server-host-saas.com on Acme's behalf. Clients can fetch this document to discover servers and then retrieve individual Server Cards for connection details.

The MCP Catalog format is a minimal, MCP-scoped subset of the AI Catalog specification. This alignment ensures that MCP Catalog entries can be used as-is within a full AI Catalog document, enabling a smooth migration path when the cross-protocol AI Catalog standard is finalized.

Well-Known URI

Organizations offering services accessible via MCP SHOULD publish an MCP Catalog at the domain users associate with the service. The MCP Catalog should live at:

/.well-known/mcp/catalog.json

This endpoint:

  • MUST be accessible via HTTPS (HTTP MAY be supported for local/development use)
  • MUST include appropriate CORS headers (see CORS Requirements)
  • SHOULD include appropriate caching headers (see Caching)

Catalog Format

An MCP Catalog document is a JSON object that MUST contain the following members:

Member Type Required Description
specVersion string Yes The version of the MCP Catalog format (currently "draft")
entries array Yes An array of Catalog Entry objects. This array MAY be empty.

Catalog Entry

Each entry in the entries array describes a single MCP server and MUST contain:

Member Type Required Description
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
url string Yes URL where the full Server Card can be retrieved

The identifier is a logical discovery name that follows the AI Catalog domain-anchored URN convention standardized in ADR 0015:

urn:air:{publisher}:{namespace}:{name}

The segments are:

  • publisher — the publisher's domain (forward DNS), e.g. example.com. ADR 0015 anchors the identifier on this domain.
  • namespace — optional, populate if you wish in accordance with the AI Catalog specification
  • name — the server's name suffix, i.e. 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. Anchoring the identifier on the publisher's domain keeps it globally unique and stable across infrastructure changes, and lets an MCP Catalog entry be indexed as-is within a full AI Catalog document.

Example: Single Server

A domain hosting a single MCP server, using only the required fields:

{
  "specVersion": "draft",
  "entries": [
    {
      "identifier": "urn:air:example.com:weather",
      "displayName": "Weather Service",
      "mediaType": "application/mcp-server-card+json",
      "url": "https://example.com/mcp/server-card"
    }
  ]
}

Example: Multiple Servers

A domain hosting several MCP servers, each with its own server card:

{
  "specVersion": "draft",
  "entries": [
    {
      "identifier": "urn:air:acme.com:code-review",
      "displayName": "Code Review Assistant",
      "mediaType": "application/mcp-server-card+json",
      "url": "https://acme.com/code-review/server-card"
    },
    {
      "identifier": "urn:air:acme.com:docs-search",
      "displayName": "Documentation Search",
      "mediaType": "application/mcp-server-card+json",
      "url": "https://acme.com/docs-search/server-card"
    },
    {
      "identifier": "urn:air:acme.com:ci-cd",
      "displayName": "CI/CD Pipeline",
      "mediaType": "application/mcp-server-card+json",
      "url": "https://acme.com/ci-cd/server-card"
    }
  ]
}

Client Discovery Flow

Clients performing domain-level discovery SHOULD follow this procedure:

flowchart TD
    A[Client wants to discover MCP servers on example.com] --> B[Fetch /.well-known/mcp/catalog.json]
    B --> C{Valid catalog returned?}
    C -->|Yes| D[Parse entries array]
    C -->|No| E[Discovery unavailable for this domain]
    D --> F[For each entry, fetch server card from url]
    F --> G[Use server card to configure connection]
  1. Fetch https://{domain}/.well-known/mcp/catalog.json
  2. If a valid MCP Catalog is returned, iterate over the entries array
  3. For each entry, retrieve the server card from the entry's url, expressing the Server Card media type via the Accept header (see Server Card Location)
  4. Use the server card metadata to configure and establish an MCP connection

Clients SHOULD validate that each entry has mediaType set to application/mcp-server-card+json and ignore entries with unrecognized media types.

MCP Server Cards

An MCP Server Card is a JSON document that describes a single MCP server — its identity and connection details. Server Cards use the media type application/mcp-server-card+json.

Server Cards do not enumerate primitives (tools, resources, prompts); those remain subject to runtime listing via the protocol's standard list operations.

A Server Card includes:

  • name — A unique identifier for the server in reverse DNS format (e.g., com.example/weather)
  • Connection details — Transport type and endpoint URL
  • Metadata — Human-readable name, description, and version

For the full Server Card specification, see SEP-2127: MCP Server Cards.

Consistency with Runtime Behavior

A Server Card is fetched before the client connects, so its contents are unverified when read. A Server Card SHOULD accurately reflect the server's runtime behavior: the values a client observes once connected — the serverInfo (name, version) and supportedVersions from server/discover, the transport served at each remotes[] endpoint, and descriptive fields (title, description, icons) — SHOULD NOT contradict the equivalent values declared in the Server Card.

As with the deliberately omitted primitives (tools, resources, prompts), a static manifest can drift from runtime, so even the fields a Server Card does declare are advisory rather than binding. Accordingly:

  • Clients MUST NOT treat Server Card contents as authoritative for security or access-control decisions.
  • Clients SHOULD verify a Server Card's claims against the live connection, preferring the runtime values where the two disagree.

Server Card Location

The Catalog is the discovery entrypoint, and every Catalog Entry already carries the url where its Server Card can be retrieved. Clients therefore never need to guess a Server Card's location — they follow the url the Catalog gives them. As a result, a Server Card MAY be hosted at any unreserved URI.

To give servers a predictable default, MCP reserves one location:

MCP Servers MAY host their Server Card at GET <streamable-http-url>/server-card, which we reserve for this purpose, though any unreserved URI (on any domain) is valid. MCP Servers SHOULD respect the application/mcp-server-card+json 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 application/mcp-server-card+json media type.

Concretely:

  • A client requesting a Server Card SHOULD send Accept: application/mcp-server-card+json on the GET request. (Accept is the representation-negotiation header for a GET; the server echoes the negotiated type back in the response Content-Type.)
  • The /server-card suffix is appended to the server's streamable-HTTP URL, not to the domain root. A server that lives at https://host/mcp therefore naturally yields https://host/mcp/server-card — you get path-namespacing for free without inventing a separate convention.

Alternatives considered

The following placements were considered and not recommended:

  • A .well-known URI (e.g., /.well-known/mcp/server-card). .well-known is for site-wide metadata, whereas an individual server's card is application-level metadata. Because the Catalog is the discovery entrypoint and already provides each card's url, hosting the card under .well-known adds no value — the card can live anywhere the Catalog points. (Note: .well-known remains correct for the Catalog itself at /.well-known/mcp/catalog.json and for OAuth metadata such as /.well-known/oauth-protected-resource — those are genuinely site-wide. This change applies only to the single-server Server Card.)
  • The bare streamable-HTTP endpoint (GET <streamable-http-url> with no suffix). In the Streamable HTTP transport a GET on the MCP endpoint already has a reserved meaning — it opens the SSE stream. Serving the card there overloads that endpoint and forces content negotiation to disambiguate "give me the card" from "open the stream." This remains spec-allowed (any unreserved URI is valid) but is explicitly not recommended; avoiding the overload of the connection-establishing endpoint is the primary motivation for reserving a distinct /server-card suffix.
  • Nesting under a domain-root /mcp/ (e.g., /mcp/server-card). In MCP, /mcp denotes the transport endpoint itself (canonical-URI examples: https://mcp.example.com/mcp, https://mcp.example.com/server/mcp). There is no precedent for /mcp/ as a metadata sub-namespace relative to a server URL. Nesting under /mcp/ collides conceptually with "the JSON-RPC endpoint" and creates ambiguity about whether the path is relative to the server URL or the domain root. (This is distinct from a server that simply happens to live at https://host/mcp: there, https://host/mcp/server-card is just <streamable-http-url> + /server-card — the recommended convention — not a domain-root /mcp/ metadata namespace.)

Relationship to AI Catalog

The MCP Catalog is designed as a transitional mechanism. The AI Catalog specification defines a cross-protocol discovery standard (/.well-known/ai-catalog.json) capable of indexing MCP servers, A2A agents, and other AI artifacts.

MCP Catalog entries are structurally compatible with AI Catalog entries. When the AI Catalog standard is finalized and adopted by the MCP steering committee:

  1. Domains MAY serve both /.well-known/mcp/catalog.json and /.well-known/ai-catalog.json during a transition period
  2. MCP Catalog entries can be included directly in an AI Catalog document without modification
  3. Domains that want richer metadata (trust manifests, publisher identity, collections) can adopt the full AI Catalog format

Security Considerations

Information Disclosure

MCP Catalogs are publicly accessible by design. Catalog entries MUST NOT include sensitive information such as:

  • Authentication credentials or tokens
  • Internal network topology or private endpoints
  • Proprietary business logic

Server Card Accuracy

A Server Card is consumed before the client connects, so an inaccurate one — stale or deliberately crafted — is a mild confusion or downgrade vector: one that overstates transport or protocol-version support, or misrepresents the server's identity, can steer a client toward a weaker configuration or the wrong server before it observes the actual server/discover response. This makes the consistency requirement partly a security property, not merely a matter of correctness. The normative protections live in Consistency with Runtime Behavior: clients do not treat a Server Card as authoritative and reconcile it against the live connection.

CORS Requirements

Discovery endpoints MUST include appropriate CORS headers to allow browser-based clients:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
Access-Control-Allow-Headers: Content-Type

This is safe because MCP Catalogs contain only public metadata and are read-only.

Caching

Servers SHOULD include caching headers to reduce unnecessary requests:

Cache-Control: public, max-age=3600

Transport Security

MCP Catalogs MUST be served over HTTPS (TLS 1.2 or later) in production. HTTP MAY be used for local development only.

Denial of Service

MCP Servers SHOULD implement rate limiting on their Server Card endpoint to prevent abuse.

MCP Clients SHOULD respect Cache-Control headers and avoid unnecessary polling.