Skip to content

feat(app): add an MCP server card at the well-known discovery path - #554

Draft
claude[bot] wants to merge 1 commit into
mainfrom
feat/mcp-server-card
Draft

feat(app): add an MCP server card at the well-known discovery path#554
claude[bot] wants to merge 1 commit into
mainfrom
feat/mcp-server-card

Conversation

@claude

@claude claude Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Requested via Slack thread

One of five PRs replacing #530, which bundled all five root-domain discovery fixes into a single change. Opened as a draft — see "Open questions" below.

Summary

Before: https://docs.page/.well-known/mcp/server-card.json returns a 404, swallowed by the .well-known catch-all route (confirmed against production). Agent-readiness scanners probe exactly this SEP-1649 path to detect MCP support, so the per-repository MCP servers docs.page already serves at /{owner}/{repo}/mcp are invisible to them.

After: that path returns a static SEP-1649 server card as application/json. docs.page has no single root MCP server, so the card's transport points at the server for docs.page's own hosted docs and its description spells out the per-repository pattern. The tool list mirrors the two tools the real server exposes, and resources is declared "dynamic" because each repository serves its own set.

In short: a scanner probing the well-known path discovers the MCP capability instead of a 404.

How: a new route at app/src/app/.well-known/mcp/server-card.json/route.ts serves the card from a build-time constant. It is a more specific segment than the existing .well-known/[[...slug]] catch-all, so it takes precedence — the same mechanism the existing .well-known/jwks.json route relies on. Cache policy comes from a new ROOT_MCP_SERVER_CARD_CACHE_HEADERS constant in app/src/proxy.ts (day-long edge TTL, hourly browser revalidation). The pre-existing MCP_CACHE_HEADERS constant, which serves the per-repo MCP route, is left untouched.

Open questions — why this is a draft

The .well-known approach was called too opinionated when it was discussed on 2026-08-25, and the card carries real unresolved problems. Each of these was checked against the current code and the live endpoint:

  1. The tool list is duplicated with nothing keeping it in sync. The card hardcodes read_doc_page and list_doc_files with their input schemas, while the actual definitions live in app/src/server/mcp/server.ts. Nothing links the two — no shared constant, no test, no codegen — so adding, renaming, or re-shaping a tool silently makes the card wrong. A comment asking future maintainers to keep it in sync is the only safeguard.

  2. The protocol version is a hardcoded pin, and this is subtler than it first looks. The card pins protocolVersion: "2025-11-25". Probing the live server: it echoes back whatever version a client asks for when it supports it (it returned 2025-06-18 and 2025-03-26 on request), and falls back to 2025-11-25 for anything it does not recognise — so 2025-11-25 is the server's current ceiling and the pin is correct today. The problem is that the ceiling is set by the @modelcontextprotocol/sdk dependency, not by anything in this repo, so a routine SDK bump moves it and leaves this constant quietly stale. Serving a single fixed version in a discovery document also misrepresents a server that negotiates per request. Worth deciding whether to derive it from the SDK or omit the field.

  3. The $schema URL does not resolve. https://static.modelcontextprotocol.io/schemas/mcp-server-card/v1.json returns a 404 (checked live). The card therefore points at a schema nobody can fetch, which is a poor look on a document whose whole purpose is machine consumption, and it means the card is not validated against anything.

Underlying all three: this is a hand-maintained static file describing a dynamic, per-repository system, added to satisfy external scanners. If the team is not happy with that trade, closing this in favour of no root card is a legitimate outcome — the other four PRs in the split stand on their own.

Scope

  • app/ (hosted site, MCP, Ask AI)
  • packages/cli/
  • packages/mdx-bundler/
  • docs/ (product documentation)
  • Repo / CI / other

Type of change

  • Bug fix
  • New feature
  • Documentation
  • Refactor / chore

Test plan

  • biome ci . clean (the check CI runs)
  • bun test — 140 pass, 0 fail
  • tsc --noEmit in app/ — clean
  • Production 404 at the well-known path confirmed live, establishing the "before"
  • Live MCP endpoint probed to check the protocol-version claim above
  • $schema URL fetched — 404

Notes for reviewers

  • Unlike the robots.txt and sitemap.xml routes in this split, this route is rendered on demand rather than prerendered, same as the existing .well-known/jwks.json route. The body is still a build-time constant and the CDN policy makes it effectively static at the edge.
  • Branch is cut from main, so this merges independently of the other four PRs.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Y5HaatshAzKUdXWYUbAC4a


Generated by Claude Code

https://docs.page/.well-known/mcp/server-card.json returned 404, swallowed by
the .well-known catch-all. Root-domain agent-readiness scanners probe this
SEP-1649 discovery path to detect MCP support, so the per-repo MCP servers
already served at /{owner}/{repo}/mcp were invisible to them.

Adds a static route serving a SEP-1649 server card. docs.page has no single
root MCP server, so the card's transport points at the server for docs.page's
own hosted docs and the description explains the per-repository pattern.
Cache policy via a new ROOT_MCP_SERVER_CARD_CACHE_HEADERS constant.

Opened as a draft: the well-known approach was called too opinionated, and the
card carries unresolved questions noted in the pull request description.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y5HaatshAzKUdXWYUbAC4a
@railway-app

railway-app Bot commented Sep 8, 2026

Copy link
Copy Markdown

🚅 Deployed to the docs.page-pr-554 environment in docs.page

Service Status Web Updated
docs.page ✅ Success (View Logs) Web Sep 8, 2026 at 10:29 am UTC

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

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.

2 participants