MCP server discovery: where each document belongs
Four different documents describe an MCP server to a client that has not connected yet. They are easy to confuse, they live in different places, and only two of them are settled standards. This page says which is which.
| Document | Where it goes | Status |
|---|---|---|
Registry manifest (server.json) | Anywhere. /.well-known/mcp.json by convention | Official schema, unofficial path |
| Server Card | <streamable-http-url>/server-card | Experimental extension, SEP-2127 under review |
| AI Catalog | /.well-known/ai-catalog.json | Standards-track, site-wide |
| Protected-resource metadata | /.well-known/oauth-protected-resource | Ratified, RFC 9728 |
None of them replaces the others. A registry manifest tells a package manager how to install a server. A Server Card tells a client how to connect to a remote one. An AI Catalog tells a crawler which servers a domain runs at all. The RFC 9728 document tells a client how to authenticate once it has arrived.
What is /.well-known/mcp.json?
A convention, not a standard. No MCP specification defines that path.
It is still worth serving, because scanners, directories and agent-readiness tools probe for it, and a server that answers is easier to find than one that does not. Just do not treat it as compliance with anything.
The body is the MCP registry’s server.json,
and that part is official. The schema is published and versioned, currently
at https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json,
and it requires name, description and version. It carries installation
metadata: npm, PyPI, NuGet, OCI and MCPB packages, runtime hints, arguments and
environment variables.
So the file is an official document at an unofficial address.
What is a Server Card?
A static document describing one remote server: its identity, its transport endpoints, and the protocol versions it speaks. Enough for a client to connect, and nothing more.
Its reserved location is not a .well-known path. It is the streamable-HTTP URL
with /server-card appended:
GET https://mcp.example.com/server-card
A server hosted at https://example.com/mcp therefore serves its card at
https://example.com/mcp/server-card. The path namespacing comes free, and one
host can run several servers without collision.
The extension’s own discovery notes considered a .well-known URI and rejected
it, on the grounds that .well-known is for site-wide metadata while a single
server’s card is application-level. A card can live at any unreserved URI; the
/server-card suffix is only the predictable default.
Four fields are required: $schema, name, description and version.
name must be reverse-DNS with exactly one slash, and description is capped
at 100 characters. remotes, repository, title, icons and websiteUrl
are optional.
Cards deliberately do not list tools, resources or prompts. Those stay runtime listings, because a static file cannot keep up with them.
Serve the card as application/mcp-server-card+json, with
Access-Control-Allow-Origin: * so browser clients can read it, an ETag, and
Cache-Control: public, max-age=3600. Honour If-None-Match with a 304.
Read the status before you build on it
The schema lives in modelcontextprotocol/experimental-ext-server-card,
which describes itself as “not an accepted or official MCP extension”. SEP-2127
is under review, and the repository is meant to be lifted into the main
specification if the proposal is accepted.
There is a wrinkle worth knowing before you validate anything. The schema pins
$schema by regex to exactly
https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json,
and that URL returned 404 when we checked it on 2026-08-23. A conforming card
has to cite a schema that nobody can currently resolve.
A card is advisory, not authoritative
A client reads the card before it connects, so nothing in it has been verified at the point of reading. The specification is explicit that clients must not treat card contents as authoritative for security or access-control decisions, and should prefer the live connection wherever the two disagree.
That makes accuracy a security property rather than a matter of tidiness. A card
that claims more transports or more protocol versions than the server actually
serves can steer a client into a weaker configuration before it observes the
real server/discover response. Keep the card’s
supportedProtocolVersions equal to what the server will really accept. If you
reject older revisions, do not list them.
What is the AI Catalog?
The document that answers “which MCP servers does this domain run?”. It lives at
/.well-known/ai-catalog.json, and unlike the two above, being site-wide is
exactly why a .well-known path is right for it.
Each entry points at a Server Card, either by URL or inline:
{
"specVersion": "1.0",
"entries": [
{
"identifier": "urn:air:example.com:mcp:weather",
"type": "application/mcp-server-card+json",
"url": "https://example.com/mcp/server-card"
}
]
}
The AI Catalog is how a client learns a card’s address, which is why cards are allowed to live anywhere. It may also point at servers on other domains, so an organisation can advertise a server that somebody else operates for it.
What about protected-resource metadata?
/.well-known/oauth-protected-resource is the one document here that is a
ratified standard, and it answers a different question from the other three:
not “where is the server” but “how do I authenticate to it”. It has to be
same-origin with the endpoint it describes.
See authentication for how we score it and how
to add it. There is also /.well-known/owners.json,
which proves who controls a domain rather than describing a server.
What we serve
VerifyMCP runs a remote MCP server, so these are our four real addresses:
| URL | Document |
|---|---|
verifymcp.io/.well-known/mcp.json | Registry manifest, on the brand domain, so the service can be found from the name people know |
mcp.verifymcp.io/.well-known/mcp.json | The same manifest, same-origin with the endpoint |
mcp.verifymcp.io/server-card | Server Card |
mcp.verifymcp.io/.well-known/oauth-protected-resource | RFC 9728 metadata |
We serve the manifest twice on purpose. The copy on the brand domain is a pointer, and a pointer you can only fetch once you already know the address is not doing its job. The copy on the service origin is for consumers that expect a discovery document to share an origin with the endpoint it describes.
Both are generated from one file, so they cannot drift apart. The card reads its
name and version from that same file, which is what keeps it honest against the
running server: our test suite fails if the card’s protocol versions stop
matching what server/discover reports.
Where to start
Serve the registry manifest first. It is the most widely read of the four, the schema is stable, and it is what gets you listed.
Add protected-resource metadata next if your server does anything that needs authorising, because that one is a real standard and we score it.
Add a Server Card when you want clients to be able to connect without reading your documentation first, and accept that the format may still move.