Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ A prior attempt to land these types directly in the core spec ([modelcontextprot

## What is a Server Card?

A **Server Card** is a JSON document, typically published at `https://<host>/.well-known/mcp/server-card`, describing:
A **Server Card** is a JSON document — hosted at any unreserved URI, with `GET <streamable-http-url>/server-card` reserved as the recommended location (see [discovery.md](docs/discovery.md)) — describing:

- The server's identity (`name`, `version`, `description`, optional `title` / `icons` / `repository` / `websiteUrl`)
- Its remote transport endpoints (URLs, headers, variable templates, supported protocol versions)
Expand Down
67 changes: 62 additions & 5 deletions docs/discovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ A domain hosting a single MCP server, using only the required fields:
"identifier": "urn:mcp:server:com.example/weather",
"displayName": "Weather Service",
"mediaType": "application/mcp-server-card+json",
"url": "https://example.com/.well-known/mcp-server-card"
"url": "https://example.com/mcp/server-card"
}
]
}
Expand All @@ -90,19 +90,19 @@ A domain hosting several MCP servers, each with its own server card:
"identifier": "urn:mcp:server:com.acme/code-review",
"displayName": "Code Review Assistant",
"mediaType": "application/mcp-server-card+json",
"url": "https://acme.com/.well-known/mcp-server-card/code-review"
"url": "https://acme.com/code-review/server-card"
},
{
"identifier": "urn:mcp:server:com.acme/docs-search",
"displayName": "Documentation Search",
"mediaType": "application/mcp-server-card+json",
"url": "https://acme.com/.well-known/mcp-server-card/docs-search"
"url": "https://acme.com/docs-search/server-card"
},
{
"identifier": "urn:mcp:server:com.acme/ci-cd",
"displayName": "CI/CD Pipeline",
"mediaType": "application/mcp-server-card+json",
"url": "https://acme.com/.well-known/mcp-server-card/ci-cd"
"url": "https://acme.com/ci-cd/server-card"
}
]
}
Expand All @@ -124,7 +124,9 @@ flowchart TD

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`
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 `mediaType` set to `application/mcp-server-card+json`
Expand All @@ -148,6 +150,61 @@ A Server Card includes:
For the full Server Card specification, see
[SEP-2127: MCP Server Cards](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2127).

### 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.
Comment thread
tadasant marked this conversation as resolved.

#### 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
Expand Down
4 changes: 2 additions & 2 deletions schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@
"type": "object"
},
"Server": {
"description": "A superset of {@link ServerCard} that additionally describes locally-runnable\npackages. This is the shape used by the MCP Registry's `server.json`.\n\n`Server` documents are typically published to a registry rather than served\nfrom a `.well-known` URI, since they may include instructions for installing\nand executing a server on a client's local machine.",
"description": "A superset of {@link ServerCard} that additionally describes locally-runnable\npackages. This is the shape used by the MCP Registry's `server.json`.\n\n`Server` documents are typically published to a registry rather than served\nfrom a Server Card URI (e.g., `<streamable-http-url>/server-card`), since they\nmay include instructions for installing and executing a server on a client's\nlocal machine.",
"properties": {
"$schema": {
"description": "The Server Card JSON Schema URI that this document conforms to. Required.\n\nMust be a `/v1/` URL under `static.modelcontextprotocol.io/schemas/`,\nnaming a Server Card / `server.json` schema (e.g.,\n`https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json`\nor `https://static.modelcontextprotocol.io/schemas/v1/server.schema.json`).\nSchema URLs are versioned by the `vN` segment rather than by date so that\nminor, additive revisions of the v1 shape don't bump every published\ndocument's `$schema` URL.",
Expand Down Expand Up @@ -527,7 +527,7 @@
"type": "object"
},
"ServerCard": {
"description": "A static metadata document describing a remote MCP server, suitable for\npublishing at a `.well-known/mcp-server-card` URI for pre-connection discovery.\n\nServer Cards intentionally describe only what is needed to discover and\nconnect to a remote server: identity, transport, and protocol versions.\nThey do not enumerate primitives (tools, resources, prompts) — those remain\nsubject to runtime listing via the protocol's standard list operations.\n\nThe companion {@link Server} shape is a strict superset that adds local\npackage metadata for use cases like the MCP Registry's `server.json`.",
"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 <streamable-http-url>/server-card` as the recommended\nlocation. Clients learn a card's URL from an MCP/AI Catalog rather than\nguessing it.\n\nServer Cards intentionally describe only what is needed to discover and\nconnect to a remote server: identity, transport, and protocol versions.\nThey do not enumerate primitives (tools, resources, prompts) — those remain\nsubject to runtime listing via the protocol's standard list operations.\n\nThe companion {@link Server} shape is a strict superset that adds local\npackage metadata for use cases like the MCP Registry's `server.json`.",
"properties": {
"$schema": {
"description": "The Server Card JSON Schema URI that this document conforms to. Required.\n\nMust be a `/v1/` URL under `static.modelcontextprotocol.io/schemas/`,\nnaming a Server Card / `server.json` schema (e.g.,\n`https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json`\nor `https://static.modelcontextprotocol.io/schemas/v1/server.schema.json`).\nSchema URLs are versioned by the `vN` segment rather than by date so that\nminor, additive revisions of the v1 shape don't bump every published\ndocument's `$schema` URL.",
Expand Down
10 changes: 7 additions & 3 deletions schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@

/**
* A static metadata document describing a remote MCP server, suitable for
* publishing at a `.well-known/mcp-server-card` URI for pre-connection discovery.
* pre-connection discovery. A Server Card MAY be hosted at any unreserved URI;
* MCP reserves `GET <streamable-http-url>/server-card` as the recommended
* location. Clients learn a card's URL from an MCP/AI Catalog rather than
* guessing it.
*
* Server Cards intentionally describe only what is needed to discover and
* connect to a remote server: identity, transport, and protocol versions.
Expand Down Expand Up @@ -126,8 +129,9 @@ export interface ServerCard {
* packages. This is the shape used by the MCP Registry's `server.json`.
*
* `Server` documents are typically published to a registry rather than served
* from a `.well-known` URI, since they may include instructions for installing
* and executing a server on a client's local machine.
* from a Server Card URI (e.g., `<streamable-http-url>/server-card`), since they
* may include instructions for installing and executing a server on a client's
* local machine.
*
* @see [SEP-2127: MCP Server Cards](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2127)
* @category Server Cards
Expand Down
Loading