• TypeScript 100%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Tadas Antanavicius 10e958fa82
Server Cards: recommend /server-card over .well-known (resolves #12) (#22)
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>
2026-06-08 12:40:51 -07:00
.github/workflows Bootstrap repo with TypeScript source-of-truth and generated JSON Schema 2026-04-27 19:47:01 +00:00
docs Server Cards: recommend /server-card over .well-known (resolves #12) (#22) 2026-06-08 12:40:51 -07:00
examples Bootstrap repo with TypeScript source-of-truth and generated JSON Schema 2026-04-27 19:47:01 +00:00
scripts chore: format schema.json with prettier in generator 2026-05-18 15:50:17 +02:00
.gitignore Bootstrap repo with TypeScript source-of-truth and generated JSON Schema 2026-04-27 19:47:01 +00:00
AGENTS.md docs: add AGENTS.md (CLAUDE.md symlink) for AI coding agents (#20) 2026-06-08 08:16:20 -07:00
CLAUDE.md docs: add AGENTS.md (CLAUDE.md symlink) for AI coding agents (#20) 2026-06-08 08:16:20 -07:00
LICENSE Initial commit 2026-04-27 21:19:27 +02:00
package-lock.json Bump vm2 in the npm_and_yarn group across 1 directory 2026-05-08 14:45:46 +00:00
package.json Bootstrap repo with TypeScript source-of-truth and generated JSON Schema 2026-04-27 19:47:01 +00:00
README.md Server Cards: recommend /server-card over .well-known (resolves #12) (#22) 2026-06-08 12:40:51 -07:00
schema.json Server Cards: recommend /server-card over .well-known (resolves #12) (#22) 2026-06-08 12:40:51 -07:00
schema.ts Server Cards: recommend /server-card over .well-known (resolves #12) (#22) 2026-06-08 12:40:51 -07:00
tsconfig.json Bootstrap repo with TypeScript source-of-truth and generated JSON Schema 2026-04-27 19:47:01 +00:00

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 and is intended to be lifted directly into the main spec when Server Cards graduate (see Graduation plan below).

A prior attempt to land these types directly in the core spec (modelcontextprotocol#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) — 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 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

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. 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