Use AI Catalog for Server Card discovery (#42)

This commit is contained in:
Sam Morrow 2026-07-20 18:54:05 +02:00 • committed by GitHub
commit 1491bd2471
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 75 additions and 124 deletions

View file

@ -16,6 +16,8 @@ A **Server Card** is a JSON document — hosted at any unreserved URI, with `GET
- Its remote transport endpoints (URLs, headers, variable templates, supported protocol versions) - Its remote transport endpoints (URLs, headers, variable templates, supported protocol versions)
- Optional registry-style extension metadata (`_meta`) - Optional registry-style extension metadata (`_meta`)
Clients can automatically discover Server Cards through [AI Catalog](https://github.com/Agent-Card/ai-catalog) entries advertised on domains present in agentic sessions.
Server Cards intentionally omit primitive listings (tools, resources, prompts) — those remain subject to runtime listing via the protocol's standard list operations. They also intentionally omit local installation metadata — see [Relationship to the MCP Registry](#relationship-to-the-mcp-registry). Server Cards intentionally omit primitive listings (tools, resources, prompts) — those remain subject to runtime listing via the protocol's standard list operations. They also intentionally omit local installation metadata — see [Relationship to the MCP Registry](#relationship-to-the-mcp-registry).
## Relationship to the MCP Registry ## Relationship to the MCP Registry

View file

@ -6,100 +6,65 @@ MCP defines a discovery mechanism that enables clients to find available MCP ser
domain without prior configuration. This mechanism answers _where_ to connect, before any domain without prior configuration. This mechanism answers _where_ to connect, before any
protocol exchange establishes _how_ to communicate. protocol exchange establishes _how_ to communicate.
## MCP Catalog ## AI Catalog
An **MCP Catalog** is a JSON document published by an organization to advertise the An [AI Catalog](https://github.com/Agent-Card/ai-catalog) is a JSON document published by
an organization to advertise AI artifacts, including the
[MCP Server Cards](#mcp-server-cards) relevant to its services. [MCP Server Cards](#mcp-server-cards) relevant to its services.
The catalog MAY reference servers on different domains than the catalog itself — for The catalog MAY reference Server Cards on different domains than the catalog itself — for
example, `acme.org/.well-known/...` MAY advertise servers operated by example, an AI Catalog on `acme.org` MAY advertise servers operated by
`mcp-server-host-saas.com` on Acme's behalf. Clients can fetch this document to discover `mcp-server-host-saas.com` on Acme's behalf. Clients can fetch the catalog to discover
servers and then retrieve individual [Server Cards](#mcp-server-cards) for connection servers and then retrieve individual Server Cards for connection details.
details.
The MCP Catalog format is a minimal, MCP-scoped subset of the
[AI Catalog](https://github.com/Agent-Card/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 ### Well-Known URI
Organizations offering services accessible via MCP SHOULD publish an MCP Catalog at the An AI Catalog MAY be served from any URL. For automated domain-level discovery, hosts MAY
domain users associate with the service. The MCP Catalog should live at: publish one at:
``` ```
/.well-known/mcp/catalog.json /.well-known/ai-catalog.json
``` ```
This endpoint: Clients performing domain-level discovery SHOULD attempt to retrieve this well-known URL.
When served over HTTP, the document SHOULD use the `application/ai-catalog+json` media
type.
- MUST be accessible via HTTPS (HTTP MAY be supported for local/development use) ### Server Card Entries
- MUST include appropriate CORS headers (see [CORS Requirements](#cors-requirements))
- SHOULD include appropriate caching headers (see [Caching](#caching))
### Catalog Format The [AI Catalog specification](https://github.com/Agent-Card/ai-catalog) defines the full
catalog and entry formats. An entry for an MCP Server Card has:
An MCP Catalog document is a JSON object that MUST contain the following members: | Member | Required | Description |
| :----------- | :------- | :---------------------------------------------------------------------------------------------------- |
| `identifier` | Yes | A logical discovery identifier for this server |
| `type` | Yes | MUST be `application/mcp-server-card+json` |
| `url` | One of | URL where the full [Server Card](#mcp-server-cards) can be retrieved |
| `data` | One of | The complete [Server Card](#mcp-server-cards) included inline; exactly one of `url` or `data` is used |
| Member | Type | Required | Description | For open or federated systems, AI Catalog identifiers use the domain-anchored format:
| :------------ | :----- | :------- | :---------------------------------------------------------- |
| `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`) |
| `type` | string | Yes | An identifier specifying the 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 |
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
[AI Catalog](https://github.com/Agent-Card/ai-catalog) domain-anchored URN convention
standardized in [ADR 0015](https://github.com/Agent-Card/ai-catalog/pull/36):
``` ```
urn:air:{publisher}:{namespace}:{name} urn:air:{publisher}:{namespace}:{name}
``` ```
The segments are: For example, a Server Card named `com.example/weather` can use the catalog identifier
`urn:air:example.com:mcp:weather`.
- **`publisher`** — the publisher's domain (forward DNS), e.g. `example.com`. ADR 0015 An entry does not need to repeat the Server Card's human-readable fields. Clients can read
anchors the identifier on this domain. the server's `title`, `description`, and `version` from the card itself, avoiding duplicated
- **`namespace`** — optional, populate if you wish in accordance with the AI Catalog specification values that could drift out of sync.
- **`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 ### Example: Single Server
A domain hosting a single MCP server: A domain advertising a single MCP server:
```json ```json
{ {
"specVersion": "draft", "specVersion": "1.0",
"entries": [ "entries": [
{ {
"identifier": "urn:air:example.com:weather", "identifier": "urn:air:example.com:mcp:weather",
"type": "application/mcp-server-card+json", "type": "application/mcp-server-card+json",
"url": "https://example.com/mcp/server-card" "url": "https://example.com/mcp/server-card"
} }
@ -109,24 +74,24 @@ A domain hosting a single MCP server:
### Example: Multiple Servers ### Example: Multiple Servers
A domain hosting several MCP servers, each with its own server card: A domain advertising several MCP servers, each with its own Server Card:
```json ```json
{ {
"specVersion": "draft", "specVersion": "1.0",
"entries": [ "entries": [
{ {
"identifier": "urn:air:acme.com:code-review", "identifier": "urn:air:acme.com:mcp:code-review",
"type": "application/mcp-server-card+json", "type": "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:mcp:docs-search",
"type": "application/mcp-server-card+json", "type": "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:mcp:ci-cd",
"type": "application/mcp-server-card+json", "type": "application/mcp-server-card+json",
"url": "https://acme.com/ci-cd/server-card" "url": "https://acme.com/ci-cd/server-card"
} }
@ -140,23 +105,25 @@ Clients performing domain-level discovery SHOULD follow this procedure:
```mermaid ```mermaid
flowchart TD flowchart TD
A[Client wants to discover MCP servers on example.com] --> B[Fetch /.well-known/mcp/catalog.json] A[Client wants to discover MCP servers on example.com] --> B[Fetch /.well-known/ai-catalog.json]
B --> C{Valid catalog returned?} B --> C{Valid AI Catalog returned?}
C -->|Yes| D[Parse entries array] C -->|No| D[Discovery unavailable for this domain]
C -->|No| E[Discovery unavailable for this domain] C -->|Yes| E[Select entries with the MCP Server Card type]
D --> F[For each entry, fetch server card from url] E --> F{Entry contains url or data?}
F --> G[Use server card to configure connection] F -->|url| G[Fetch Server Card from url]
F -->|data| H[Read inline Server Card]
G --> I[Use Server Card to configure connection]
H --> I
``` ```
1. Fetch `https://{domain}/.well-known/mcp/catalog.json` 1. Fetch `https://{domain}/.well-known/ai-catalog.json`
2. If a valid MCP Catalog is returned, iterate over the `entries` array 2. If a valid AI Catalog is returned, select entries whose `type` is
3. For each entry, retrieve the server card from the entry's `url`, expressing the `application/mcp-server-card+json`
Server Card media type via the `Accept` header (see 3. For an entry with `url`, retrieve the Server Card from that URL, expressing the Server
[Server Card Location](#server-card-location)) Card media type via the `Accept` header (see
4. Use the server card metadata to configure and establish an MCP connection [Hosted Server Card Location](#hosted-server-card-location)); for an entry with `data`,
use the inline Server Card
Clients SHOULD validate that each entry has `type` set to `application/mcp-server-card+json` 4. Use the Server Card metadata to configure and establish an MCP connection
and ignore entries with unrecognized types.
## MCP Server Cards ## MCP Server Cards
@ -195,21 +162,20 @@ than binding. Accordingly:
- Clients SHOULD verify a Server Card's claims against the live connection, preferring the - Clients SHOULD verify a Server Card's claims against the live connection, preferring the
runtime values where the two disagree. runtime values where the two disagree.
### Server Card Location ### Hosted Server Card Location
The Catalog is the discovery entrypoint, and every Catalog Entry already carries the An AI Catalog entry with `url` carries the exact location where its Server Card can be
`url` where its Server Card can be retrieved. Clients therefore never need to _guess_ a retrieved. Clients therefore never need to _guess_ a hosted Server Card's location — they
Server Card's location — they follow the `url` the Catalog gives them. As a result, a follow the `url` the catalog gives them. As a result, a Server Card MAY be hosted at any
Server Card MAY be hosted at any unreserved URI. unreserved URI. An entry with `data` carries the Server Card inline instead.
To give servers a predictable default, MCP reserves one location: To give servers a predictable default, MCP reserves one location:
> MCP Servers MAY host their Server Card at `GET <streamable-http-url>/server-card`, > 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. > 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 > 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 > 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` > it SHOULD request that URL expressing the `application/mcp-server-card+json` media type.
> media type.
Concretely: Concretely:
@ -227,12 +193,11 @@ The following placements were considered and **not** recommended:
- **A `.well-known` URI** (e.g., `/.well-known/mcp/server-card`). `.well-known` is for - **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_ _site-wide_ metadata, whereas an individual server's card is _application-level_
metadata. Because the Catalog is the discovery entrypoint and already provides each metadata. Because the AI Catalog already provides each hosted card's `url`, hosting the
card's `url`, hosting the card under `.well-known` adds no value — the card can live card under `.well-known` adds no value — the card can live anywhere the catalog points.
anywhere the Catalog points. (Note: `.well-known` remains correct for the **Catalog** `.well-known` remains correct for the AI Catalog itself at
itself at `/.well-known/mcp/catalog.json` and for OAuth metadata such as `/.well-known/ai-catalog.json` and for OAuth metadata such as
`/.well-known/oauth-protected-resource` — those are genuinely site-wide. This change `/.well-known/oauth-protected-resource`; those are genuinely site-wide.
applies only to the single-server Server Card.)
- **The bare streamable-HTTP endpoint** (`GET <streamable-http-url>` with no suffix). - **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 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 meaning — it opens the SSE stream. Serving the card there overloads that endpoint and
@ -250,29 +215,12 @@ The following placements were considered and **not** recommended:
`<streamable-http-url>` + `/server-card` — the recommended convention — not a domain-root `<streamable-http-url>` + `/server-card` — the recommended convention — not a domain-root
`/mcp/` metadata namespace.) `/mcp/` metadata namespace.)
## Relationship to AI Catalog
The MCP Catalog is designed as a transitional mechanism. The
[AI Catalog](https://github.com/Agent-Card/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 ## Security Considerations
### Information Disclosure ### Information Disclosure
MCP Catalogs are publicly accessible by design. Catalog entries MUST NOT include sensitive AI Catalogs and Server Cards used for public discovery are publicly accessible by design.
information such as: They MUST NOT include sensitive information such as:
- Authentication credentials or tokens - Authentication credentials or tokens
- Internal network topology or private endpoints - Internal network topology or private endpoints
@ -291,7 +239,8 @@ treat a Server Card as authoritative and reconcile it against the live connectio
### CORS Requirements ### CORS Requirements
Discovery endpoints MUST include appropriate CORS headers to allow browser-based clients: Hosted Server Card endpoints MUST include appropriate CORS headers to allow browser-based
clients:
``` ```
Access-Control-Allow-Origin: * Access-Control-Allow-Origin: *
@ -299,11 +248,11 @@ Access-Control-Allow-Methods: GET
Access-Control-Allow-Headers: Content-Type Access-Control-Allow-Headers: Content-Type
``` ```
This is safe because MCP Catalogs contain only public metadata and are read-only. This is safe because Server Cards contain only public metadata and are read-only.
### Caching ### Caching
Servers SHOULD include caching headers to reduce unnecessary requests: Server Card hosts SHOULD include caching headers to reduce unnecessary requests:
``` ```
Cache-Control: public, max-age=3600 Cache-Control: public, max-age=3600
@ -311,8 +260,8 @@ Cache-Control: public, max-age=3600
### Transport Security ### Transport Security
MCP Catalogs MUST be served over HTTPS (TLS 1.2 or later) in production. HTTP MAY be Hosted Server Cards MUST be served over HTTPS (TLS 1.2 or later) in production. HTTP MAY
used for local development only. be used for local development only.
### Denial of Service ### Denial of Service