From aa8a42a7c88fe593ee03b26d43a1f776c0ac0529 Mon Sep 17 00:00:00 2001 From: Tadas Antanavicius Date: Mon, 8 Jun 2026 20:09:57 +0000 Subject: [PATCH 1/2] docs: require Server Card to be consistent with runtime behavior (closes #23) The Server Card spec describes what a card declares (identity, transport, supported protocol versions) but had no normative requirement that those declarations match the server's actual runtime behavior. A Server Card is fetched before the client connects, so a stale or incorrect card can claim a name, version, transport, or protocol-version set that contradicts what a client observes after connecting. schema.ts already encodes the *omission* half of the threat model (primitives are excluded because a static manifest drifts from runtime). This adds the complementary requirement for the fields the card *does* declare. docs/discovery.md: - New "Consistency with Runtime Behavior" subsection under "MCP Server Cards": a Server Card SHOULD accurately reflect runtime behavior; the serverInfo (name, version) and supportedVersions returned by server/discover, and the transport served at each remotes[] endpoint, SHOULD NOT contradict the card. Clients MUST NOT treat card contents as authoritative for security/access-control decisions and SHOULD verify against the live connection. - New "Server Card Accuracy" subsection under Security Considerations framing an inaccurate card as a mild confusion/downgrade vector. schema.ts: short pointer comment in the ServerCard JSDoc referencing the discovery-doc requirement; schema.json regenerated in the same commit. Co-Authored-By: Claude Opus 4.8 --- docs/discovery.md | 34 ++++++++++++++++++++++++++++++++++ schema.json | 2 +- schema.ts | 7 +++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/docs/discovery.md b/docs/discovery.md index 6768df6..e152478 100644 --- a/docs/discovery.md +++ b/docs/discovery.md @@ -150,6 +150,27 @@ A Server Card includes: For the full Server Card specification, see [SEP-2127: MCP Server Cards](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2127). +### Consistency with Runtime Behavior + +A Server Card is fetched _before_ the client connects to the server, so its contents are +unverified at the time a client reads them. A Server Card SHOULD accurately reflect the +server's actual runtime behavior: the identity and connection metadata a client observes +once connected — for example, the `serverInfo` (`name`, `version`) and `supportedVersions` +returned by [`server/discover`](https://modelcontextprotocol.io/specification/draft/server/discover), +and the transport actually served at each `remotes[]` endpoint — SHOULD NOT contradict the +equivalent values declared in the Server Card. Descriptive fields (`title`, `description`, +`icons`) SHOULD likewise be consistent with what the server presents at runtime. + +This mirrors the reasoning behind the Server Card's deliberate omission of primitives +(tools, resources, prompts): because a static manifest can drift from runtime, the Server +Card describes only identity, transport, and protocol versions, and even those declarations +are advisory rather than binding. Accordingly: + +- Clients MUST NOT treat Server Card contents as authoritative for security or + access-control decisions. +- Clients SHOULD verify a Server Card's claims against the live connection after + connecting, and SHOULD prefer the values observed at runtime where the two disagree. + ### Server Card Location The Catalog is the discovery entrypoint, and every Catalog Entry already carries the @@ -233,6 +254,19 @@ information such as: - Internal network topology or private endpoints - Proprietary business logic +### Server Card Accuracy + +Because a Server Card is consumed before the client connects, an inaccurate Server Card — +whether stale or deliberately crafted — is a mild confusion or downgrade vector. A Server +Card that overstates transport or protocol-version support, or otherwise misrepresents the +server's identity, can steer a client toward a weaker configuration or a misidentified +server before it has connected and observed the server's actual `server/discover` response. +This is why the consistency requirement is partly a security property and not merely a +matter of correctness. The normative protections against it 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 once +established. + ### CORS Requirements Discovery endpoints MUST include appropriate CORS headers to allow browser-based clients: diff --git a/schema.json b/schema.json index ea100c5..5f18383 100644 --- a/schema.json +++ b/schema.json @@ -527,7 +527,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 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`.", + "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 fields a Server Card does declare (identity, transport, protocol\nversions) are advisory, not authoritative: they SHOULD be consistent with\nwhat a client observes at runtime (e.g. the server's `server/discover`\nresponse), and clients MUST NOT treat them as authoritative for security\ndecisions. See \"Consistency with Runtime Behavior\" in docs/discovery.md for\nthe normative requirement.\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 32eccca..07a5107 100644 --- a/schema.ts +++ b/schema.ts @@ -21,6 +21,13 @@ * They do not enumerate primitives (tools, resources, prompts) — those remain * subject to runtime listing via the protocol's standard list operations. * + * The fields a Server Card does declare (identity, transport, protocol + * versions) are advisory, not authoritative: they SHOULD be consistent with + * what a client observes at runtime (e.g. the server's `server/discover` + * response), and clients MUST NOT treat them as authoritative for security + * decisions. See "Consistency with Runtime Behavior" in docs/discovery.md for + * the normative requirement. + * * The companion {@link Server} shape is a strict superset that adds local * package metadata for use cases like the MCP Registry's `server.json`. * From 0d0389b4ea6654494b83e070785489431ddaf887 Mon Sep 17 00:00:00 2001 From: Tadas Antanavicius Date: Mon, 8 Jun 2026 20:28:11 +0000 Subject: [PATCH 2/2] docs: brevity pass on card-vs-runtime consistency text (Sam's review) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tighten the new "Consistency with Runtime Behavior" and "Server Card Accuracy" prose without changing any normative content — same SHOULD / SHOULD NOT / MUST NOT requirements, same server/discover reference. Co-Authored-By: Claude Opus 4.8 --- docs/discovery.md | 44 ++++++++++++++++++++------------------------ schema.json | 2 +- schema.ts | 7 +++---- 3 files changed, 24 insertions(+), 29 deletions(-) diff --git a/docs/discovery.md b/docs/discovery.md index e152478..7faffd9 100644 --- a/docs/discovery.md +++ b/docs/discovery.md @@ -152,24 +152,22 @@ For the full Server Card specification, see ### Consistency with Runtime Behavior -A Server Card is fetched _before_ the client connects to the server, so its contents are -unverified at the time a client reads them. A Server Card SHOULD accurately reflect the -server's actual runtime behavior: the identity and connection metadata a client observes -once connected — for example, the `serverInfo` (`name`, `version`) and `supportedVersions` -returned by [`server/discover`](https://modelcontextprotocol.io/specification/draft/server/discover), -and the transport actually served at each `remotes[]` endpoint — SHOULD NOT contradict the -equivalent values declared in the Server Card. Descriptive fields (`title`, `description`, -`icons`) SHOULD likewise be consistent with what the server presents at runtime. - -This mirrors the reasoning behind the Server Card's deliberate omission of primitives -(tools, resources, prompts): because a static manifest can drift from runtime, the Server -Card describes only identity, transport, and protocol versions, and even those declarations -are advisory rather than binding. Accordingly: +A Server Card is fetched _before_ the client connects, so its contents are unverified when +read. A Server Card SHOULD accurately reflect the server's runtime behavior: the values a +client observes once connected — the `serverInfo` (`name`, `version`) and `supportedVersions` +from [`server/discover`](https://modelcontextprotocol.io/specification/draft/server/discover), +the transport served at each `remotes[]` endpoint, and descriptive fields (`title`, +`description`, `icons`) — SHOULD NOT contradict the equivalent values declared in the Server +Card. + +As with the deliberately omitted primitives (tools, resources, prompts), a static manifest +can drift from runtime, so even the fields a Server Card does declare are advisory rather +than binding. Accordingly: - Clients MUST NOT treat Server Card contents as authoritative for security or access-control decisions. -- Clients SHOULD verify a Server Card's claims against the live connection after - connecting, and SHOULD prefer the values observed at runtime where the two disagree. +- Clients SHOULD verify a Server Card's claims against the live connection, preferring the + runtime values where the two disagree. ### Server Card Location @@ -256,16 +254,14 @@ information such as: ### Server Card Accuracy -Because a Server Card is consumed before the client connects, an inaccurate Server Card — -whether stale or deliberately crafted — is a mild confusion or downgrade vector. A Server -Card that overstates transport or protocol-version support, or otherwise misrepresents the -server's identity, can steer a client toward a weaker configuration or a misidentified -server before it has connected and observed the server's actual `server/discover` response. -This is why the consistency requirement is partly a security property and not merely a -matter of correctness. The normative protections against it live in +A Server Card is consumed before the client connects, so an inaccurate one — stale or +deliberately crafted — is a mild confusion or downgrade vector: one that overstates +transport or protocol-version support, or misrepresents the server's identity, can steer a +client toward a weaker configuration or the wrong server before it observes the actual +`server/discover` response. This makes the consistency requirement partly a security +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 once -established. +treat a Server Card as authoritative and reconcile it against the live connection. ### CORS Requirements diff --git a/schema.json b/schema.json index 5f18383..781fc9f 100644 --- a/schema.json +++ b/schema.json @@ -527,7 +527,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 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 fields a Server Card does declare (identity, transport, protocol\nversions) are advisory, not authoritative: they SHOULD be consistent with\nwhat a client observes at runtime (e.g. the server's `server/discover`\nresponse), and clients MUST NOT treat them as authoritative for security\ndecisions. See \"Consistency with Runtime Behavior\" in docs/discovery.md for\nthe normative requirement.\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 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.\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 07a5107..a8211d8 100644 --- a/schema.ts +++ b/schema.ts @@ -23,10 +23,9 @@ * * The fields a Server Card does declare (identity, transport, protocol * versions) are advisory, not authoritative: they SHOULD be consistent with - * what a client observes at runtime (e.g. the server's `server/discover` - * response), and clients MUST NOT treat them as authoritative for security - * decisions. See "Consistency with Runtime Behavior" in docs/discovery.md for - * the normative requirement. + * the server's `server/discover` response, and clients MUST NOT treat them as + * authoritative for security decisions. See "Consistency with Runtime + * Behavior" in docs/discovery.md for the normative requirement. * * The companion {@link Server} shape is a strict superset that adds local * package metadata for use cases like the MCP Registry's `server.json`.