Skip to content

Server Cards: recommend /server-card over .well-known (resolves #12)#22

Merged
tadasant merged 7 commits into
mainfrom
server-card-placement
Jun 8, 2026
Merged

Server Cards: recommend /server-card over .well-known (resolves #12)#22
tadasant merged 7 commits into
mainfrom
server-card-placement

Conversation

@tadasant

@tadasant tadasant commented Jun 8, 2026

Copy link
Copy Markdown
Member

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+jsonapplication/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

  • npm run check passes (schema.json in sync with schema.ts + tsc --noEmit clean)
  • npm run generate run and regenerated schema.json committed in the same change
  • npm run validate passes — all 7 examples validate against the regenerated schema
  • npm run format run (prettier clean)
  • 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
  • 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
  • Examples updated and internally consistent with the new prose
  • Fresh-eyes subagent review performed; its one cosmetic finding was addressed and CI re-confirmed green
  • CI green (see checks on this PR)

🤖 Generated with Claude Code

Agent (Claude) and others added 5 commits June 8, 2026 02:18
Move the single-server Server Card off a `.well-known` path. Reserve
`GET <streamable-http-url>/server-card` as the recommended location while
allowing any unreserved URI, since the Catalog already carries each card's
`url` and clients never need to guess the location.

- docs/discovery.md: new "Server Card Location" convention + permanent
  "Alternatives considered" subsection (bare endpoint / SSE-GET overload,
  `.well-known`, `/mcp/`-`/MCP/` nesting); rewrite single- and multi-server
  example URLs to the new style.
- Use `Accept: application/mcp-server-card+json` on the GET request (the
  representation-negotiation header for a GET); `Content-Type` is the
  server's response header.
- Normalize the media type to `application/mcp-server-card+json` everywhere,
  removing the prior `application/mcp-server+json` inconsistency.
- schema.ts / schema.json / README.md: drop single-card `.well-known`
  phrasing for the new convention (Catalog + OAuth `.well-known` untouched).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address review nit: distinguish the rejected domain-root /mcp/ metadata
namespace from a streamable-HTTP URL that happens to end in /mcp, whose
/server-card suffix is exactly the recommended convention.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Capitalized /MCP/ was never a real candidate; remove it and keep the
rejected alternative focused on domain-root /mcp/ nesting.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… only

The application/mcp-server+json -> application/mcp-server-card+json rename
is handled in a separate PR. Revert the media-type strings here so this PR
changes only the Server Card placement convention and does not trample that
work.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The reserved-location blockquote and Accept example now name the media
type explicitly. Since this is new text the separate rename PR will not
touch, use the post-rename application/mcp-server-card+json directly.
Pre-existing application/mcp-server+json strings remain untouched for the
rename PR to handle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
dsp-ant
dsp-ant previously approved these changes Jun 8, 2026
SamMorrowDrums
SamMorrowDrums previously approved these changes Jun 8, 2026

@SamMorrowDrums SamMorrowDrums left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved with one minor comment.

Comment thread docs/discovery.md
Allow for any domain

@SamMorrowDrums SamMorrowDrums left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@tadasant tadasant merged commit 10e958f into main Jun 8, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Discovery: consider GET-on-server-URL instead of (or alongside) .well-known for single-server cards

3 participants