Skip to main content
Glama

perfectui-mcp

A read-only MCP server that gives coding agents the real classes, markup and install instructions of Perfect UI 1.0.0, so they stop inventing pui-* classes.

Everything the server answers comes from one file, data/corpus-1.0.0.json, generated from the library's documents at the v1.0.0 tag and from the stylesheet of the published @chrissgon/perfectui@1.0.0 package. The server never writes, runs or downloads anything, and it makes no network requests.

The npm package is @chrissgon/perfectui-mcp.

Tools

Tool

Input

Returns

get_install

none

The npm command and the other package managers' commands, the CDN stylesheet and script URLs, and the import statements, all pinned to 1.0.0 (never latest).

list_components

none

Every document in the documentation's order (components, forms, layout, customization, guides): slug, title, section and a one-line description.

get_component

name: a slug from list_components, for example button

The document's full Markdown, its HTML examples and the pui-* classes they use.

search_docs

query (1 to 200 characters), limit (1 to 10, default 5)

The best matching sections: slug, heading, snippet and score. Prefix matching and one typo from four characters.

check_markup

html (up to 100,000 characters)

Every pui-* class in class or className attributes that Perfect UI 1.0.0 does not define (kind: "unknown"), with its line and the closest real class; and every Perfect UI 0.23.0 class that the migration guide renames (kind: "legacy"), with the guide's replacement.

Every tool declares readOnlyHint: true, destructiveHint: false, idempotentHint: true and openWorldHint: false, rejects unknown arguments, and returns structured content that matches its output schema.

A typical agent loop: list_components or search_docs to find the right document, get_component to copy its markup, then check_markup on the result before handing it over.

check_markup { "html": "<button class=\"pui-button\">Save</button>" }
→ line 1: pui-button → pui-btn (pui-button is not a class of Perfect UI 1.0.0; the Button document (get_component button) uses pui-btn)

Related MCP server: material-web-mcp

Install

Requirements: Node.js 20 or later and npm (the server is developed and tested on Node.js 24).

The server speaks MCP over stdio. An MCP client starts it with npx, which downloads the package on first use:

npx -y @chrissgon/perfectui-mcp

Run on its own, it waits for a client on stdin and prints one status line to stderr.

Client configuration

Many clients take a server as a command and its args inside an mcpServers object like the one below; check where your client keeps it:

{
  "mcpServers": {
    "perfectui": {
      "command": "npx",
      "args": ["-y", "@chrissgon/perfectui-mcp"]
    }
  }
}

Claude Code:

claude mcp add perfectui -- npx -y @chrissgon/perfectui-mcp

VS Code (.vscode/mcp.json in a workspace):

{
  "servers": {
    "perfectui": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@chrissgon/perfectui-mcp"]
    }
  }
}

To pin a version, write it in the package name: @chrissgon/perfectui-mcp@0.2.0.

To try it without a client, use the MCP Inspector's command-line mode. Leave -y out of the server command here: with it, Inspector 2.8.0 fails to start the server (npx still installs the package without asking, because its input is not a terminal).

npx -y @modelcontextprotocol/inspector --cli npx @chrissgon/perfectui-mcp --method tools/list
npx -y @modelcontextprotocol/inspector --cli npx @chrissgon/perfectui-mcp --method tools/call --tool-name get_component --tool-arg name=button

Use it as a library

From 0.2.0 the package also has a library entry, so a host can serve the same five tools over another transport. buildServer(corpus) returns a new McpServer (from @modelcontextprotocol/sdk) that is not connected yet; loadCorpus() reads and validates the bundled corpus. Importing the entry starts nothing. Types ship with the package.

import { buildServer, loadCorpus } from "@chrissgon/perfectui-mcp";
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";

const corpus = loadCorpus(); // once per process

// Stateless Streamable HTTP: a new server and transport for every request.
export async function handle(request: Request): Promise<Response> {
  const server = buildServer(corpus);
  const transport = new WebStandardStreamableHTTPServerTransport({ sessionIdGenerator: undefined, enableJsonResponse: true });
  await server.connect(transport);
  try {
    return await transport.handleRequest(request);
  } finally {
    await transport.close();
    await server.close();
  }
}

The entry also exports TOOL_NAMES, instructions, PACKAGE_VERSION, CORPUS_VERSION and the corpus types. The package reads data/corpus-1.0.0.json and its own package.json from files next to its code, so keep it external when you bundle (installed in node_modules, not inlined). The bin is unchanged: npx -y @chrissgon/perfectui-mcp is still the stdio server.

Run it from a checkout

git clone https://github.com/chrissgon/perfectui-mcp.git
cd perfectui-mcp
npm ci
npm run build

Then point the client at the built file, with your checkout's absolute path:

{
  "mcpServers": {
    "perfectui": {
      "command": "node",
      "args": ["/absolute/path/to/perfectui-mcp/dist/server.js"]
    }
  }
}
npx @modelcontextprotocol/inspector --cli node dist/server.js --method tools/list

Where the data comes from

npm run corpus rebuilds data/corpus-1.0.0.json:

  • Documents: one entry per link in the summary of the library's docs/README.md at the v1.0.0 tag (28 documents, including the migration guide). Each entry keeps the document's Markdown as written, its ```html blocks as examples, and the pui-* classes those examples use.

  • Classes: every .pui-* selector in dist/perfectui.css of the published package (51 classes). The package's npm integrity hash is recorded in the corpus.

  • Class renames: the tables, diff blocks and "survive as" sentence of the library's MIGRATION.md (38 renames from 0.23.0, each checked against the stylesheet). The guide starts at 0.23.0, so classes of older releases (0.7.x, for example) are not recognised; names the guide gives no pui-* class for (dark, dropdown-trigger, field-group-error) and the removed utilities are not reported.

  • Install instructions: read from the installation document and pinned to the package version; every CDN file and import is checked against the package's files and exports before it is written.

The library is read from PERFECTUI_SOURCE (a local checkout, as it is on disk) when set, else from .cache/library/v1.0.0/, else from one download of the tag's archive from GitHub. The package comes from .cache/package/1.0.0/, else from npm pack. Only this build step uses the network; the server does not.

Development

Task

Command

Tests (offline)

npm test

Type-check source, scripts and tests

npm run typecheck

Build dist/

npm run build

Rebuild the corpus

npm run corpus

Start on stdio

npm start

List what the package ships

npm pack --dry-run

Count invented classes in saved eval outputs (evals/cases.json)

npx tsx scripts/eval-markup.ts --runs evals/runs/<date>/<model>

The tests call every tool through the MCP SDK client over an in-memory transport, so they exercise the same schemas, validation and errors a real client sees. Design notes on the transport are in docs/spikes/stdio.md.

Releases

A release is a tag v<version> that matches package.json, pushed by the owner. .github/workflows/publish.yml then checks that the tag is on main, runs the same checks as CI, publishes to npm with trusted publishing (no npm token is stored; npm attaches provenance) and creates the GitHub release. A version with a prerelease suffix (1.0.0-beta.0) is published under the next dist-tag, never latest.

License

MIT, see LICENSE. data/corpus-1.0.0.json contains the Perfect UI documentation, also MIT, copyright Christopher Gonçalves. The summary parser in scripts/build-corpus.ts is adapted from perfectui-doc (MIT), so slugs match the documentation site.

Available Tools

5 tools
check_markupCheck markupA
Read-onlyIdempotent

Lists every pui-* class in the HTML that Perfect UI 1.0.0 does not define (kind "unknown"), with its line and the closest real class, and every Perfect UI 0.23.0 class that the migration guide renames (kind "legacy"), with the guide's replacement. Reads class and className attributes only; other classes (your own, Tailwind) are ignored. Call it on any markup before returning it.

Inputs: html (required). Returns: valid, checked, version, findings

get_componentGet a documentA
Read-onlyIdempotent

The full Markdown of one Perfect UI 1.0.0 document, with its HTML examples and the pui-* classes they use. Copy markup from the examples instead of writing classes from memory. Names come from list_components.

Inputs: name (required). Returns: file, slug, title, classes, +5 more

get_installGet install instructionsA
Read-onlyIdempotent

How to install Perfect UI 1.0.0: the npm command and the other package managers' commands, the CDN stylesheet and script URLs and the import statements, all pinned to this version, from the library's installation document (get_component with name installation explains when the script is needed).

Inputs: no named parameters. Returns: cdn, npm, source, imports, +3 more

list_componentsList documentsA
Read-onlyIdempotent

Every document of Perfect UI 1.0.0, in the documentation's order: components, forms, layout, customization and guides, each with its slug (the name get_component takes), title, section and one-line description.

Inputs: no named parameters. Returns: version, components

search_docsSearch the documentationA
Read-onlyIdempotent

Full-text search over the sections of every Perfect UI 1.0.0 document (prefix and typo tolerant). Returns the document slug (for get_component), the section heading (empty for the opening section), a snippet and a score, best first.

Inputs: query (required), limit. Returns: query, results

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.2/5.0

    Scored across 5 tools

    Disambiguation4/5

    get_install and get_component both retrieve documentation content for installation, but get_install is a specialized shortcut for install commands while get_component returns full Markdown of any document; descriptions clarify the boundary. Other tools (list_components, search_docs, check_markup) have clearly distinct purposes. Minor overlap prevents a perfect score.

    Naming Consistency5/5

    All tool names follow a consistent snake_case verb_noun pattern (get_install, list_components, search_docs, get_component, check_markup). This makes the set predictable and easy to parse.

    Tool Count5/5

    Five tools cover the essential operations for a UI library documentation server: installation lookup, listing documents, searching, retrieving a document, and validating markup. Each tool has a clear role and the set is well-scoped.

    Completeness5/5

    The surface covers installation, discovery (list, search), retrieval, and validation, including legacy class migration. No obvious dead ends for the stated purpose of helping agents use Perfect UI correctly; the documentation lifecycle is fully covered.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      Provides programmatic access to Material Web documentation and components for AI agents, enabling documentation search, template generation, and HTML validation.
      7
      18 npm
      1
      MIT
    • A
      license
      Not graded
      quality
      A
      maintenance
      Enables coding agents to ground UI work in real product screens by searching a catalogue for concrete screen references and design materials such as fonts, icons, and animated icons, then pulling the colors, typography, components, and provenance behind a chosen web screen. It also serves bundled skill documents, command playbooks, and connection diagnostics so an agent can settle a screen's states and acceptance criteria before building and verify the rendered result afterward.
      MIT