Resolves #12. ## What & why Moves the **single-server Server Card** off a `.well-known` path. We reserve `GET <streamable-http-url>/server-card` as the recommended location while allowing **any unreserved URI** — the Catalog (`/.well-known/mcp/catalog.json`) is the discovery entrypoint and already carries each card's `url`, so clients never need to guess where a card lives. Adopts wording close to the resolution discussed in #12 (credit: Darrel Miller's point that `.well-known` is for *site-wide* metadata, not application-level metadata like an individual server's card; proposed wording from @SamMorrowDrums and @tadasant): > MCP Servers MAY host their Server Card at `GET <streamable-http-url>/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. ### Content negotiation A client fetching a Server Card requests its preferred representation with the `Accept` header (`Accept: application/mcp-server-card+json`) — the request-side content-negotiation header for a GET. The server echoes the type it actually served back in the response's `Content-Type`. > **Note on media type:** this PR is scoped to *placement* only and does **not** perform the `application/mcp-server+json` → `application/mcp-server-card+json` rename — that is handled in a separate PR. So the two coexist deliberately here: > - **Pre-existing strings** (catalog-entry description, the four example `mediaType` values, validation prose, and the "Server Cards use the media type" line) are left as `application/mcp-server+json`, untouched, for the rename PR to sweep. > - **New prose introduced by this PR** (the reserved-location blockquote and the `Accept`-header example in the "Server Card Location" section) names the type explicitly as the **post-rename `application/mcp-server-card+json`**, since the rename PR's diff is against `main` and would not touch text that doesn't yet exist there. > > The temporary mix resolves to a single consistent type once both PRs land. ## Rationale for `/server-card` (also captured permanently in `docs/discovery.md` → "Alternatives considered") - **Not `.well-known`:** site-wide vs. application-level metadata; the Catalog already provides the `url`, so `.well-known` adds no value for the card. - **Not the bare streamable-HTTP endpoint** (`GET <url>` with no suffix): a GET there already opens the SSE stream in Streamable HTTP. Hosting the card there overloads the connection-establishing endpoint and forces content negotiation to disambiguate. Spec-*allowed*, explicitly **not recommended** — this is the primary motivation for a distinct suffix. - **Not domain-root `/mcp/` nesting:** `/mcp` denotes the *transport endpoint itself* in MCP's canonical-URI examples; there's no precedent for `/mcp/` as a metadata sub-namespace, and it collides conceptually with "the JSON-RPC endpoint." - **Elegant consequence:** because the suffix is appended to the streamable-HTTP URL, a server at `https://host/mcp` naturally yields `https://host/mcp/server-card` — path-namespacing for free. ## Scope guardrail This applies **only to the single-server Server Card**. `.well-known` is unchanged and remains correct for the **Catalog** (`/.well-known/mcp/catalog.json`) and OAuth metadata (`/.well-known/oauth-protected-resource`, etc.) — those are genuinely site-wide. The doc calls this out explicitly so it doesn't read as "abandon `.well-known` everywhere." ## Files changed - **`docs/discovery.md`** — new "Server Card Location" section with the reserved convention + `Accept`-header guidance; permanent "Alternatives considered" subsection; rewritten single- and multi-server example URLs (`https://example.com/mcp/server-card`; `https://acme.com/code-review/server-card`, `/docs-search/server-card`, `/ci-cd/server-card`). - **`schema.ts`** — updated the two `.well-known` doc comments (`ServerCard` and `Server`) to the new convention. - **`schema.json`** — regenerated from `schema.ts` (`npm run generate`). - **`README.md`** — updated the "What is a Server Card?" line to the new convention, normalizing the pre-existing README-vs-schema `.well-known` mismatch. ## Verification - [x] `npm run check` passes (schema.json in sync with schema.ts + `tsc --noEmit` clean) - [x] `npm run generate` run and regenerated `schema.json` committed in the same change - [x] `npm run validate` passes — all 7 examples validate against the regenerated schema - [x] `npm run format` run (prettier clean) - [x] No single-server-card `.well-known` references remain in `README.md`, `schema.ts`, `schema.json`, or `docs/discovery.md` (verified via grep); remaining `.well-known` references are Catalog/OAuth/the "Alternatives considered" explainer only - [x] Pre-existing media-type strings left untouched — `git diff origin/main` shows zero changes to existing `application/mcp-server+json` strings (rename owned by a separate PR); only the new placement prose names the post-rename `application/mcp-server-card+json` - [x] Examples updated and internally consistent with the new prose - [x] Fresh-eyes subagent review performed; its one cosmetic finding was addressed and CI re-confirmed green - [x] CI green (see checks on this PR) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Agent (Claude) <peter@tadasant.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
76 lines
4.9 KiB
Markdown
76 lines
4.9 KiB
Markdown
# MCP Server Cards (Experimental Extension)
|
|
|
|
> #### **Status:** Experimental. This work is for prototyping and feedback only, and is not an accepted or official MCP extension.
|
|
|
|
This repository defines a TypeScript source-of-truth and generated JSON Schema for **MCP Server Cards** — a static metadata document that describes a remote MCP server enough for clients to discover and connect to it before initialization.
|
|
|
|
It tracks [SEP-2127](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2127) and is intended to be lifted directly into the main spec when Server Cards graduate (see [Graduation plan](#graduation-plan) below).
|
|
|
|
A prior attempt to land these types directly in the core spec ([modelcontextprotocol#2652](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2652)) is being relaunched here as an experimental extension while the SEP itself is still under review.
|
|
|
|
## What is a Server Card?
|
|
|
|
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)
|
|
- Optional registry-style extension metadata (`_meta`)
|
|
|
|
The companion **Server** document is a strict superset that adds locally-runnable `packages` — it is the shape the [MCP Registry](https://github.com/modelcontextprotocol/registry) uses for `server.json`.
|
|
|
|
Server Cards intentionally omit primitive listings (tools, resources, prompts) — those remain subject to runtime listing via the protocol's standard list operations.
|
|
|
|
## Layout
|
|
|
|
```
|
|
schema.ts # TypeScript source of truth (single file)
|
|
schema.json # Generated JSON Schema 2020-12 (do not edit by hand)
|
|
scripts/
|
|
generate-schema.ts # Generates schema.json from schema.ts
|
|
validate-examples.ts # Validates examples/ against the generated schema
|
|
examples/
|
|
ServerCard/{valid,invalid} # Example Server Card documents
|
|
Server/{valid,invalid} # Example Server (registry-shaped) documents
|
|
```
|
|
|
|
The generated `schema.json` is checked into the repo so consumers can grab it without running the toolchain.
|
|
|
|
## Working on the schema
|
|
|
|
```bash
|
|
npm install
|
|
npm run generate # regenerates schema.json from schema.ts
|
|
npm run validate # runs all examples through ajv against schema.json
|
|
npm run check # asserts schema.json is in sync with schema.ts and tsc passes
|
|
npm run format # prettier write
|
|
```
|
|
|
|
When you change `schema.ts`, always run `npm run generate` and commit the updated `schema.json` in the same commit. CI runs `npm run check` and will fail if they drift.
|
|
|
|
## Schema URL conventions
|
|
|
|
The `$schema` field on every document MUST be a URL of the form:
|
|
|
|
```
|
|
https://static.modelcontextprotocol.io/schemas/v1/<name>.schema.json
|
|
```
|
|
|
|
Schema URLs are versioned by their `vN` segment rather than by date, so additive revisions of the v1 shape don't bump every published document's `$schema`. Breaking changes would publish a `v2` family.
|
|
|
|
## Graduation plan
|
|
|
|
When the SEP is accepted and Server Cards graduate from this experimental extension:
|
|
|
|
1. The contents of `schema.ts` in this repo move into `schema/draft/schema.ts` of [`modelcontextprotocol/modelcontextprotocol`](https://github.com/modelcontextprotocol/modelcontextprotocol). The two `MetaObject` and `Icon` definitions inlined here at the bottom of `schema.ts` already exist in the main spec and are dropped from the migration.
|
|
2. The main spec's existing `scripts/generate-schemas.ts` regenerates `schema/draft/schema.json` (and downstream `docs/specification/draft/schema.mdx`) — no per-extension generator is required there.
|
|
3. Published documents update their `$schema` to point at the main spec's hosted schema URL (e.g., `https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json` served from `modelcontextprotocol/static`).
|
|
4. This repository is archived with a pointer to the relevant section of `schema/draft/schema.ts` in the main spec.
|
|
|
|
The `schema.ts` in this repo is deliberately structured to be copy-pasted into the main spec's `schema/draft/schema.ts` with no transformation other than removing the inlined `MetaObject` / `Icon` definitions.
|
|
|
|
## References
|
|
|
|
- [SEP-2127: MCP Server Cards (PR)](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2127)
|
|
- [SEP-2133: Extensions framework (PR)](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2133)
|
|
- Abandoned core spec PR (superseded by this repo): [modelcontextprotocol#2652](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2652)
|
|
- [MCP Registry `server.json` schema](https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/generic-server-json.md)
|