From 85263d256a09c7d2aea1d7583437807b1f54e214 Mon Sep 17 00:00:00 2001 From: Sam Morrow Date: Sat, 18 Jul 2026 22:52:19 +0200 Subject: [PATCH 1/3] docs(discovery): use AI Catalog for Server Card discovery Closes #26 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: bc66c0fe-15a9-493d-81c7-258a6948e4f0 --- README.md | 2 + docs/discovery.md | 250 ++++++++-------------------------------------- schema.json | 2 +- schema.ts | 4 +- 4 files changed, 45 insertions(+), 213 deletions(-) diff --git a/README.md b/README.md index 235cff3..33df70d 100644 --- a/README.md +++ b/README.md @@ -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) - Optional registry-style extension metadata (`_meta`) +Clients discover Server Cards through [AI Catalog](https://github.com/Agent-Card/ai-catalog) entries with the `application/mcp-server-card+json` media type. + 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 diff --git a/docs/discovery.md b/docs/discovery.md index ced0146..6ad81fc 100644 --- a/docs/discovery.md +++ b/docs/discovery.md @@ -2,161 +2,46 @@ **Protocol Revision**: draft -MCP defines a discovery mechanism that enables clients to find available MCP servers on a -domain without prior configuration. This mechanism answers _where_ to connect, before any -protocol exchange establishes _how_ to communicate. +MCP Server Cards describe where and how to connect to MCP servers before any protocol +exchange. Clients discover Server Cards through an +[AI Catalog](https://github.com/Agent-Card/ai-catalog). -## MCP Catalog +## AI Catalog -An **MCP Catalog** is a JSON document published by an organization to advertise the -[MCP Server Cards](#mcp-server-cards) relevant to its services. +An AI Catalog is a typed container for discovering heterogeneous AI artifacts. Catalog +entries for MCP Server Cards use the `application/mcp-server-card+json` media type and +either reference a hosted card by URL or include the card inline. The AI Catalog +specification defines the catalog format, publication locations, and discovery behavior. -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](#mcp-server-cards) for connection -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 - -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](#cors-requirements)) -- SHOULD include appropriate caching headers (see [Caching](#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`) | -| `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} -``` - -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: - -```json -{ - "specVersion": "draft", - "entries": [ - { - "identifier": "urn:air:example.com:weather", - "type": "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: - -```json -{ - "specVersion": "draft", - "entries": [ - { - "identifier": "urn:air:acme.com:code-review", - "type": "application/mcp-server-card+json", - "url": "https://acme.com/code-review/server-card" - }, - { - "identifier": "urn:air:acme.com:docs-search", - "type": "application/mcp-server-card+json", - "url": "https://acme.com/docs-search/server-card" - }, - { - "identifier": "urn:air:acme.com:ci-cd", - "type": "application/mcp-server-card+json", - "url": "https://acme.com/ci-cd/server-card" - } - ] -} -``` +Clients discovering MCP servers from an AI Catalog SHOULD select entries whose `type` is +`application/mcp-server-card+json` and ignore entries with other media types. ## Client Discovery Flow -Clients performing domain-level discovery SHOULD follow this procedure: +Clients discovering MCP servers through an AI Catalog SHOULD follow this procedure: ```mermaid 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] + A[Client wants to discover MCP servers] --> B[Locate an AI Catalog] + B --> C{Valid catalog available?} + C -->|No| D[Discovery unavailable] + C -->|Yes| E[Select MCP Server Card entries] + E --> F{Entry content} + F -->|url| G[Fetch the Server Card] + F -->|data| H[Read the inline Server Card] + G --> I[Validate the Server Card] + H --> I + I --> J[Configure the MCP 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](#server-card-location)) -4. Use the server card metadata to configure and establish an MCP connection - -Clients SHOULD validate that each entry has `type` set to `application/mcp-server-card+json` -and ignore entries with unrecognized types. +1. Locate and validate an AI Catalog according to the AI Catalog specification. +2. Select entries whose `type` is `application/mcp-server-card+json`. +3. For a `url` entry, retrieve the Server Card from that URL, expressing the Server Card + media type via the `Accept` header (see + [Hosted Server Card Location](#hosted-server-card-location)). For a `data` entry, use + the inline Server Card. +4. Validate the Server Card and use its metadata to configure and establish an MCP + connection. ## MCP Server Cards @@ -195,21 +80,20 @@ than binding. Accordingly: - Clients SHOULD verify a Server Card's claims against the live connection, preferring the 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 -`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. +An AI Catalog entry with a `url` provides the exact location of its Server Card, so clients +never need to guess where a hosted card lives. A Server Card MAY therefore be hosted at any +unreserved URI. An AI Catalog entry with `data` includes the Server Card inline and does +not require a hosted location. To give servers a predictable default, MCP reserves one location: > MCP Servers MAY host their Server Card at `GET /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. +> they choose to host it. After a client identifies a Server Card URL from an AI Catalog, +> it SHOULD request that URL expressing the `application/mcp-server-card+json` media type. Concretely: @@ -227,12 +111,9 @@ 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.) + metadata. AI Catalog entries already provide each hosted card's URL, so an individual + card can live anywhere its entry points. `.well-known` remains appropriate for + site-wide metadata such as AI Catalog and OAuth metadata. - **The bare streamable-HTTP endpoint** (`GET ` 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 @@ -250,34 +131,8 @@ The following placements were considered and **not** recommended: `` + `/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](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 -### 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 @@ -289,33 +144,8 @@ property, not merely a matter of correctness. The normative protections live in [Consistency with Runtime Behavior](#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. +Server Card hosts SHOULD implement rate limiting on their endpoints to prevent abuse. MCP Clients SHOULD respect `Cache-Control` headers and avoid unnecessary polling. diff --git a/schema.json b/schema.json index a93de94..b114823 100644 --- a/schema.json +++ b/schema.json @@ -193,7 +193,7 @@ "type": "object" }, "ServerCard": { - "description": "A static metadata document describing a remote MCP server, suitable for\npre-connection discovery. A Server Card may be hosted at any unreserved URI;\nMCP reserves `GET /server-card` as the recommended\nlocation. Clients learn a card's URL from an [AI Catalog](https://github.com/Agent-Card/ai-catalog)\nrather than guessing it.\n\nServer Cards describe only what is needed to discover and connect to a remote server:\nidentity, transport, and protocol versions.\n\nThey do not enumerate primitives (tools, resources, prompts) — those remain\nsubject to runtime listing via the protocol's standard list operations.\n\nThe fields a Server Card does declare (identity, transport, protocol\nversions) are advisory, not authoritative: they should be consistent with\nthe server's `server/discover` response, and clients must not treat them as\nauthoritative for security decisions. See \"Consistency with Runtime\nBehavior\" in docs/discovery.md for the normative requirement.", + "description": "A static metadata document describing a remote MCP server, suitable for\npre-connection discovery. A Server Card may be hosted at any unreserved URI;\nMCP reserves `GET /server-card` as the recommended\nlocation. Clients discover cards through an [AI Catalog](https://github.com/Agent-Card/ai-catalog),\nwhich can reference a hosted card by URL or include it inline.\n\nServer Cards describe only what is needed to discover and connect to a remote server:\nidentity, transport, and protocol versions.\n\nThey do not enumerate primitives (tools, resources, prompts) — those remain\nsubject to runtime listing via the protocol's standard list operations.\n\nThe fields a Server Card does declare (identity, transport, protocol\nversions) are advisory, not authoritative: they should be consistent with\nthe server's `server/discover` response, and clients must not treat them as\nauthoritative for security decisions. See \"Consistency with Runtime\nBehavior\" in docs/discovery.md for the normative requirement.", "properties": { "$schema": { "description": "The Server Card JSON Schema URI that this document conforms to. Required.\n\nMust be the `/v1/` Server Card schema URL under\n`static.modelcontextprotocol.io/schemas/` (i.e.,\n`https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json`).\nSchema URLs are versioned by the `vN` segment rather than by date; a\nbreaking revision of the Server Card shape publishes a new `vN` family.", diff --git a/schema.ts b/schema.ts index 20f168d..19f975f 100644 --- a/schema.ts +++ b/schema.ts @@ -9,8 +9,8 @@ * A static metadata document describing a remote MCP server, suitable for * pre-connection discovery. A Server Card may be hosted at any unreserved URI; * MCP reserves `GET /server-card` as the recommended - * location. Clients learn a card's URL from an [AI Catalog](https://github.com/Agent-Card/ai-catalog) - * rather than guessing it. + * location. Clients discover cards through an [AI Catalog](https://github.com/Agent-Card/ai-catalog), + * which can reference a hosted card by URL or include it inline. * * Server Cards describe only what is needed to discover and connect to a remote server: * identity, transport, and protocol versions. From b81914657e5d42b7423e5e4bdcf53856cf5bf628 Mon Sep 17 00:00:00 2001 From: Sam Morrow Date: Sat, 18 Jul 2026 23:28:08 +0200 Subject: [PATCH 2/3] docs(discovery): retain detailed AI Catalog flow Restore the existing discovery structure and explicitly surface the AI Catalog well-known path. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: bc66c0fe-15a9-493d-81c7-258a6948e4f0 --- docs/discovery.md | 189 +++++++++++++++++++++++++++++++++++++--------- schema.json | 2 +- schema.ts | 4 +- 3 files changed, 157 insertions(+), 38 deletions(-) diff --git a/docs/discovery.md b/docs/discovery.md index 6ad81fc..59dd287 100644 --- a/docs/discovery.md +++ b/docs/discovery.md @@ -2,46 +2,128 @@ **Protocol Revision**: draft -MCP Server Cards describe where and how to connect to MCP servers before any protocol -exchange. Clients discover Server Cards through an -[AI Catalog](https://github.com/Agent-Card/ai-catalog). +MCP defines a discovery mechanism that enables clients to find available MCP servers on a +domain without prior configuration. This mechanism answers _where_ to connect, before any +protocol exchange establishes _how_ to communicate. ## AI Catalog -An AI Catalog is a typed container for discovering heterogeneous AI artifacts. Catalog -entries for MCP Server Cards use the `application/mcp-server-card+json` media type and -either reference a hosted card by URL or include the card inline. The AI Catalog -specification defines the catalog format, publication locations, and discovery behavior. +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. -Clients discovering MCP servers from an AI Catalog SHOULD select entries whose `type` is -`application/mcp-server-card+json` and ignore entries with other media types. +The catalog MAY reference Server Cards on different domains than the catalog itself — for +example, an AI Catalog on `acme.org` MAY advertise servers operated by +`mcp-server-host-saas.com` on Acme's behalf. Clients can fetch the catalog to discover +servers and then retrieve individual Server Cards for connection details. + +### Well-Known URI + +An AI Catalog MAY be served from any URL. For automated domain-level discovery, hosts MAY +publish one at: + +``` +/.well-known/ai-catalog.json +``` + +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. + +### Server Card Entries + +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: + +| 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 | + +For open or federated systems, AI Catalog identifiers use the domain-anchored format: + +``` +urn:air:{publisher}:{namespace}:{name} +``` + +For example, a Server Card named `com.example/weather` can use the catalog identifier +`urn:air:example.com:mcp:weather`. + +An entry does not need to repeat the Server Card's human-readable fields. Clients can read +the server's `title`, `description`, and `version` from the card itself, avoiding duplicated +values that could drift out of sync. + +### Example: Single Server + +A domain advertising a single MCP server: + +```json +{ + "specVersion": "1.0", + "entries": [ + { + "identifier": "urn:air:example.com:mcp:weather", + "type": "application/mcp-server-card+json", + "url": "https://example.com/mcp/server-card" + } + ] +} +``` + +### Example: Multiple Servers + +A domain advertising several MCP servers, each with its own Server Card: + +```json +{ + "specVersion": "1.0", + "entries": [ + { + "identifier": "urn:air:acme.com:mcp:code-review", + "type": "application/mcp-server-card+json", + "url": "https://acme.com/code-review/server-card" + }, + { + "identifier": "urn:air:acme.com:mcp:docs-search", + "type": "application/mcp-server-card+json", + "url": "https://acme.com/docs-search/server-card" + }, + { + "identifier": "urn:air:acme.com:mcp:ci-cd", + "type": "application/mcp-server-card+json", + "url": "https://acme.com/ci-cd/server-card" + } + ] +} +``` ## Client Discovery Flow -Clients discovering MCP servers through an AI Catalog SHOULD follow this procedure: +Clients performing domain-level discovery SHOULD follow this procedure: ```mermaid flowchart TD - A[Client wants to discover MCP servers] --> B[Locate an AI Catalog] - B --> C{Valid catalog available?} - C -->|No| D[Discovery unavailable] - C -->|Yes| E[Select MCP Server Card entries] - E --> F{Entry content} - F -->|url| G[Fetch the Server Card] - F -->|data| H[Read the inline Server Card] - G --> I[Validate the Server Card] + A[Client wants to discover MCP servers on example.com] --> B[Fetch /.well-known/ai-catalog.json] + B --> C{Valid AI Catalog returned?} + C -->|No| D[Discovery unavailable for this domain] + C -->|Yes| E[Select entries with the MCP Server Card type] + E --> F{Entry contains url or data?} + 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 - I --> J[Configure the MCP connection] ``` -1. Locate and validate an AI Catalog according to the AI Catalog specification. -2. Select entries whose `type` is `application/mcp-server-card+json`. -3. For a `url` entry, retrieve the Server Card from that URL, expressing the Server Card - media type via the `Accept` header (see - [Hosted Server Card Location](#hosted-server-card-location)). For a `data` entry, use - the inline Server Card. -4. Validate the Server Card and use its metadata to configure and establish an MCP - connection. +1. Fetch `https://{domain}/.well-known/ai-catalog.json` +2. If a valid AI Catalog is returned, select entries whose `type` is + `application/mcp-server-card+json` +3. For an entry with `url`, retrieve the Server Card from that URL, expressing the Server + Card media type via the `Accept` header (see + [Hosted Server Card Location](#hosted-server-card-location)); for an entry with `data`, + use the inline Server Card +4. Use the Server Card metadata to configure and establish an MCP connection ## MCP Server Cards @@ -82,10 +164,10 @@ than binding. Accordingly: ### Hosted Server Card Location -An AI Catalog entry with a `url` provides the exact location of its Server Card, so clients -never need to guess where a hosted card lives. A Server Card MAY therefore be hosted at any -unreserved URI. An AI Catalog entry with `data` includes the Server Card inline and does -not require a hosted location. +An AI Catalog entry with `url` carries the exact location where its Server Card can be +retrieved. Clients therefore never need to _guess_ a hosted 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. An entry with `data` carries the Server Card inline instead. To give servers a predictable default, MCP reserves one location: @@ -111,9 +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 _site-wide_ metadata, whereas an individual server's card is _application-level_ - metadata. AI Catalog entries already provide each hosted card's URL, so an individual - card can live anywhere its entry points. `.well-known` remains appropriate for - site-wide metadata such as AI Catalog and OAuth metadata. + metadata. Because the AI Catalog already provides each hosted card's `url`, hosting the + card under `.well-known` adds no value — the card can live anywhere the catalog points. + `.well-known` remains correct for the AI Catalog itself at + `/.well-known/ai-catalog.json` and for OAuth metadata such as + `/.well-known/oauth-protected-resource`; those are genuinely site-wide. - **The bare streamable-HTTP endpoint** (`GET ` 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 @@ -133,6 +217,15 @@ The following placements were considered and **not** recommended: ## Security Considerations +### Information Disclosure + +AI Catalogs and Server Cards used for public discovery are publicly accessible by design. +They 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 @@ -144,8 +237,34 @@ property, not merely a matter of correctness. The normative protections live in [Consistency with Runtime Behavior](#consistency-with-runtime-behavior): clients do not treat a Server Card as authoritative and reconcile it against the live connection. +### CORS Requirements + +Hosted Server Card 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 Server Cards contain only public metadata and are read-only. + +### Caching + +Server Card hosts SHOULD include caching headers to reduce unnecessary requests: + +``` +Cache-Control: public, max-age=3600 +``` + +### Transport Security + +Hosted Server Cards MUST be served over HTTPS (TLS 1.2 or later) in production. HTTP MAY +be used for local development only. + ### Denial of Service -Server Card hosts SHOULD implement rate limiting on their endpoints to prevent abuse. +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. diff --git a/schema.json b/schema.json index b114823..a93de94 100644 --- a/schema.json +++ b/schema.json @@ -193,7 +193,7 @@ "type": "object" }, "ServerCard": { - "description": "A static metadata document describing a remote MCP server, suitable for\npre-connection discovery. A Server Card may be hosted at any unreserved URI;\nMCP reserves `GET /server-card` as the recommended\nlocation. Clients discover cards through an [AI Catalog](https://github.com/Agent-Card/ai-catalog),\nwhich can reference a hosted card by URL or include it inline.\n\nServer Cards describe only what is needed to discover and connect to a remote server:\nidentity, transport, and protocol versions.\n\nThey do not enumerate primitives (tools, resources, prompts) — those remain\nsubject to runtime listing via the protocol's standard list operations.\n\nThe fields a Server Card does declare (identity, transport, protocol\nversions) are advisory, not authoritative: they should be consistent with\nthe server's `server/discover` response, and clients must not treat them as\nauthoritative for security decisions. See \"Consistency with Runtime\nBehavior\" in docs/discovery.md for the normative requirement.", + "description": "A static metadata document describing a remote MCP server, suitable for\npre-connection discovery. A Server Card may be hosted at any unreserved URI;\nMCP reserves `GET /server-card` as the recommended\nlocation. Clients learn a card's URL from an [AI Catalog](https://github.com/Agent-Card/ai-catalog)\nrather than guessing it.\n\nServer Cards describe only what is needed to discover and connect to a remote server:\nidentity, transport, and protocol versions.\n\nThey do not enumerate primitives (tools, resources, prompts) — those remain\nsubject to runtime listing via the protocol's standard list operations.\n\nThe fields a Server Card does declare (identity, transport, protocol\nversions) are advisory, not authoritative: they should be consistent with\nthe server's `server/discover` response, and clients must not treat them as\nauthoritative for security decisions. See \"Consistency with Runtime\nBehavior\" in docs/discovery.md for the normative requirement.", "properties": { "$schema": { "description": "The Server Card JSON Schema URI that this document conforms to. Required.\n\nMust be the `/v1/` Server Card schema URL under\n`static.modelcontextprotocol.io/schemas/` (i.e.,\n`https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json`).\nSchema URLs are versioned by the `vN` segment rather than by date; a\nbreaking revision of the Server Card shape publishes a new `vN` family.", diff --git a/schema.ts b/schema.ts index 19f975f..20f168d 100644 --- a/schema.ts +++ b/schema.ts @@ -9,8 +9,8 @@ * A static metadata document describing a remote MCP server, suitable for * pre-connection discovery. A Server Card may be hosted at any unreserved URI; * MCP reserves `GET /server-card` as the recommended - * location. Clients discover cards through an [AI Catalog](https://github.com/Agent-Card/ai-catalog), - * which can reference a hosted card by URL or include it inline. + * location. Clients learn a card's URL from an [AI Catalog](https://github.com/Agent-Card/ai-catalog) + * rather than guessing it. * * Server Cards describe only what is needed to discover and connect to a remote server: * identity, transport, and protocol versions. From 8e929ff671b2c7323a7f0f0135eb70509aa47237 Mon Sep 17 00:00:00 2001 From: Sam Morrow Date: Mon, 20 Jul 2026 18:53:32 +0200 Subject: [PATCH 3/3] Update README.md Co-authored-by: Tadas Antanavicius --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 33df70d..48299d7 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ 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) - Optional registry-style extension metadata (`_meta`) -Clients discover Server Cards through [AI Catalog](https://github.com/Agent-Card/ai-catalog) entries with the `application/mcp-server-card+json` media type. +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).