Skip to content

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.

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.

HostFile
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).

Install next to core. The lockfile pins both.

npm install -D @airframeui/mcp

Point the host at that install:

{
  "mcpServers": {
    "airframeui": {
      "command": "node",
      "args": ["./node_modules/@airframeui/mcp/dist/server.js"]
    }
  }
}

Enable the server if the host prompts.

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"]
    }
  }
}

Ask the coding agent for Airframe markup. It should follow this loop:

search_patterns → get_pattern → get_example → compose af-* → validate_markup

get_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).

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).

ToolUse
search_patternsFind a pattern or layout (ranks useCases / guidelines text). Call this first.
get_patternOne pattern or layout (name, base class, or alias — app-shell → app, hr → divider). Dense results include useCases, guidelines, criteria when present.
get_exampleExtra markup samples. After get_pattern. Same aliases as get_pattern.
validate_markupUnknown af-* / --af-*, raw ms / cubic-bezier, plus catalog htmlSemantics (E/W HTML rules). Issues include ruleId. Unknown classes include closeMatches. After composing.
search_tokensFind --af-* tokens.
get_tokenOne token by exact name. Unknown names return suggestions.
generate_themeToken file contents or an Airframe spec → theme.css. Lint afterward.
lint_themeLint theme.css or a spec. After generate_theme.
list_patternsFull inventory. Prefer search_patterns.
list_tokensFull inventory. Prefer search_tokens.
map_tokensForeign tokens → spec + unmapped list.
validate_themeMap + lint inbound tokens in one step.

Hosts that support MCP resources can read these. Tools are enough if the host does not.

URIWhat it is
airframe://aiShort agent loop. Prefer tools; do not dump catalogs.
airframe://rulesFull markup contract (@airframeui/core/rules).
airframe://theme/rulesTheme generate/lint. Only when mapping a foreign token set.

If Airframe tools are not connected, do not guess docs URLs. Read the files that ship with @airframeui/core:

  1. component-catalog.json (@airframeui/core/catalog) — pattern id, classes, guidance, useCases / guidelines / criteria, docsUrl, htmlSemantics
  2. examples.json (@airframeui/core/examples)
  3. dist/patterns/<id>.css when the example is not enough
  4. breaking.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.