What is an MCP server card?
An MCP server card is a JSON document published at /.well-known/mcp.json that advertises a Model Context Protocol server’s name, description, version, and (optionally) the transports it exposes. Clients like Claude Desktop, Cursor, and Cline fetch the card to auto-configure without users typing connection details by hand. The discovery spec is SEP-2127, a Working Group draft that superseded the earlier SEP-1649 proposal. See our validator for the full field-by-field requirements.
Where should mcp.json live?
Always at /.well-known/mcp.json on the domain serving your MCP endpoint. The /.well-known/ path is reserved by RFC 8615 for machine-readable discovery documents. If your server runs at api.example.com/mcp, the card belongs at api.example.com/.well-known/mcp.json — same origin as the server.
Step 1 — Decide your transport and endpoint
MCP supports several transports. Pick one that matches how clients reach your server:
streamable-http— remote HTTP server (recommended for public servers).sse— a Server-Sent Events endpoint.stdio— local server spawned by the client (Claude Desktop, Cursor).
Decide the endpoint URL agents will connect to — usually a path like https://api.yourdomain.com/mcp. You’ll reference this in the card’s remotes[].url field.
Step 2 — Create public/.well-known/mcp.json
In a Next.js project, add the file under public/ at the .well-known/ subpath. Next.js serves it at /.well-known/mcp.json with no additional config. For non-Next.js stacks, drop the file at whichever directory maps to your domain root and ensure your static server doesn’t hide dotfile-prefixed paths.
# from your Next.js project root
mkdir -p public/.well-known
touch public/.well-known/mcp.jsonStep 3 — Add the required Server Card fields
The minimum valid card contains three required fields: name, description, and version. Everything else — including $schema and remotes — is optional, but a card with no remotes entry gives clients nothing to connect to, so publish at least one.
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-10-17/server.schema.json",
"name": "acme-weather",
"description": "Live weather data for AI agents",
"version": "1.0.0",
"remotes": [
{ "type": "streamable-http", "url": "https://api.acme.dev/mcp" }
]
}
Each remotes[] entry needs a recognised type (streamable-http, sse, or stdio) and, for streamable-http/sse, a url. Plain "http" is not a recognised type.
Step 4 — Declare your authentication model
The current schema has no dedicated authentication field on the card. If your MCP endpoint requires auth, publish an OAuth Protected Resource metadata document at /.well-known/oauth-protected-resource per RFC 9728 and SEP-985 — clients discover it by calling your endpoint, getting a 401, and following the challenge there. That document declares your authorization server, scopes, and token endpoints. Anonymous servers can skip it entirely.
Step 5 — Verify with curl and validate
Deploy or start your dev server, then send a HEAD request to confirm the file returns HTTP 200 with Content-Type: application/json.
curl -I https://api.acme.dev/.well-known/mcp.json
# Expected response:
# HTTP/2 200
# content-type: application/json
Then run your URL through the MCP card validator to confirm it validates — all required fields present, each remotes[] transport type recognized, and (if applicable) OAuth metadata reachable.
How do I generate mcp.json dynamically?
When your server’s capabilities or endpoint vary by environment, generate the card from code instead of shipping a static file. Use a Next.js route handler at src/app/.well-known/mcp.json/route.ts:
// src/app/.well-known/mcp.json/route.ts
import { getServerInfo } from "@/lib/mcp";
export async function GET() {
const info = await getServerInfo();
const card = {
$schema:
"https://static.modelcontextprotocol.io/schemas/2025-10-17/server.schema.json",
name: info.name,
description: info.description,
version: info.version,
remotes: [
{ type: "streamable-http", url: process.env.MCP_ENDPOINT },
],
};
return Response.json(card, {
headers: {
"Cache-Control": "public, max-age=3600",
},
});
}
Response.json() sets the correct application/json Content-Type automatically. Add a sensible Cache-Control header so clients don’t hammer the route on every connect.
Common pitfalls when publishing mcp.json
- Card on a different origin than the server. If your MCP endpoint is
api.example.com/mcp, the card must be atapi.example.com/.well-known/mcp.json— not on the apex domain. - Missing OAuth metadata when auth is required. If your MCP endpoint requires auth but
/.well-known/oauth-protected-resourcereturns 404, clients can’t complete the handshake. There’s no card field for this — it’s discovered from the endpoint’s own 401 response. - Wrong Content-Type. If your CDN serves the card as
text/plainortext/html, clients may refuse to parse it. Confirmapplication/jsonin the response headers. - Pointing $schema at the superseded SEP-1649 URL. An earlier draft used a
schemas/mcp-server-card/schema URL that now 404s. If you set$schema, point it at the current schema instead. - Auth-gated paths under /.well-known/. Some frameworks apply auth middleware to every route by default. Confirm
/.well-known/mcp.jsonis publicly fetchable without credentials.
Frequently asked questions
- Does my MCP server need a server card?
- Yes if you want auto-discovery. Without /.well-known/mcp.json, users have to type your server's URL and config by hand into their MCP client. With the card, clients like Claude Desktop or Cursor can fetch your domain, find the card, and offer a one-click install. It's the same dynamic as robots.txt — voluntary, but expected for production servers.
- What's the difference between mcp.json and server-card.json?
- An earlier proposal, SEP-1649, used /.well-known/mcp/server-card.json and a different card shape; it's since been superseded by SEP-2127, which settled on the simpler /.well-known/mcp.json path and a server.json-derived shape. Some clients still try both paths — publish at /.well-known/mcp.json to cover the canonical location; add a copy at /.well-known/mcp/server-card.json if you want belt-and-braces.
- Do I need to publish OAuth metadata too?
- Only if your MCP endpoint requires authentication. There's no authentication field on the card itself — clients discover the requirement by calling your endpoint, getting a 401, and following the challenge to /.well-known/oauth-protected-resource per RFC 9728. That document declares your authorization server, supported scopes, and token endpoints. Anonymous servers can skip it entirely.
- Where exactly should the file be served from?
- At /.well-known/mcp.json on the domain agents will use to reach your MCP server. If your server runs at api.example.com/mcp, publish the card at api.example.com/.well-known/mcp.json (not example.com/.well-known/mcp.json). The card and the server must share an origin.
- Can I version my MCP server card?
- The card's version field is your server's own release version — update it whenever your server changes. If you declare $schema, point it at the schema you're conforming to; bump it independently if you move to a newer schema snapshot. There's no separate protocolVersion field on the card in the current schema.