MCP server cards¶
ai-rulez can write an MCP Server Card (SEP-2127, Final) for each remote MCP server of the project: a small JSON document a client reads before it connects, naming the server and the endpoints to connect to.
The schema comes from an experimental extension
The card schema is schema.json of the experimental
server-card extension, generated from
schema.ts. ai-rulez pins it at commit 526201b (Apache-2.0), vendored under tests/conformance/schemas/mcp-server-card,
and the conformance tests check every card against it. The shape can change before a versioned schema is published.
Generate¶
ai-rulez publish --emit mcp-server-card # dist/emit/mcp-server-card/<server>.json, in the release
ai-rulez publish emit mcp-server-card --output-dir cards # only the cards, without a release
The emitter is also available as [[publish.emitters]] name = "mcp-server-card".
[[mcp_servers]]
name = "docs"
description = "Search the docs."
transport = "http"
url = "https://docs.acme.example/mcp"
headers = { Authorization = "Bearer ${DOCS_TOKEN}" }
becomes docs.json:
{
"$schema": "https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json",
"name": "io.github.acme/docs",
"description": "Search the docs.",
"version": "1.4.0",
"remotes": [
{
"type": "streamable-http",
"url": "https://docs.acme.example/mcp",
"headers": [{ "name": "Authorization", "isRequired": true, "isSecret": true }]
}
]
}
What a card holds¶
- Remote servers only. A card describes endpoints, not commands, so a stdio server gets no card; the emitter reports
each one it skips. A server with
transport = "http"(or aurland no transport) isstreamable-http;ssestayssse. - No secrets. Header values and environment values are never written. Each header becomes a required input named after
the header, marked
isSecretwhen its name is credential-like (such asAuthorization), it is listed as secret, or its value is a${VAR}reference. A URL with credentials is refused. A server whose URL has a query, a fragment or an unresolved${...}placeholder is skipped with a note. The URL path is otherwise published as written, so a key carried in it is a leak: a path segment that looks like a credential (a prefix such assk-,ghp_orAKIA, a shape the security scan knows, or an opaque token of 32 or more letters and digits, which includes a UUID) also skips the server, and the note never repeats the URL. - Name.
<namespace>/<server>, where the server part has any character outside letters, digits,.,_and-replaced by-. The namespace is the emitter optionnamespace, else the reversed[ard]publisher (acme.exampleisexample.acme), else derived from the repository (owner/nameandgithub.com/owner/nameareio.github.owner;host/owner/nameon another host is the reversed host followed by the owner, such astest.acme.git.acme). - Version. The emitter option
version, else the plugin version, else0.0.0. - Description. The server's description cut to the schema's 100 characters, or
MCP server <name>without one.
With ARD¶
The ARD manifest lists each remote server as an application/mcp-server-card+json entry whose data is the same
card, built by the same code; ARD additionally requires an https URL. Stdio servers are left out of the manifest.
Not generated¶
title, icons, repository, websiteUrl, URL variables, supportedProtocolVersions and _meta are not generated
yet, and validate does not read cards back; the conformance tests are the check.