diff --git a/README.md b/README.md index 7ca95ff..c76c238 100644 --- a/README.md +++ b/README.md @@ -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:///.well-known/mcp/server-card`, describing: +A **Server Card** is a JSON document — hosted at any unreserved URI, with `GET /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) diff --git a/docs/discovery.md b/docs/discovery.md index 3aea775..2a0cf24 100644 --- a/docs/discovery.md +++ b/docs/discovery.md @@ -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" } ] } @@ -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" } ] } @@ -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` @@ -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 /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 ` 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 + `` + `/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 diff --git a/schema.json b/schema.json index af69faa..ea100c5 100644 --- a/schema.json +++ b/schema.json @@ -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., `/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.", @@ -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 /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.", diff --git a/schema.ts b/schema.ts index 34cb067..32eccca 100644 --- a/schema.ts +++ b/schema.ts @@ -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 /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. @@ -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., `/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