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>
11 KiB
Discovery
Protocol Revision: draft
MCP defines a discovery mechanism that enables clients to find available MCP servers on a domain without prior configuration. This mechanism complements the lifecycle handshake by answering where to connect, before the protocol establishes how to communicate.
MCP Catalog
An MCP Catalog is a JSON document published by an organization to advertise the MCP Server Cards relevant to its services.
The catalog MAY reference servers on different domains than the catalog itself — for
example, acme.org/.well-known/... MAY advertise servers operated by
mcp-server-host-saas.com on Acme's behalf. Clients can fetch this document to discover
servers and then retrieve individual Server Cards for connection
details.
The MCP Catalog format is a minimal, MCP-scoped subset of the AI Catalog specification. This alignment ensures that MCP Catalog entries can be used as-is within a full AI Catalog document, enabling a smooth migration path when the cross-protocol AI Catalog standard is finalized.
Well-Known URI
Organizations offering services accessible via MCP SHOULD publish an MCP Catalog at the domain users associate with the service. The MCP Catalog should live at:
/.well-known/mcp/catalog.json
This endpoint:
- MUST be accessible via HTTPS (HTTP MAY be supported for local/development use)
- MUST include appropriate CORS headers (see CORS Requirements)
- SHOULD include appropriate caching headers (see Caching)
Catalog Format
An MCP Catalog document is a JSON object that MUST contain the following members:
| Member | Type | Required | Description |
|---|---|---|---|
specVersion |
string | Yes | The version of the MCP Catalog format (currently "draft") |
entries |
array | Yes | An array of Catalog Entry objects. This array MAY be empty. |
Catalog Entry
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 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.
Example: Single Server
A domain hosting a single MCP server, using only the required fields:
{
"specVersion": "draft",
"entries": [
{
"identifier": "urn:mcp:server:com.example/weather",
"displayName": "Weather Service",
"mediaType": "application/mcp-server-card+json",
"url": "https://example.com/mcp/server-card"
}
]
}
Example: Multiple Servers
A domain hosting several MCP servers, each with its own server card:
{
"specVersion": "draft",
"entries": [
{
"identifier": "urn:mcp:server:com.acme/code-review",
"displayName": "Code Review Assistant",
"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-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-card+json",
"url": "https://acme.com/ci-cd/server-card"
}
]
}
Client Discovery Flow
Clients performing domain-level discovery SHOULD follow this procedure:
flowchart TD
A[Client wants to discover MCP servers on example.com] --> B[Fetch /.well-known/mcp/catalog.json]
B --> C{Valid catalog returned?}
C -->|Yes| D[Parse entries array]
C -->|No| E[Discovery unavailable for this domain]
D --> F[For each entry, fetch server card from url]
F --> G[Use server card to configure connection]
- Fetch
https://{domain}/.well-known/mcp/catalog.json - If a valid MCP Catalog is returned, iterate over the
entriesarray - For each entry, retrieve the server card from the entry's
url, expressing the Server Card media type via theAcceptheader (see Server Card Location) - 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
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 and connection details. Server Cards use the media type
application/mcp-server-card+json.
Server Cards do not enumerate primitives (tools, resources, prompts); those remain subject to runtime listing via the protocol's standard list operations.
A Server Card includes:
name— A unique identifier for the server in reverse DNS format (e.g.,com.example/weather)- Connection details — Transport type and endpoint URL
- Metadata — Human-readable name, description, and version
For the full Server Card specification, see SEP-2127: MCP Server Cards.
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 <streamable-http-url>/server-card, which we reserve for this purpose, though any unreserved URI (on any domain) is valid. MCP Servers SHOULD respect theapplication/mcp-server-card+jsonmedia 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 theapplication/mcp-server-card+jsonmedia type.
Concretely:
- A client requesting a Server Card SHOULD send
Accept: application/mcp-server-card+jsonon the GET request. (Acceptis the representation-negotiation header for a GET; the server echoes the negotiated type back in the responseContent-Type.) - The
/server-cardsuffix is appended to the server's streamable-HTTP URL, not to the domain root. A server that lives athttps://host/mcptherefore naturally yieldshttps://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-knownURI (e.g.,/.well-known/mcp/server-card)..well-knownis 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'surl, hosting the card under.well-knownadds no value — the card can live anywhere the Catalog points. (Note:.well-knownremains correct for the Catalog itself at/.well-known/mcp/catalog.jsonand 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 <streamable-http-url>with no suffix). In the Streamable HTTP transport aGETon 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-cardsuffix. - Nesting under a domain-root
/mcp/(e.g.,/mcp/server-card). In MCP,/mcpdenotes 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 athttps://host/mcp: there,https://host/mcp/server-cardis just<streamable-http-url>+/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
AI Catalog specification defines a
cross-protocol discovery standard (/.well-known/ai-catalog.json) capable of indexing
MCP servers, A2A agents, and other AI artifacts.
MCP Catalog entries are structurally compatible with AI Catalog entries. When the AI Catalog standard is finalized and adopted by the MCP steering committee:
- Domains MAY serve both
/.well-known/mcp/catalog.jsonand/.well-known/ai-catalog.jsonduring a transition period - MCP Catalog entries can be included directly in an AI Catalog document without modification
- Domains that want richer metadata (trust manifests, publisher identity, collections) can adopt the full AI Catalog format
Security Considerations
Information Disclosure
MCP Catalogs are publicly accessible by design. Catalog entries MUST NOT include sensitive information such as:
- Authentication credentials or tokens
- Internal network topology or private endpoints
- Proprietary business logic
CORS Requirements
Discovery endpoints MUST include appropriate CORS headers to allow browser-based clients:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
Access-Control-Allow-Headers: Content-Type
This is safe because MCP Catalogs contain only public metadata and are read-only.
Caching
Servers SHOULD include caching headers to reduce unnecessary requests:
Cache-Control: public, max-age=3600
Transport Security
MCP Catalogs MUST be served over HTTPS (TLS 1.2 or later) in production. HTTP MAY be used for local development only.