From 96aa564d1f4dfa64d383fa7ba7a3b0e98f3e62ac Mon Sep 17 00:00:00 2001 From: "Agent (Claude)" Date: Mon, 8 Jun 2026 02:18:44 +0000 Subject: [PATCH 1/6] Server Cards: recommend `/server-card` over `.well-known` (resolves #12) Move the single-server Server Card off a `.well-known` path. Reserve `GET /server-card` as the recommended location while allowing any unreserved URI, since the Catalog already carries each card's `url` and clients never need to guess the location. - docs/discovery.md: new "Server Card Location" convention + permanent "Alternatives considered" subsection (bare endpoint / SSE-GET overload, `.well-known`, `/mcp/`-`/MCP/` nesting); rewrite single- and multi-server example URLs to the new style. - Use `Accept: application/mcp-server-card+json` on the GET request (the representation-negotiation header for a GET); `Content-Type` is the server's response header. - Normalize the media type to `application/mcp-server-card+json` everywhere, removing the prior `application/mcp-server+json` inconsistency. - schema.ts / schema.json / README.md: drop single-card `.well-known` phrasing for the new convention (Catalog + OAuth `.well-known` untouched). Co-Authored-By: Claude Opus 4.8 --- README.md | 2 +- docs/discovery.md | 88 ++++++++++++++++++++++++++++++++++++++--------- schema.json | 4 +-- schema.ts | 10 ++++-- 4 files changed, 81 insertions(+), 23 deletions(-) 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 78db7cd..3488f87 100644 --- a/docs/discovery.md +++ b/docs/discovery.md @@ -50,12 +50,12 @@ An MCP Catalog document is a JSON object that MUST contain the following members Each entry in the `entries` array describes a single MCP server and MUST contain: -| Member | Type | Required | Description | -| :------------ | :----- | :------- | :------------------------------------------------------------------------------- | -| `identifier` | string | Yes | A URN identifying this server (e.g., `urn:mcp:server:com.example/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+json` | -| `url` | string | Yes | URL where the full [Server Card](#mcp-server-cards) can be retrieved | +| Member | Type | Required | Description | +| :------------ | :----- | :------- | :------------------------------------------------------------------------------------ | +| `identifier` | string | Yes | A URN identifying this server (e.g., `urn:mcp:server:com.example/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](#mcp-server-cards) can be retrieved | The `identifier` MUST begin with `urn:mcp:server:` and end with the `name` value of the referenced Server Card, with no characters in between. @@ -71,8 +71,8 @@ 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+json", - "url": "https://example.com/.well-known/mcp-server-card" + "mediaType": "application/mcp-server-card+json", + "url": "https://example.com/mcp/server-card" } ] } @@ -89,20 +89,20 @@ 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+json", - "url": "https://acme.com/.well-known/mcp-server-card/code-review" + "mediaType": "application/mcp-server-card+json", + "url": "https://acme.com/code-review/server-card" }, { "identifier": "urn:mcp:server:com.acme/docs-search", "displayName": "Documentation Search", - "mediaType": "application/mcp-server+json", - "url": "https://acme.com/.well-known/mcp-server-card/docs-search" + "mediaType": "application/mcp-server-card+json", + "url": "https://acme.com/docs-search/server-card" }, { "identifier": "urn:mcp:server:com.acme/ci-cd", "displayName": "CI/CD Pipeline", - "mediaType": "application/mcp-server+json", - "url": "https://acme.com/.well-known/mcp-server-card/ci-cd" + "mediaType": "application/mcp-server-card+json", + "url": "https://acme.com/ci-cd/server-card" } ] } @@ -124,17 +124,19 @@ 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+json` +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, capabilities, and connection details. Server Cards use the media type -`application/mcp-server+json`. +`application/mcp-server-card+json`. A Server Card includes: @@ -146,6 +148,58 @@ 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 is valid. MCP Servers +> SHOULD respect the agreed 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 Server Card 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 `/mcp/` or `/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, and a capitalized `/MCP/` matches nothing in the + ecosystem. 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. + ## 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 From a8134513f921f2f6ab9b3b5cf1d49b73184db64d Mon Sep 17 00:00:00 2001 From: "Agent (Claude)" Date: Mon, 8 Jun 2026 02:21:45 +0000 Subject: [PATCH 2/6] docs(discovery): clarify /mcp/ nesting vs a server living at /mcp Address review nit: distinguish the rejected domain-root /mcp/ metadata namespace from a streamable-HTTP URL that happens to end in /mcp, whose /server-card suffix is exactly the recommended convention. Co-Authored-By: Claude Opus 4.8 --- docs/discovery.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/discovery.md b/docs/discovery.md index 3488f87..15221a3 100644 --- a/docs/discovery.md +++ b/docs/discovery.md @@ -198,7 +198,9 @@ The following placements were considered and **not** recommended: sub-namespace relative to a server URL, and a capitalized `/MCP/` matches nothing in the ecosystem. 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. + 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 From ff9fc734e3dc5fa08d9b5a8073868317c7b7ec01 Mon Sep 17 00:00:00 2001 From: "Agent (Claude)" Date: Mon, 8 Jun 2026 02:25:46 +0000 Subject: [PATCH 3/6] docs(discovery): drop /MCP/ from alternatives considered Capitalized /MCP/ was never a real candidate; remove it and keep the rejected alternative focused on domain-root /mcp/ nesting. Co-Authored-By: Claude Opus 4.8 --- docs/discovery.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/discovery.md b/docs/discovery.md index 15221a3..5702fe1 100644 --- a/docs/discovery.md +++ b/docs/discovery.md @@ -192,15 +192,15 @@ The following placements were considered and **not** recommended: 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 `/mcp/` or `/MCP/`** (e.g., `/mcp/server-card`). In MCP, `/mcp` denotes +- **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, and a capitalized `/MCP/` matches nothing in the - ecosystem. 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.) + 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 From 8fc395b2d0d93ff124ccd383cebcebdcb8666701 Mon Sep 17 00:00:00 2001 From: "Agent (Claude)" Date: Mon, 8 Jun 2026 02:27:48 +0000 Subject: [PATCH 4/6] docs(discovery): keep existing media type; scope PR to card placement only The application/mcp-server+json -> application/mcp-server-card+json rename is handled in a separate PR. Revert the media-type strings here so this PR changes only the Server Card placement convention and does not trample that work. Co-Authored-By: Claude Opus 4.8 --- docs/discovery.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/discovery.md b/docs/discovery.md index 5702fe1..fc4514c 100644 --- a/docs/discovery.md +++ b/docs/discovery.md @@ -50,12 +50,12 @@ An MCP Catalog document is a JSON object that MUST contain the following members Each entry in the `entries` array describes a single MCP server and MUST contain: -| Member | Type | Required | Description | -| :------------ | :----- | :------- | :------------------------------------------------------------------------------------ | -| `identifier` | string | Yes | A URN identifying this server (e.g., `urn:mcp:server:com.example/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](#mcp-server-cards) can be retrieved | +| Member | Type | Required | Description | +| :------------ | :----- | :------- | :------------------------------------------------------------------------------- | +| `identifier` | string | Yes | A URN identifying this server (e.g., `urn:mcp:server:com.example/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+json` | +| `url` | string | Yes | URL where the full [Server Card](#mcp-server-cards) can be retrieved | The `identifier` MUST begin with `urn:mcp:server:` and end with the `name` value of the referenced Server Card, with no characters in between. @@ -71,7 +71,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", + "mediaType": "application/mcp-server+json", "url": "https://example.com/mcp/server-card" } ] @@ -89,19 +89,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", + "mediaType": "application/mcp-server+json", "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", + "mediaType": "application/mcp-server+json", "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", + "mediaType": "application/mcp-server+json", "url": "https://acme.com/ci-cd/server-card" } ] @@ -129,14 +129,14 @@ flowchart TD [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` +Clients SHOULD validate that each entry has `mediaType` set to `application/mcp-server+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, capabilities, and connection details. Server Cards use the media type -`application/mcp-server-card+json`. +`application/mcp-server+json`. A Server Card includes: @@ -165,7 +165,7 @@ To give servers a predictable default, MCP reserves one location: Concretely: -- A client requesting a Server Card SHOULD send `Accept: application/mcp-server-card+json` +- A client requesting a Server Card SHOULD send `Accept: application/mcp-server+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 From 3b4aae0b7b5d43c644f7518a4f36cc60a796bcfa Mon Sep 17 00:00:00 2001 From: "Agent (Claude)" Date: Mon, 8 Jun 2026 02:31:09 +0000 Subject: [PATCH 5/6] docs(discovery): inline explicit media type in new placement prose The reserved-location blockquote and Accept example now name the media type explicitly. Since this is new text the separate rename PR will not touch, use the post-rename application/mcp-server-card+json directly. Pre-existing application/mcp-server+json strings remain untouched for the rename PR to handle. Co-Authored-By: Claude Opus 4.8 --- docs/discovery.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/discovery.md b/docs/discovery.md index fc4514c..b934c50 100644 --- a/docs/discovery.md +++ b/docs/discovery.md @@ -159,13 +159,14 @@ 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 is valid. MCP Servers -> SHOULD respect the agreed 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 Server Card media type. +> 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+json` +- 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 From 10ba5fbc9de91afc4d28567779e163e4550ff67b Mon Sep 17 00:00:00 2001 From: Tadas Antanavicius Date: Mon, 8 Jun 2026 12:39:59 -0700 Subject: [PATCH 6/6] Update discovery.md Allow for any domain --- docs/discovery.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/discovery.md b/docs/discovery.md index 3f79d86..2a0cf24 100644 --- a/docs/discovery.md +++ b/docs/discovery.md @@ -160,10 +160,10 @@ 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 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` +> 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: