Airframe MCP
Airframe MCP (@airframeui/mcp) is a stdio MCP server for Cursor, Claude Code, Codex, VS Code, and other hosts. Coding agents use it to look up af-* patterns, --af-* tokens, and to validate markup on demand.
What Airframe is for agents: Airframe for AI agents. This page is how to connect.
It reads the catalogs that ship with @airframeui/core and @airframeui/tokens. It is not a second source of truth. Theme tools use @airframeui/theme.
MCP does not put CSS on the page. Still install @airframeui/core in the app.
The UI language is Structure → Patterns → Blocks → Blueprints. MCP looks up patterns and structure. For a whole section, start from Blocks (/llms-blocks.txt) and edit it. For a whole screen, start from Blueprints and change it. They are guides, not the only correct markup.
Do not dump catalogs into context. Lookup on demand. Do not invent af-* or --af-* names. Do not reimplement pattern CSS. Compose valid semantic HTML — catalog htmlSemantics lists E/W rules and nest selectors. validate_markup flags them (ruleId on each issue). Pattern look-alikes live on catalog entries as useCases / guidelines / criteria — read them on get_pattern.
Connect
Section titled “Connect”Requires Node.js 24 or later. Public packages share one version — keep MCP on the same version as @airframeui/core so lookups match the CSS in the app.
Treat MCP as optional. Cursor project MCP off, cloud agents, and CI often have no Airframe tools — see Without MCP.
Two ways to run the server when you do connect it. npx works before install. A dev dependency pins MCP in the lockfile next to core (recommended once the app is installed).
Each host has its own config file. Restart the airframeui server after saving.
| Host | File |
|---|---|
| Cursor | .cursor/mcp.json (or Cursor Settings → MCP) |
| Claude Code | .mcp.json |
| Codex | .codex/config.toml |
| VS Code | .vscode/mcp.json |
Cursor also reads ~/.cursor/mcp.json. Codex also reads ~/.codex/config.toml (project .codex/config.toml only in trusted projects). VS Code uses a top-level servers key, not mcpServers. Codex is TOML, not JSON.
Same mcpServers JSON as Cursor works in Claude Desktop (claude_desktop_config.json), Windsurf, and Gemini CLI (.gemini/settings.json).
Dev dependency (recommended)
Section titled “Dev dependency (recommended)”Install next to core. The lockfile pins both.
npm install -D @airframeui/mcpyarn add -D @airframeui/mcppnpm add -D @airframeui/mcpPoint the host at that install:
{
"mcpServers": {
"airframeui": {
"command": "node",
"args": ["./node_modules/@airframeui/mcp/dist/server.js"]
}
}
}{
"mcpServers": {
"airframeui": {
"command": "node",
"args": ["./node_modules/@airframeui/mcp/dist/server.js"]
}
}
}[mcp_servers.airframeui]
command = "node"
args = ["./node_modules/@airframeui/mcp/dist/server.js"]{
"servers": {
"airframeui": {
"type": "stdio",
"command": "node",
"args": ["./node_modules/@airframeui/mcp/dist/server.js"]
}
}
}Enable the server if the host prompts.
npx (default — works before install)
Section titled “npx (default — works before install)”Skip package.json if you want. Pin the version in the args — @latest can drift from core:
{
"mcpServers": {
"airframeui": {
"command": "npx",
"args": ["-y", "@airframeui/mcp@0.8.2"]
}
}
}{
"mcpServers": {
"airframeui": {
"command": "npx",
"args": ["-y", "@airframeui/mcp@0.8.2"]
}
}
}[mcp_servers.airframeui]
command = "npx"
args = ["-y", "@airframeui/mcp@0.8.2"]{
"servers": {
"airframeui": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@airframeui/mcp@0.8.2"]
}
}
}Ask the coding agent for Airframe markup. It should follow this loop:
search_patterns → get_pattern → get_example → compose af-* → validate_markupget_pattern is dense by default (dense: true). Pass dense: false when you need every class. When present, read useCases / guidelines / criteria — treat must* as hard limits; follow useInstead (catalog id) or prefer (utility).
Close matches
Section titled “Close matches”An unknown af-* class is a failed lookup. validate_markup still returns the usual error and suggestion, and adds closeMatches: catalog ids whose name or description scores against the invented class. Each hit has id, baseClass, why (the pattern description), and docsUrl when the catalog has one.
Use the first hit. If none of them fit, the reply has to name the ids and why. That rejection is the only path to a new pattern, and it belongs in the catalog, not in product CSS.
{
"valid": false,
"errors": [
{
"token": "af-dialog-box",
"suggestion": "af-dialog",
"message": "Unknown class: af-dialog-box. Close catalog match: dialog (af-dialog). Use it, or name why it does not fit."
}
],
"closeMatches": [
{
"id": "dialog",
"baseClass": "af-dialog",
"why": "Modal dialog component",
"docsUrl": "https://www.airframeui.com/docs/patterns/dialog"
}
]
}This is the markup contract, not a prompt trick. Hosts without MCP still have the same rule in @airframeui/core/rules: look up, then compose. The tool makes the miss visible.
Tokens: search_tokens / get_token. Prefer unsuffixed names in CSS (--af-color-background, not --af-color-background--dark).
Theme mapping is optional. Most apps override CSS variables. When mapping a foreign token file: generate_theme → lint_theme until clean. format defaults to auto (DTCG, Tokens Studio, CSS, Figma Variables, Style Dictionary, or an Airframe spec).
| Tool | Use |
|---|---|
search_patterns | Find a pattern or layout (ranks useCases / guidelines text). Call this first. |
get_pattern | One pattern or layout (name, base class, or alias — app-shell → app, hr → divider). Dense results include useCases, guidelines, criteria when present. |
get_example | Extra markup samples. After get_pattern. Same aliases as get_pattern. |
validate_markup | Unknown af-* / --af-*, raw ms / cubic-bezier, plus catalog htmlSemantics (E/W HTML rules). Issues include ruleId. Unknown classes include closeMatches. After composing. |
search_tokens | Find --af-* tokens. |
get_token | One token by exact name. Unknown names return suggestions. |
generate_theme | Token file contents or an Airframe spec → theme.css. Lint afterward. |
lint_theme | Lint theme.css or a spec. After generate_theme. |
list_patterns | Full inventory. Prefer search_patterns. |
list_tokens | Full inventory. Prefer search_tokens. |
map_tokens | Foreign tokens → spec + unmapped list. |
validate_theme | Map + lint inbound tokens in one step. |
Resources
Section titled “Resources”Hosts that support MCP resources can read these. Tools are enough if the host does not.
| URI | What it is |
|---|---|
airframe://ai | Short agent loop. Prefer tools; do not dump catalogs. |
airframe://rules | Full markup contract (@airframeui/core/rules). |
airframe://theme/rules | Theme generate/lint. Only when mapping a foreign token set. |
Without MCP
Section titled “Without MCP”If Airframe tools are not connected, do not guess docs URLs. Read the files that ship with @airframeui/core:
component-catalog.json(@airframeui/core/catalog) — pattern id, classes, guidance,useCases/guidelines/criteria,docsUrl,htmlSemanticsexamples.json(@airframeui/core/examples)dist/patterns/<id>.csswhen the example is not enoughbreaking.json(@airframeui/core/breaking) — version-to-version import/catalog renames
Pattern pages: /docs/patterns/{catalogId} (skip, nav-collapse). That short URL redirects to the nested page.
Related
Section titled “Related”- Airframe for AI agents — what this is: vocabulary, MCP, catalogs, endpoints
- AI Rules — markup contract
- Installation — CSS in the project
- Figma plugin — plugin how-to (
af theme export→ Update Figma) - Airframe → Figma — product overview, Theme Studio, and
@airframeui/theme - Theming — CSS variable overrides
- Theme package —
@airframeui/theme; Theme Studio for a browser UI - IntelliSense for Airframe — editor autocomplete
- Packages — npm inventory
- Blocks — section guides
- Blueprints — screen guides
- Package README: npm