WingoUI
ComponentsTemplatesDocsChangelogBlogAI agents
ThemePricing
  1. Home
  2. Blog
  3. Building UI with AI agents
  4. Component Library MCP: Make Agents Use Real Components
  1. Blog
  2. Building UI with AI agents
  3. Component Library MCP: Make Agents Use Real Components
Building UI with AI agents
Building UI with AI agents

Component Library MCP: Make Agents Use Real Components

SR
Serban Rusu · Founder of Wingo UI
Oct 9, 2026 · 25 min read

On this page

0%
  1. What is a component library MCP server?
  2. Why do coding agents invent components?
  3. What does an agent need besides the MCP server?
  4. Which tools should a component library MCP server expose?
    1. Search should return slugs and one line each
    2. Props need their defaults
    3. Keep tool output small
    4. Errors should say what to do next
    5. Server instructions are the first thing the agent reads
  5. How do I connect Claude Code, Cursor and Codex?
    1. Claude Code
    2. Cursor
    3. Codex
    4. Any other client
  6. What goes in the rules file?
  7. Where do llms.txt and Markdown docs fit?
  8. Why install through a registry instead of pasting code?
  9. What does a full agent session look like?
  10. How do agent-installed components stay up to date?
  11. How do I check what the agent built?
  12. Should you build an MCP server for your own design system?
  13. Where should I start?
  14. FAQ
    1. What is a component library MCP server?
    2. Do I still need a rules file if I connect an MCP server?
    3. Is llms.txt enough without an MCP server?
    4. Does the Wingo UI MCP server work without an account?
    5. Can I use the shadcn MCP server with Wingo UI?
    6. Which coding agents can connect to the Wingo UI MCP server?

TL;DR

A component library MCP server gives coding agents tools to search the catalog, read real props and design rules, and check installed versions, so they stop guessing APIs from training data. It works best with three companions: a short rules file that tells the agent when to call those tools, llms.txt and Markdown docs for agents without MCP, and a registry plus CLI that writes the real files and records their versions.

Published Oct 9, 2026

Ask Claude Code for a settings page and it will write one in a minute. It may also invent a <Button intent="primary"> your library never had, hardcode #3b82f6 where a token belongs and rebuild a date picker you already own. A component library MCP server fixes that at the source: it gives the agent tools to look up what exists, read the real props and install the real files. This guide covers how a React component library exposes itself to Claude Code, Cursor and Codex, the four pieces that make it work (an MCP server, a rules file, llms.txt and a registry), and the setup our CLI writes for you.

We build Wingo UI, so the examples use our server, CLI and registry, with output copied from release 1.7.0. The approach applies to any library, an internal design system included, and where another tool fits better, we say so. Shorter guides on agents and UI live under Building UI with AI agents: AGENTS.md vs CLAUDE.md vs Cursor rules for the rules file, a Claude Code shadcn setup for the shadcn MCP server next to a second registry, and a React AI chat UI guide for when the screen you are building is the chat itself.

What is a component library MCP server?

A component library MCP server is a Model Context Protocol (opens in a new tab) server that turns a UI library into tools an agent can call: search the catalog, read one component's props and usage, fetch the design rules, and compare installed versions with the latest release. The agent asks instead of remembering.

The client (Claude Code, Cursor, Codex, Gemini CLI) lists a server's tools and lets the model decide when to call them. A server runs as a local process over stdio or as a remote endpoint over Streamable HTTP. Remote servers are easier to keep current, because every client sees a new release the moment you deploy it.

The React component library MCP servers we checked come in three shapes. Here is how they compare, as of October 2026:

ServerRuns asWhat the agent getsWrites files into your project
shadcn MCPnpx shadcn@latest mcp (local)Browse, search and install items from every registry in components.json, private ones includedYes, through the shadcn CLI
MUI MCPnpx -y @mui/mcp@latest (local, stdio)Official Material UI docs and code examples, with links to real pagesNo, Material UI is an npm package
React Suite MCPnpx -y @rsuite/mcp@latest (local)get_component_props, list_components, list_hooks, search_componentsNo, React Suite is an npm package
Wingo UI MCPhttps://wingo-ui.com/mcp (remote, Streamable HTTP) or npx -y wingo-ui@latest mcp (local)Search, props with defaults, usage, blocks, design rules, theme tokens, update checks, changelogYes, through the Wingo UI CLI

Sources, checked in October 2026: the shadcn MCP docs (opens in a new tab), the Material UI MCP guide (opens in a new tab), the React Suite MCP guide (opens in a new tab) and our MCP server docs.

The first shape is a docs lookup. MUI and React Suite ship npm packages, so the agent needs correct props and working links; it never needs source files. If your app runs on Material UI, MUI's own server is the right choice.

The second shape is a registry installer. The shadcn docs describe listing, searching and installing from any shadcn-compatible registry in components.json; they do not mention design rules or update checks. If you pull from several registries, one shadcn server covers them all, which is a real advantage.

The third shape is what a source-copy library needs: docs, install and maintenance in one server. When components live in your repository as code you can edit, the agent has to know what the library offers, which version your project has and how the library expects to be used. That last part is the one a props table alone does not carry.

Why do coding agents invent components?

Because the model writes from training data, and training data predates your library version and leans toward the most common APIs. Without a way to check, the agent fills every gap with the likeliest guess: shadcn's API on a library that is not shadcn, a prop that was renamed two majors ago, a hex color where a semantic token belongs.

The monday.com engineering team described the same failure in How We Use AI to Turn Figma Designs into Production Code (opens in a new tab) (Rivka Ungar, February 2, 2026). Their first attempt, a Figma link pasted into Cursor with the Figma MCP, produced code that hardcoded colors and skipped their design system components. Their diagnosis: "the model had no understanding of what the design system actually was." They then built an MCP server for the design system and found it was still not enough on its own: "the MCP only provided knowledge; it didn't decide how or when that knowledge should be applied across a full UI."

A server full of correct facts does nothing if the agent never calls it, calls it after writing the code, or reads the props and then restyles everything with utility classes. So the server is one of four pieces.

What does an agent need besides the MCP server?

It needs a rules file that says when to call which tool, docs it can read without MCP, and a registry plus CLI that writes the files. Each piece answers a different question and changes at a different speed:

PieceWhat it answersHow often it changesIn Wingo UI
MCP serverWhat exists, its props and usage, the design rules, which versions are currentEvery releasehttps://wingo-ui.com/mcp, 10 tools and 1 prompt
Rules fileWhen to call which tool, how to install, what never to doRarelyA marked block in CLAUDE.md, AGENTS.md or GEMINI.md, a Cursor rule, a Claude Code skill
llms.txt and Markdown docsThe same facts as plain text for agents without MCPEvery release/llms.txt, a file per category, a .md twin of every docs page
Registry and CLIThe actual files, their dependencies and a version recordEvery release/r/<slug>.json in the shadcn format, npx wingo-ui@latest add

The split that matters: the rules file stays short and stable, and everything that changes lives behind the server. Prop tables pasted into a rules file go stale with the next release, and an agent tends to trust the copy already in its context over a tool it would have to call. Our rules file names tools and commands. It never lists a component's props.

Which tools should a component library MCP server expose?

A few read-only tools, shaped around what an agent does when it builds UI: find, read, follow the rules, install, stay current. Ours has ten:

  • search_components: find components, blocks, hooks and helpers by keywords.
  • list_categories: browse the categories with item counts.
  • get_component: props, parts, usage, dependencies, the install command and the source.
  • get_block: a full screen or section and the components it composes.
  • get_design_rules: tokens, sizes, motion, forms, overlays and mobile rules.
  • get_theme_tokens: the CSS variables for light and dark mode.
  • get_install_instructions: project setup for Next.js or Vite.
  • check_updates: compare installed items with the latest release.
  • get_changelog: recent releases and their notes.
  • get_account_status: whether the key has Pro, with the links to upgrade.

There is also one prompt, build_screen, that walks the agent through search, rules, install and composition. Every tool is marked read-only and idempotent in its annotations, and none of them writes to your disk. Writing files is the CLI's job.

Search should return slugs and one line each

A search result is a short list the agent can scan in one glance. This is the real answer from our server to search_components with the query "orders table with filters" and limit: 5, trimmed to the first three hits:

text
5 results for "orders table with filters":
- **Data Table** `data-table` (component, pro, v1.1.0): The admin table on TanStack Table v9: search, filters, sorting, bulk actions, pinning, resizing, virtualization and cards on phones.
- **Audit Log** `audit-log` (component, pro, v1.0.0): Who did what, when and to which record: a filterable activity log with day groups, before / after diffs and a CSV export.
- **Rule Builder** `rule-builder` (component, pro, v1.0.0): An if-this-then-that editor for automations: a trigger, conditions and ordered actions as sentence cards, read back as one sentence.
Next: get_component (or get_block for blocks) with a slug for props, usage and the install command.

Every hit carries its slug, kind, access tier and version, and the last line names the next tool, so the agent never has to guess which call turns a slug into props. The third hit is a weak match. That is fine: one line of description lets the agent skip it without spending a get_component call to find out.

Props need their defaults

get_component returns the props table the docs page shows, with types and defaults, plus parts, a usage example, the npm and registry dependencies, and the install command. Defaults are what keep generated code short. An agent that knows the Button defaults to type="button", tone="neutral" and size="md" writes <Button>Cancel</Button> instead of spelling out props it guessed. One that knows loading keeps the width and sets aria-busy does not wrap the button in its own spinner logic.

Below is that Button with the brand tone and a loading label set through props.

Click Pay now: the spinner takes the label's place, the width holds and the button ignores clicks until it settles
$ npx wingo-ui@latest add button
FreeButton docs

Without JavaScript, the demo is one solid "Pay now" button in the brand color; pressing it shows a spinner and "Paying" in the same width.

Keep tool output small

Large answers run into hard limits in the clients. As of October 2026, Claude Code's MCP docs (opens in a new tab) say it warns when a tool result passes 10,000 tokens, caps results at 25,000 tokens by default (MAX_MCP_OUTPUT_TOKENS raises it) and saves text results over 50,000 characters to a file instead of putting them in context.

Our Data Table is one file of 3,940 lines, about 150 KB of TypeScript. Its docs without source come back as about 18,000 characters, roughly 4,500 tokens. With the source attached (a Pro key), the same call grows past 160,000 characters and passes every one of those limits. So the rule for agents, and for anyone designing one of these servers, is: docs through MCP, files through the CLI. Call get_component with includeSource: false for large items and let npx wingo-ui@latest add write the code.

The same goes for rules. get_design_rules with the topic all returns about 45,000 characters, roughly 11,000 tokens at the usual four characters per token, which is already past Claude Code's warning line. The mobile topic alone is about 1,900 characters and forms about 4,200. Ask for the topic the task needs.

Errors should say what to do next

A tool error is a prompt the agent reads, so write it like one. An unknown slug answers with the closest matches and points back to search_components. A Pro item requested without a Pro key answers with the docs and this, word for word from our server (links trimmed, lines wrapped):

text
Login Page is part of Wingo UI Pro; the source is not included for this caller
(no API key; a free account at https://wingo-ui.com/sign-in unlocks the free items).
Do not re-create it from the docs.
Tell the user it needs Pro (https://wingo-ui.com/pricing); with a Pro key
(Authorization: Bearer wui_...) this tool returns the files and
`npx wingo-ui@latest add login-page` works after `npx wingo-ui@latest login`.
Free alternatives to look at: otp-input.

"Do not re-create it from the docs" is the most important sentence on the server. An agent that has just read a complete props table and a long interaction description has everything it needs to attempt a rewrite, and the result is a half copy that matches the docs on paper and nothing else: no version record, no updates, none of the edge cases the description summarizes in one line.

Server instructions are the first thing the agent reads

Claude Code turns on tool search by default, so only tool names and each server's instructions load at the start of a session; full tool definitions load when the model looks for them. The same docs say Claude Code cuts each tool description and each server's instructions at 2,048 characters by default. The instructions are your server's pitch to the model: what tasks it handles, when to search for its tools, and the rules that must survive truncation. Put "search before you write UI" in the first lines.

We learned the cost of that limit on our own server. Its instructions run 2,235 characters in release 1.7.0, so Claude Code drops the last sentence, the one that says never to re-create a component without the right key. The rule still reaches the agent because every refusal and the rules file repeat it. Count your characters, and repeat any rule that matters somewhere the model cannot miss.

How do I connect Claude Code, Cursor and Codex?

One CLI command writes both the MCP config and the rules for your agent. With WINGO_UI_API_KEY set it writes the HTTP configs below, which read the key from the environment so it never lands in your repository; without the variable it writes the local stdio proxy. You can also add the server by hand.

bash
npx wingo-ui@latest login # once per computer
npx wingo-ui@latest agents install claude # or codex, gemini, grok, cursor, all

Running it again changes nothing, and it keeps the other servers in your MCP configs. Where each agent's files go:

AgentMCP configRules
Claude Code.mcp.json.claude/skills/wingo-ui/SKILL.md and a marked block in CLAUDE.md
Codex~/.codex/config.tomlA marked block in AGENTS.md
Gemini CLI.gemini/settings.jsonA marked block in GEMINI.md
Grok.mcp.jsonA marked block in AGENTS.md
Cursor.cursor/mcp.json.cursor/rules/wingo-ui.mdc

Access works in three tiers. Without a key, search, docs, props, design rules and tokens all answer, with no source. A key from a free account (email only, no card) adds the source of the 75 free items. A Pro key adds the source of all 326. Create the key in your account and export it in your shell profile as WINGO_UI_API_KEY.

Claude Code

Claude Code stores MCP servers in three scopes: local (the default, private to you in ~/.claude.json), project (.mcp.json at the repository root, committed for the whole team) and user (all your projects). For a library the team shares, use project scope; .mcp.json expands ${VAR} from the environment, so the file is safe to commit:

json
{
"mcpServers": {
"wingo-ui": {
"type": "http",
"url": "https://wingo-ui.com/mcp",
"headers": {
"Authorization": "Bearer ${WINGO_UI_API_KEY}"
}
}
}
}

For a quick personal setup, the one-liner adds it in local scope:

bash
claude mcp add --transport http wingo-ui https://wingo-ui.com/mcp --header "Authorization: Bearer $WINGO_UI_API_KEY"

Run /mcp inside a session to see whether the server connected. If you already run other Claude Code MCP servers, this one sits next to them in the same file, and agents install keeps the entries it did not write. Our Claude Code shadcn tutorial walks through the shadcn MCP server, its skill and a second registry in the same project.

Cursor

Cursor reads .cursor/mcp.json in the project and ~/.cursor/mcp.json for every project. It uses its own variable syntax, ${env:NAME}, documented in Cursor's MCP docs (opens in a new tab):

json
{
"mcpServers": {
"wingo-ui": {
"url": "https://wingo-ui.com/mcp",
"headers": {
"Authorization": "Bearer ${env:WINGO_UI_API_KEY}"
}
}
}
}

Codex

Codex reads MCP servers from ~/.codex/config.toml (or a trusted project's .codex/config.toml). For a remote server, bearer_token_env_var names the variable that holds the token, as the Codex MCP docs (opens in a new tab) describe. Restart Codex after adding it so it picks up the server.

toml
[mcp_servers.wingo-ui]
url = "https://wingo-ui.com/mcp"
bearer_token_env_var = "WINGO_UI_API_KEY"

Any other client

Clients that cannot send a header to a remote server can run the local proxy. It reads the key saved by wingo-ui login and mirrors the remote tools, so new tools appear without updating anything:

json
{
"mcpServers": {
"wingo-ui": { "command": "npx", "args": ["-y", "wingo-ui@latest", "mcp"] }
}
}

What goes in the rules file?

When to call which tool, how to install, and what never to do, in as few lines as you can manage. This is the whole block we put in AGENTS.md, CLAUDE.md or GEMINI.md:

md
<!-- wingo-ui:start v=2 -->
## Wingo UI
This project builds its UI with Wingo UI (React 19 + Tailwind CSS v4 components installed as source, see `wingo-ui.json`).
- Before writing UI, use the `wingo-ui` MCP tools: `search_components` to find what exists (blocks for whole screens), `get_component` / `get_block` for props and usage, `get_design_rules` for tokens, sizes, motion and mobile rules. Never recreate a component the library has.
- Install with `npx wingo-ui@latest add <slug...>`. At the start of UI work run `check_updates` (or `npx wingo-ui@latest outdated`) and mention updates; update with `npx wingo-ui@latest update`.
- Semantic tokens only (`bg-background`, `bg-surface`, `text-muted-foreground`, `border-border`), configure components through props, keep `cn()`, `data-slot` and license headers in copied files. Check 390px and 1440px, light and dark.
- No MCP tools available? The CLI has `search`, `info`, `add`, `outdated`, `update`; the docs for models are at https://wingo-ui.com/llms.txt.
<!-- wingo-ui:end -->

A few choices in there are deliberate. Every bullet tells the agent what to do or when to do it. It names tools and commands but lists no component's props, because props change and tool names do not. It has a fallback for sessions without the MCP server, so the agent degrades to the CLI instead of guessing. And it carries a version marker: npx wingo-ui@latest agents status tells you whether your copy is current, and agents update rewrites only the text between the markers.

Claude Code also gets a skill with the longer workflow, and Cursor gets a project rule scoped to .tsx, .jsx and .css files. The full setup is on the coding agents docs page.

For an internal library, copy the structure: one line on what the library is, one on which tools to call before writing UI, one on how to install, one on styling, one fallback. Five lines that an agent follows beat fifty that it skims. Which of these files each agent reads, and how one AGENTS.md can serve Claude Code, Codex and Cursor at once, is in our AGENTS.md vs CLAUDE.md comparison.

Where do llms.txt and Markdown docs fit?

They serve assistants that can read a URL but have no MCP connection, and they back up the server when it is not configured. The llms.txt proposal (opens in a new tab), published by Jeremy Howard in September 2024, puts a Markdown file at the site root: an H1 with the name, a short summary, then sections of links. It also recommends a clean Markdown version of each page at the same URL with .md added, and its current version (updated August 2026) describes a rel="alternate" link of type text/markdown that points to it.

Our version follows that layout:

  • /llms.txt is the map: what the library is, the counts, pricing, the docs pages, the install commands, a link per category and one line per item with its Markdown link.
  • /llms/<category>.txt holds the item docs for one category, for example every table or every overlay.
  • Every docs page has a Markdown twin, like /components/button.md, linked from the HTML head.
  • /llms-full.txt has everything in one file, about 3.3 MB as of October 2026 (the docs of release 1.7.0 plus the blog posts).

That last file is the trap. A model handed 3.3 MB of docs either truncates it or spends its context on components it will never use. Treat llms.txt as a map and point the agent at the one category file or .md page the task needs. For a chat assistant that can fetch URLs, "read https://wingo-ui.com/components/data-table.md (opens in a new tab), then write an orders table with it" puts the real props in front of the model with one fetch.

What llms.txt cannot do is act. It cannot tell the agent which version your project has, whether your key covers an item, or write files with their dependencies. That is why it is the fallback in our rules and the MCP server is the default.

Why install through a registry instead of pasting code?

Because the registry and CLI write the exact files with their dependencies and record what they installed, and that record is the only way later releases can reach code you have edited. An agent that copies source out of a tool result skips all three steps.

Take the Login Page block. npx wingo-ui@latest add login-page writes three files into components/blocks, then pulls in the 16 registry items the block depends on (Alert, Avatar, Button, Checkbox, Input, OTP Input, Password Input, Separator, Toast and seven hooks and helpers), plus whatever those depend on, and installs its npm packages: motion, lucide-react, react-hook-form and zod. It records each item's version and content hash in wingo-ui.json and keeps a pristine copy under .wingo-ui/base/. When a release changes the block, npx wingo-ui@latest update runs a three-way merge between that pristine copy, your edited file and the new version, the way git merges branches.

An agent pasting code from get_block can miss a dependency, records nothing, and leaves you with files no tool can update. That is why every answer carries the install command and the rules say "install with the CLI" before anything about styling.

The registry also speaks the shadcn format. Free items install straight from their URL, for example npx shadcn@latest add https://wingo-ui.com/r/button.json, and Pro items install by name once the @wingo-ui registry with your key is in components.json, which also lets the shadcn MCP server install them. The trade-off is on our installation page: the shadcn CLI does not record versions, so wingo-ui update cannot merge later changes into files installed that way.

What does a full agent session look like?

Take a Next.js app that already has a wingo-ui.json and a plain prompt: "Build a sign-in page with two-step codes and an orders page with filters, using Wingo UI." With the server connected and the rules in place, the rules and server instructions lay out this path, and the prompt never names a tool:

  1. check_updates with the items from wingo-ui.json, and a one-line report of what changed upstream.
  2. search_components with "sign in page" and the kind block. On our server the first hit is login-page.
  3. get_block for login-page: the props, the components it composes and the install command.
  4. search_components with "orders table with filters", then get_component for data-table with includeSource: false.
  5. get_design_rules for the forms and mobile topics.
  6. One install for everything: npx wingo-ui@latest add login-page data-table (Button, Input and the rest come along as dependencies).
  7. Two pages built from the installed components, configured through their props.

Step 2 is the one a setup without the server skips. With nothing to search, an agent writes a sign-in form from scratch: two fields, a button, perhaps a "forgot password" link that leads nowhere. The block the search returns covers password, email link or code sign-in, Google, Apple and Microsoft buttons, two-step codes that lock for a minute after three wrong tries, and the whole password recovery flow. The page code is short because the block does the work:

tsx
// app/(auth)/login/page.tsx
"use client";
import { useRouter } from "next/navigation";
import { LoginPage } from "@/components/blocks/login-page";
// a non-2xx answer becomes the message the block shows above the form
async function post(url: string, body: unknown, error: string) {
const response = await fetch(url, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(body),
});
if (!response.ok) throw new Error(error);
}
export default function Page() {
const router = useRouter();
return (
<LoginPage
methods={["password"]}
showProviders={false}
twoFactor
onSignIn={(values) => post("/api/login", values, "The email or the password is not correct")}
onVerifyCode={(code, { backup }) => post("/api/login/verify", { code, backup }, "That code is not correct")}
onForgot={(email) => post("/api/password/forgot", { email }, "We could not send the email. Try again.")}
onSuccess={() => router.push("/orders")}
/>
);
}

A rejected promise from onSignIn shows its message in an alert above the form, and twoFactor sends a correct password to the code step. Three wrong codes lock the input for a minute whatever your handler does.

The pitfall is in the handlers the code leaves out. The block ships simulated ones so its demo works, and every on* prop you skip keeps its simulation. Without onVerifyCode, the two-step view accepts 123456. Without showProviders={false} or your own onProvider, the Google, Apple and Microsoft buttons spin for 1.2 seconds and then call onSuccess. An agent that wires onSignIn and stops ships a login page where a click on Google goes straight to /orders without signing anyone in. The get_block props table documents every one of these defaults, so the fix is the same as everywhere else: read the props, then wire each handler or turn the feature off.

The demo below runs on those simulated handlers, with the default methods and providers.

Sign in with any email and a password shorter than 8 characters to see the error alert, then choose "Email me a sign-in link" and send it to see the resend countdown
$ npx wingo-ui@latest add login-page
ProLogin Page docs

Without JavaScript, the demo shows the sign-in form: email and password fields, a "Remember me for 30 days" checkbox, the sign-in button, the emailed link option and buttons for Google, Apple and Microsoft.

The orders page follows the same pattern. The Data Table props the agent read decide most of the code: typed columns from createColumns, a badge column with a tone per status, a currency column with a footer sum, filters per column and quick filter chips.

tsx
// app/orders/orders-table.tsx
"use client";
import { useRouter } from "next/navigation";
import { Eye, Plus } from "lucide-react";
import { DataTable, createColumns } from "@/components/ui/data-table";
export type Order = {
id: string;
customer: string;
city: string;
status: "Paid" | "Pending" | "Refunded";
total: number;
placedAt: string;
};
const col = createColumns<Order>();
const columns = col([
col.accessor("customer", { header: "Customer", filter: "text", mobile: "title" }),
col.accessor("id", { header: "Order", mobile: "subtitle" }),
col.accessor("city", { header: "City", filter: "multi-select" }),
col.accessor("status", {
header: "Status",
type: "badge",
badge: { Paid: { tone: "success" }, Pending: { tone: "warning" }, Refunded: { tone: "neutral" } },
filter: "multi-select",
}),
col.accessor("total", { header: "Total", type: "currency", footer: "sum", filter: "number-range" }),
col.accessor("placedAt", { header: "Placed", type: "date", filter: "date-range" }),
]);
export function OrdersTable({ orders }: { orders: Order[] }) {
const router = useRouter();
return (
<DataTable
data={orders}
columns={columns}
getRowId={(order) => order.id}
caption="Orders"
locale="en-US"
searchPlaceholder="Search orders"
quickFilters={[{ id: "pending", label: "Pending", columnFilter: { id: "status", value: ["Pending"] } }]}
toolbarActions={[{ label: "New order", icon: <Plus />, primary: true, onSelect: () => router.push("/orders/new") }]}
rowActions={(order) => [{ label: "View", icon: <Eye />, onSelect: () => router.push(`/orders/${order.id}`) }]}
persistKey="orders"
/>
);
}

The page itself stays a server component that loads the rows and passes them down:

tsx
// app/orders/page.tsx
import { OrdersTable, type Order } from "./orders-table";
async function getOrders(): Promise<Order[]> {
// your database query goes here
return [{ id: "ORD-1042", customer: "Emma Carter", city: "New York", status: "Paid", total: 129, placedAt: "2026-10-02" }];
}
export default async function Page() {
const orders = await getOrders();
return (
<main className="mx-auto flex max-w-6xl flex-col gap-4 p-4 sm:p-8">
<h1 className="text-xl font-semibold text-foreground">Orders</h1>
<OrdersTable orders={orders} />
</main>
);
}

The split is deliberate. getRowId, rowActions and onSelect are functions (so is any custom cell renderer in the columns), and the App Router cannot pass functions from a server component to a client one. An agent that renders <DataTable> with inline callbacks straight from a server page.tsx gets that error at render time. Keeping the columns and callbacks in a client file and passing only plain rows avoids it.

Two more details come straight from the docs get_component returns. The mobile roles pick each card's title and subtitle below 768px, where the table becomes cards by default (mobileLayout="cards"). And persistKey remembers column visibility, order, widths, density and page size in local storage.

Search for a client, toggle the Overdue chip, then sort or filter from the toolbar; on a phone the rows become cards with a Load more button
$ npx wingo-ui@latest add data-table
ProData Table docs

Without JavaScript, the demo is a client table (client, city, status, owner, balance, last invoice) with a search field, quick filter chips such as Active and Overdue, and export and new client actions.

One more case to plan for: the Login Page and the Data Table are both Pro. Without a Pro key, steps 3 and 4 return the docs plus the refusal quoted earlier, and an agent that follows the rules reports the gap instead of rebuilding them from their props tables.

How do agent-installed components stay up to date?

The agent checks, you decide. At the start of UI work the rules ask for check_updates with the items in wingo-ui.json. The answer lists each update with its semver bump and the notes of every library release that touched the item, then the items that are current. Here is the real output for a project with an older Data Table and a current Button:

text
Latest Wingo UI release: 1.7.0.
1 update:
- **data-table**: 1.0.0 → 1.1.0 (minor)
- 1.2.0: with no rows to show the empty state stands alone and compact, without column headers spread over nothing; `showHeaderWhenEmpty` keeps them.
- 1.0.1: sticky header cells no longer drop down over the first row when the header is pinned while scrolling.
Update with `npx wingo-ui@latest update <slug...>` (a 3-way merge that keeps local edits); read breaking notes first.
Up to date: button

The numbers in front of the notes are library releases; the item itself goes from 1.0.0 to 1.1.0.

The Claude Code skill tells the agent to mention updates and run them only when you agree. An update is a code change in files you own, and it deserves the same review as any other diff. From the terminal the loop is three commands:

bash
npx wingo-ui@latest outdated # installed items vs the latest release
npx wingo-ui@latest diff data-table # your file vs upstream
npx wingo-ui@latest update # 3-way merge, with the release notes

The rules have their own version: agents status reports an old copy and agents update refreshes it. To keep your own edits to a managed file, delete its wingo-ui:managed line. The updates docs cover conflicts and the --theirs flag, and our guide to updating shadcn components without losing edits shows the same 3-way merge done by hand with git.

How do I check what the agent built?

Review it like a pull request from a fast junior developer who has read the docs. The server gets the first draft onto the right components; it does not replace looking at the result. Our checklist:

  • Hardcoded colors and radii. Search the diff for hex values, rgb( and arbitrary rounded-[...] classes. The rules ask for semantic tokens, and a stray hex color is easy to miss.
  • Rebuilt components. A new file under components/ that looks like a library item means the agent skipped search.
  • Restyling instead of props. A long class list on a Button often stands in for a variant, tone or size the agent did not read.
  • Simulated handlers. Blocks ship demo handlers for every on* prop. Compare the handlers the agent wired with the features left on screen, as in the login example above.
  • Phone width and both themes. At 390px tables should become cards and menus should open as bottom sheets (our mobile-first React components guide has the full list); light and dark should both hold up.
  • Library files. npx wingo-ui@latest diff <slug> shows whether the agent edited one. Edits are allowed, but they become merge work on the next update.

Should you build an MCP server for your own design system?

If several people or agents build UI on an internal library, yes. A UI component library MCP server is a smaller project than it sounds: ours is one file of about 220 lines on the TypeScript SDK (@modelcontextprotocol/server) plus four small tool modules, and most of the effort went into the data behind it. The protocol part was the easy bit. What we would tell a design system team, from building ours:

  • Start from metadata you already keep. Our tools read the same registry metadata that renders the docs pages. If your props live only in TypeScript types, extract them once into data the docs and the server share, or the two will drift.
  • Keep every tool read-only. Let the agent read; let your CLI or package manager write.
  • Return structured content and text. The model reads the text; scripts and future clients parse the structure.
  • Make outputs small and name the next step. Slugs in search, the source behind a flag, the next tool at the end.
  • Write errors as instructions. "Did you mean ..." and "do not re-create it" put the fix in front of the model at the moment it needs it.
  • Keep server instructions under 2,048 characters, with the "when to use this server" sentence first. Ours are 187 characters over in 1.7.0, and the sentence that falls off is one we care about.
  • Serve the release you deployed. One fresh server per request, backed by that deploy's registry, means agents never see stale props.
  • Offer HTTP and stdio. Remote HTTP for clients that send headers, a local proxy for the rest.

The MCP server for UI components we run answers without an account, so you can point any client at it and see these choices from the agent's side before you design your own.

Where should I start?

To try it, connect the server with npx wingo-ui@latest agents install claude (or your agent's name) and ask for a screen in plain words. A free account adds the source of the 75 free items to MCP answers, including the Button and the OTP Input; the CLI installs those without an account. The Login Page and Data Table are part of Pro, which covers all 326 items: $8 a month, $80 a year or $150 once, on the pricing page. The MCP server docs have the per-client setup and troubleshooting.

If you maintain your own library, an MCP server is the cheapest way we know to make agents use it correctly. Pair it with five lines of rules and an installer that records versions, and the agent stops inventing your components and starts installing them.

Components in this post

  • Button

    The button every screen starts with: five variants, six tones, three sizes plus icon sizes, and a loading state that never jumps.

    Free
  • Login Page

    The sign-in screen of Northwind CRM: password, email link or code, Google / Apple / Microsoft, two-step codes and the whole password recovery.

    Pro
  • Data Table

    The admin table on TanStack Table v9: search, filters, sorting, bulk actions, pinning, resizing, virtualization and cards on phones.

    Pro

FAQ

What is a component library MCP server?

It is a Model Context Protocol server that exposes a UI library to coding agents as tools: search the catalog, read one component's props with defaults and usage, fetch the design rules and check installed items for updates. The agent calls these tools instead of guessing an API from its training data.

Do I still need a rules file if I connect an MCP server?

Yes. The server supplies facts, but an agent does not always reach for a tool on its own. A few lines in CLAUDE.md, AGENTS.md or a Cursor rule tell it to search before it writes UI, to install with the CLI and never to rebuild a component the library has.

Is llms.txt enough without an MCP server?

It helps assistants that can only read URLs, but it cannot act on anything. It cannot install files, compare your installed versions with the latest release or tell the agent which items your plan includes.

Does the Wingo UI MCP server work without an account?

Yes for docs: search, props, usage, design rules and theme tokens answer without a key. A key from a free account (email only) adds the source of the 75 free items, and a Pro key adds the source of everything else.

Can I use the shadcn MCP server with Wingo UI?

Yes. Add the @wingo-ui registry to components.json, with your API key for Pro items, and the shadcn MCP server can search and install from it. It does not serve our design rules or update checks, and the shadcn CLI does not record versions, so wingo-ui update cannot merge later releases into files installed that way.

Which coding agents can connect to the Wingo UI MCP server?

npx wingo-ui@latest agents install writes ready configs and rules for Claude Code, Codex, Gemini CLI, Grok and Cursor. Any other client that runs local commands can use the stdio proxy, npx -y wingo-ui@latest mcp.

  • MCP
  • Claude Code
  • Cursor
  • Codex
  • AI agents
  • Registry

Share

SR

About the author

Serban Rusu

Founder of Wingo UI

Serban Rusu is the founder of Wingo UI. He builds the component library, its CLI and its MCP server, and writes about React interfaces that work well on phones and with AI coding agents.

More from Serban
Keep reading

Related posts

All posts
Building UI with AI agents

Claude Code shadcn Setup: MCP Server, Skill and CLAUDE.md

Claude Code shadcn setup, tested on shadcn 4.21.4: the MCP server, the skill, a second registry in its own folder, a CLAUDE.md block and prompts that work.

SRSerban Rusu·Oct 9, 2026·12 min read
Comparisons and alternatives

14 shadcn Alternatives in 2026: Price, Mobile and MCP

14 shadcn alternatives checked in October 2026: free and paid UI libraries by license, price, mobile behavior and MCP support, with a pick per use case.

SRSerban Rusu·Oct 9, 2026·19 min read
Component guides

How to Update shadcn Components Without Losing Edits

Update shadcn components without losing edits: what shadcn diff and add --diff show, why a 2-way diff hides whose change is whose, and how a 3-way merge works.

SRSerban Rusu·Oct 9, 2026·10 min read
Newsletter

Get new posts by email

New guides, tutorials and comparisons from the Wingo UI blog, sent when they are published.

No spam. Unsubscribe at any time.

WingoUI

Animated, configurable, mobile-first React components. Copy the source, make it yours, and let your coding agent build with it.

ComponentsTemplatesPricingBlogTheme

Component categories

  • Buttons & Actions
  • Inputs
  • Forms
  • Navigation
  • Overlays
  • Feedback
  • Data Display
  • Tables & Lists
  • Charts & Stats
  • Layout
  • Media
  • AI Kit
  • Text & Effects
  • Mobile
  • Commerce
  • Marketing Sections
  • Blocks
  • Hooks & Utilities
Wingo UI