Add experimental Server Cards support (SEP-2127)
Closed
DS
3mo ago+1760+1760+0123456789012345678901234567890123456789-0-0-0123456789
Summary
Adds first-class SDK support for MCP Server Cards (SEP-2127) under the experimental namespaces, so:
- servers can quickly generate a card from their identity and hand it to Starlette for serving, and
- clients can fetch and validate (ingest) one for pre-connection discovery.
A Server Card is a static metadata document (typically at https://<host>/.well-known/mcp/server-card) describing a remote server's identity, transport endpoints, and supported protocol versions. It deliberately omits primitive listings (tools/resources/prompts), which stay subject to runtime listing.
API
# Server: generate from identity, then serve via Starlette
from mcp.server.experimental.server_card import build_server_card, mount_server_card
from mcp.shared.experimental.server_card import Remote
card = build_server_card(
server, # low-level Server or MCPServer
name="io.modelcontextprotocol.examples/dice-roller", # reverse-DNS card name
remotes=[Remote(type="streamable-http", url="https://dice.example.com/mcp")],
)
app = server.streamable_http_app()
mount_server_card(app, card) # GET /.well-known/mcp/server-card
# or: Starlette(routes=[server_card_route(card)])
# or write a file: card.model_dump_json(by_alias=True, exclude_none=True)
# Client: ingest + validate
from mcp.client.experimental.server_card import fetch_server_card
card = await fetch_server_card("https://dice.example.com")
Layout
| Module | Purpose |
|---|---|
mcp.shared.experimental.server_card | Pydantic models (ServerCard, Server, Remote, Package, transports, args, ...), mirroring mcp.types conventions (camelCase wire format, reuses Icon) |
mcp.server.experimental.server_card | build_server_card (derive from a server's identity) + server_card_route / mount_server_card (Starlette) |
mcp.client.experimental.server_card | fetch_server_card / load_server_card / well_known_url |
Design notes
- Pure-Pydantic validation, consistent with the rest of
mcp.types— no separate JSON-Schema/CLI layer. Malformed cards raisepydantic.ValidationError; version ranges (which the field pattern can't express) are rejected by a validator. $schemadefaults to the canonical v1 URL so generation needs no boilerplate; ingestion is lenient about a missing$schema.- The
ServerCardvsServer(registryserver.json) split matches the spec;Serveraddspackages. - Experimental: importable from submodules only, not added to the top-level
mcpAPI surface.
Tests
- 28 tests across
tests/experimental/server_card/; 100% line + branch coverage on the three new modules (verified withstrict-no-cover). ruff+pyrightclean.- Round-trips the SEP-2127 conformance example shapes (minimal, templated remote with header variables, registry
Serverwith a package); server→client verified end-to-end over an in-memory ASGI transport.
Supersedes #2692 (which added this only as a standalone example app).