Describe the intent.
A hero with subtle motion. A cursor with a trailing effect. Start with what it should do, even if you don’t know its name.
matchcn.dev
matchcn gives your coding agent access to 4,578 components across 14 registries.
Describe the UI you need. Get matching components and their install commands.
Paste this into your coding agent to configure matchcn.
npx matchcn
Run the stdio MCP server with npx. To make the tool available to your agent, add the MCP configuration to your client.
Node.js 20+ · npm / npx
Add the config to your client, connect the server, and start with an English brief for the most reliable results.
# Start the MCP server $ npx matchcn
pick_component(brief, registry?, maxResults?)A semantic index for shadcn-format components. Describe behavior, motion, or layout in plain English. matchcn finds real components across fourteen registries and returns an explanation, a source, and an install command.
Choose a real test from the repo.
a dense bento grid for a landing page



4,578 components. Fourteen indexed registries.
One tool to query them.
0.90 recorded selection confidenceFit signal, not an accuracy score
layout section/layout sectionstatic/staticdense/densedisplay only/display only0.18/0.270.00/0.02npx shadcn@latest add https://magicui.design/r/bento-grid.jsonThis component is a named example in the density criteria. This recorded result is not an independent accuracy test.
{
"outcome": "confident",
"message": "Selected \"bento-grid\" from magicui.",
"chosen": {
"name": "bento-grid",
"registry": "magicui",
"title": "Bento Grid",
"installCommand": "npx shadcn@latest add https://magicui.design/r/bento-grid.json",
"sourceUrl": "https://magicui.design/r/bento-grid.json",
"confidence": 0.9,
"reasons": [
{
"dimension": "category",
"briefWants": "layout-section",
"componentHas": "layout-section",
"matched": true,
"weight": 0.98
},
{
"dimension": "motion",
"briefWants": "static",
"componentHas": "static",
"matched": true,
"weight": 0.98
},
{
"dimension": "visual_density",
"briefWants": "dense",
"componentHas": "dense",
"matched": true,
"weight": 1
},
{
"dimension": "interaction_model",
"briefWants": "display-only",
"componentHas": "display-only",
"matched": true,
"weight": 0.76
},
{
"dimension": "needs_external_data",
"briefWants": 0.18,
"componentHas": 0.27,
"matched": true,
"weight": 0.64
},
{
"dimension": "decorative_only",
"briefWants": 0,
"componentHas": 0.02,
"matched": true,
"weight": 1
}
]
},
"resolveUsed": true,
"decisionsSpent": 7
}A hero with subtle motion. A cursor with a trailing effect. Start with what it should do, even if you don’t know its name.
Components are tagged across seven dimensions. Deterministic ranking weighs those tags by confidence; Resolve evaluates the candidates.
Your agent gets the original registry’s shadcn install command. Component code comes directly from its creator.
Copy a prompt for your client. The agent configures matchcn; you review the changes.
› Configure the matchcn MCP server
✓ .mcp.json
+ matchcn → npx -y matchcn
› Find a dense bento grid ▌
Paste it in your coding session — Claude adds the MCP configuration to your project.
+ [mcp_servers.matchcn]
+ command = "npx"
+ args = ["-y", "matchcn"]Give Codex the same task — review the configuration, then ask for a component.
{
"mcpServers": {
"matchcn": {
"command": "npx",
"args": ["-y", "matchcn"]
}
}
}Paste it in agent chat — add matchcn to your project’s MCP servers and enable the tool.
How do I set up matchcn?
Add this server to your local MCP client:
Then call pick_component with your UI brief.
Get setup instructions in chat — then run matchcn in a local client that supports MCP.
Illustrative configuration previews. Grok provides setup guidance; running matchcn requires a local MCP client.
Numbers from the committed tagging and demo reports.
Across 14 shadcn-format registries
Since launch, via npx matchcn
Brief to result, 5-brief live test including Resolve
Category, domain, motion, density, interaction, and two more
| BRIEF | OUTCOME | RESULT |
|---|---|---|
| Hero with subtle background motion | No match | 3 candidates rejected |
| Cursor with a trailing effect | Confident | react-bits / GhostCursor-TS-TW |
| Dense bento grid for a landing page | Confident | magicui / bento-grid |
| Three-plan pricing section, in Polish | No match | All 5 candidates rejected |
| Date picker with range selection | Confident | uiable / date-picker-input |
A five-brief development demo, not an accuracy evaluation, recorded before non-English support and the visual-density fix shipped. The bento grid is a named anchor in the tagging criteria. Classifier confidence can vary between runs.
Implementation, tool contract, evidence, and known limits.
matchcn is a semantic index of shadcn-format UI components, exposed through a local Model Context Protocol (MCP) server. It finds existing components from a plain-language description of the UI a developer needs and returns the original registry's installation command. It does not generate component source code or host a replacement component registry.
This reference describes the local v0.2.7 source and development reports inspected on September 26, 2026. The counts and findings below are a snapshot, not a live inventory or a guarantee of future registry availability.
A developer can ask for a component by purpose, motion, density, or interaction instead of knowing its registry-specific name. A coding agent calls pick_component, reads the outcome and explanation, and can use the returned npx shadcn@latest add <sourceUrl> command to install from the original publisher.
The current index contains 4,578 components from fourteen registries. matchcn is a discovery layer for the shadcn registry ecosystem. shadcn/ui supplies the registry format and installation tooling; it is not an indexed catalog in this snapshot. The landing page's interactive example displays recorded responses from the development demo report, including component reasons and install commands. It does not perform a live component search.
The documented CLI entry point is npx matchcn. It starts a stdio MCP server, not an interactive search shell. Node.js 20 or newer is required. For an MCP client, configure the command as npx with arguments -y and matchcn:
{
"mcpServers": {
"matchcn": {
"command": "npx",
"args": ["-y", "matchcn"]
}
}
}
The configuration belongs in the selected client's MCP settings. Claude Code can use a project's .mcp.json; Cursor can use .cursor/mcp.json. Codex uses its own TOML configuration format rather than this JSON wrapper. The page provides separate setup prompts. The Grok prompt provides configuration guidance for a local MCP-capable client; it is not a claim that this server runs directly in Grok chat.
The inspected source package is version 0.2.7. The npm package matchcn is published, the source repository is public: github.com/francesco0242/matchcn, and the server is listed in the official MCP Registry as io.github.francesco0242/matchcn.
The server exposes one tool: pick_component(brief, registry?, maxResults?). The MCP adapter returns a text content block containing the result serialized as JSON.
| Parameter | Type | Behavior |
|---|---|---|
brief |
Required string | Plain-language description of the required UI. Non-English text is auto-detected and translated before matching. |
registry |
Optional enum | Restricts matching to one of the fourteen exact registry identifiers listed below. |
maxResults |
Optional integer, 1–10 | Maximum candidates returned for a shortlist or no-match result. Default: 3. It does not expand Resolve beyond its top-eight comparison. |
Example tool arguments:
{
"brief": "a dense bento grid for a landing page",
"registry": "magicui",
"maxResults": 3
}
The tool discovers components and returns commands. Component installation is a separate action performed by the developer or coding agent. A returned component still needs to be evaluated against the application's dependencies, design, and accessibility requirements.
Source: MCP adapter.
Every result contains outcome, message, resolveUsed, and decisionsSpent. The fields chosen, candidates, and differentiators appear when applicable.
| Outcome | Meaning | How to use it |
|---|---|---|
confident |
The selection logic identifies one component. chosen contains its details. |
Review its reasons and source install command. |
shortlist |
There is no sufficiently decisive selection. candidates contains ranked options, and differentiators names differences visible to the tag schema. |
Compare those differences before choosing. |
no_match |
Resolve explicitly rejects the candidates, or no tagged components are available. There is no chosen field. |
Do not treat any diagnostic candidates as a recommended installation. |
A component result includes name, registry, nullable title, sourceUrl, installCommand, confidence, and reasons. Optional variants list available stack variants with their own registryItemName and install command. Each reason contains dimension, briefWants, componentHas, matched, and weight.
A no-match response can include nearby candidates for reference. Rejection is communicated by the overall outcome and message; the component objects do not have a separate rejected boolean. A shortlist's differentiators contain the dimension and the candidates' values. Choice dimensions differ when their known labels differ; probability dimensions differ when their known values span more than 0.2.
confidence indicates fit or selection confidence, not component quality, security, accessibility, or measured probability of success. For a chosen result it can come from Resolve when available, otherwise from the ranking score. Candidate lists use the ranking score, rounded to two decimals. These values should not be conflated with benchmark accuracy.
Source: selection logic and response types.
data/tags/ for inspection and versioning.The pipeline uses files rather than a database. Ingestion can enrich missing or short descriptions from a registry's per-item endpoint, using source excerpts as tagging input. This does not make matchcn a component-source mirror: published tag outputs contain derived data and links, not redistributed component source.
| Dimension | Representation | What it describes |
|---|---|---|
category |
Unordered label | Primary UI purpose, such as hero, navigation, card, form input, chart, layout section, background effect, cursor, or transition wrapper. Includes an escape label. |
domain |
Unordered label | What real-world task the component is FOR (auth, scheduling, commerce, messaging, analytics, content, settings, search, marketing, or general-purpose), independent of its structural shape. Added to separate components that share the same shape but serve different purposes, such as a calendar and a login form. |
motion |
Ordered label | static, subtle-transitions, animated-on-interaction, or continuous-background-motion. |
visual_density |
Probability or null | How visually dense the component reads, from sparse (one focal element) to dense (multiple regions sharing attention). Reformulated from a 3-label choice to a continuous probability after the labeled version proved consistently unreliable. |
interaction_model |
Unordered label | display-only, hover, click-toggle, form-input, drag-or-gesture, or none of these. |
needs_external_data |
Probability or null | Whether useful operation requires caller-supplied data, state, or non-trivial props. |
decorative_only |
Probability or null | Whether the component is primarily a decorative effect rather than functional or informational content. |
The probability dimensions are implemented through yes/no classification scores. A value near 0.5 represents uncertainty, not a middle category. compositionLevel is derived from registry metadata; it is not a model-tagged dimension.
Source: dimension definitions and exact criteria.
The ranking function blends two distances: a structural distance from the tagged dimensions, and a text-relevance distance between the brief and each candidate's name/title. Structural distance treats matching unordered labels as zero distance and mismatches as distance one; ordered labels use normalized index distance, so adjacent values are closer than distant ones; probability dimensions use the absolute difference between their values.
For choice dimensions, the structural weight is the smaller confidence of the brief and the component. For probability dimensions, certainty is 2 * abs(probability - 0.5), and the smaller certainty of the two sides is used. Null or zero-weight dimensions contribute no structural evidence.
The text-relevance distance is TF-IDF-weighted cosine similarity between the brief and each candidate's name/title, not a plain word-overlap count: a shared word that appears in only a handful of indexed components (e.g. "login") counts far more than one that appears in hundreds (e.g. "form"). This exists because the seven tagged dimensions alone cannot separate near-identical variants of the same structural shape (a login form, an OTP field, and a generic form-input block all tag as form-input/auth/static), which a real catalog measurement found: without a text-relevance term, "a login form with email and password fields" ranked an OTP field above all of the catalog's genuine login-form components. The text-relevance term is weighted more heavily than the structural distance in the final blend (1.5 : 1), reflecting how load-bearing this signal turned out to be in practice, not an arbitrary tiebreaker. If all weights (structural and text-relevance combined) are zero, distance is one. Lower distance ranks first, and the ranking confidence is 1 - distance.
The ranking stage is deterministic for identical parsed dimension vectors, tag records, and input order. The complete text-to-result process is not guaranteed to return identical values on every call, because brief parsing and Resolve call an external classifier.
Resolve is skipped when the leader's ranking confidence is at least 0.55 and its distance advantage over the runner-up is at least 0.15. For a single candidate, only the confidence floor applies. Resolve compares at most eight candidates (widened from five after the same catalog measurement above found genuine matches occasionally ranking as low as position six through eight) using their names, registry, composition level, and tagged properties; it does not inspect full component source at query time. The 0.55 and 0.15 thresholds are MVP heuristics, not values optimized against a labeled accuracy dataset.
Sources: ranking implementation, Resolve implementation.
| Exact registry identifier | Publisher | Components in snapshot |
|---|---|---|
react-bits |
React Bits | 204 |
magicui |
Magic UI | 79 |
aceternity |
Aceternity UI | 119 |
kokonutui |
Kokonut UI | 51 |
animate-ui |
Animate UI | 420 |
motion-primitives |
Motion Primitives | 33 |
shadcn-dashboard |
shadcndashboard.dev | 343 |
assistant-ui |
assistant-ui.com | 154 |
bundui |
bundui.io | 217 |
cnippet |
ui.cnippet.dev | 1128 |
uiable |
uiable.com | 969 |
plate |
platejs.org | 174 |
react-aria |
react-aria.adobe.com | 62 |
shadcn-ui-blocks |
shadcn-ui-blocks.com | 626 |
These counts total 4,578 components. They describe the indexed snapshot, not the current size of each publisher's library. The first six registries are the original motion/marketing family; the middle three are a product-UI expansion added after per-registry filter verification; cnippet and uiable are a second product-UI expansion, added the same way; plate and react-aria are a third, each added after fixing a real filter gap (plate's documentation pages were being indexed as components; react-aria published the same component up to three times under a style-prefix naming convention). shadcn-ui-blocks is a fourth: its combined free-and-paid index was evaluated and rejected outright (82% of its real blocks return 401 unauthenticated), but the registry's own maintainer later pointed at a separate, curated free-only index the vendor publishes, and a fresh per-item check against that one found 100% installable unauthenticated, so only that free-only index is used. Two other candidates from the cnippet/uiable expansion, shadcnuikit and shadcn-space, were evaluated and excluded: a real per-item availability check found genuine paywalls on 40% and 33.3% of a sample from each. uiable's descriptions are largely name-echoed templates rather than hand-written text; cnippet and uiable were later measured at full scale (8,388 choice-dimension answers) and scored 24.4% under 0.6 confidence, in line with the rest of the catalog, not the outlier a 20-item pre-tagging sample had suggested. shadcn-dashboard's count (343) already excludes 165 components that a real per-item availability check found returned 401/403 at their actual install URL ("License required"), not visible in the registry index itself. Aceternity's count (118) already excludes 163 page-template components found paywalled the same way, and one duplicate listing (the same component catalogued twice under two different types, pointing at the same install URL) collapsed into one entry. shadcnblocks was tagged (4,171 components) and re-evaluated with a clean, from-scratch availability check (not just the original one): 55.6% of a 3,358-item confident sample return real 401s, so it remains excluded, the same conclusion as the original check, now confirmed rather than suspected. cult-ui was excluded because its index sits behind a bot challenge; a real fix is possible (a headless browser passes it) but was not built, since doing so would mean building a tool specifically to bypass an anti-bot control the vendor put there on purpose.
The original full tagging run processed 1,069 components across six dimensions, spending 6,414 classification decisions, in a first-to-last tagging timestamp window of approximately 2 minutes 43 seconds. A second run added four product-UI registries, spending 30,300 more decisions across 5,050 components, split across two IPs to cover the free tier's daily quota. That run tagged 6,119 components across ten registries; the shipping catalog was then smaller, 1,783 components across nine registries, after a real per-item availability check found a meaningful share of shadcnblocks and shadcn-dashboard paywalled at their actual install URL and shadcnblocks was pulled entirely rather than shipped on contaminated data (see the known limits section). A third run added cnippet and uiable, spending 12,582 more decisions across 2,097 components. A subsequent real per-item availability check, run for the first time against the original six registries, found aceternity's page-template demo pages 57.8% paywalled and excluded 163 of its 282 tagged components. A fourth expansion added plate, react-aria, and shadcn-ui-blocks (626 components from its vendor-curated free-only index), and a new domain dimension was backfilled across the entire catalog in a single-dimension pass rather than a full re-tag. The current shipping catalog is 4,578 components across fourteen registries. These decision and timing figures exclude throttling and debugging time and are not a measurement of search latency or total setup duration.
The five-brief demo spent 35 decisions: six for parsing and one for Resolve per brief in that run. It returned a shortlist for a subtly animated hero, a confident React Bits cursor result, a confident Magic UI bento-grid result, and two no-match outcomes for a Polish pricing brief and a range date picker.
This is a development demonstration, not a labeled accuracy benchmark, a comparison against another product, or evidence that every request needs seven decisions. Resolve can be skipped. The bento grid is also a named example in the visual-density criteria, so its result is not an independent validation of those criteria.
visual_density was the schema's clear weakest dimension for most of this project's history: 36-37% of its answers scored below 0.6 confidence after two different labeling schemes (a counting heuristic, then a perceptual judgment anchored to named examples) both plateaued there. It was reformulated from a 3-way label choice into a continuous probability, the same representation already used for two other dimensions, piloted against a real sample before any backfill, then backfilled across the full catalog: full-catalog result is now 21.4% under-threshold, in line with the rest of the schema (13.5-21.5% across all seven dimensions). assistant-ui is a separate, persistent outlier: its choice-dimension answers land under 0.6 confidence at a materially higher rate than any other registry, likely because its content (agent and chat UI: tool timelines, trace waterfalls, reasoning panels) is further from the schema's original motion/marketing anchors than any other registry. cnippet and uiable, initially estimated at 35% under 0.6 from a 20-item pre-tagging sample, were later measured at full scale across their full 8,388 choice-dimension answers: 24.4%, in line with the catalog-wide baseline, not the outlier the small sample suggested. These are tag-confidence statistics, not error rates. Non-English behavior was examined on three Polish briefs and found measurably weaker; a real fix (local language detection plus translation to English before matching, not just a prompt-wording change) closed that gap, verified directly on the case that first exposed it.
Evidence: full tagging report, five-brief demo with raw output, pilot report.
The MCP transport and deterministic ranking run locally, but the tool is not offline-only. The client sends the brief and classification criteria to https://classifier.dev/v1/classify using the fast tier. Resolve can send the brief with descriptions assembled from the top candidates' tagged properties. The inspected HTTP client supplies no API key or authorization header.
During ingestion and tagging, registry metadata and available source excerpts can be used as classification input. Raw fetch data is cached locally; derived tags are stored separately. This reference describes the source's data flow, not the external provider's retention policy or a guarantee about its future availability, pricing, or rate limits. Errors and exhausted retries are not equivalent to a no_match result.
Source: HTTP classification client.
The MVP covers fourteen registries rather than the full shadcn ecosystem. shadcnblocks is not indexed, despite being tagged. A real per-item availability check (does npx shadcn add actually work unauthenticated, not just what the index claims) found roughly half of its components return 401/403 "License required" at their real install URL, something invisible in the registry's own index data. The original full-scale check was contaminated by the vendor's rate limiter partway through; a later clean re-check, run from scratch with proper backoff and explicitly separating rate-limit noise from real answers, confirmed the same conclusion on a 3,358-item confident sample: 55.6% genuinely paywalled, well past the threshold that already excludes other registries below. It remains excluded, not pending. shadcn-dashboard had the same problem at a smaller scale (32.5%) and was fixed by filtering the paywalled components out before shipping. Aceternity, one of the original six registries, was found to have the same problem much later: 163 of its 170 page-template demo pages (95.9%) are paywalled and excluded, found only after real-world use surfaced a confident match whose install command required Aceternity Pro, because the availability check was built after aceternity's original tagging run and had never been applied to it retroactively until then; a separate, unrelated data issue in the same registry (one component listed twice under two different types, both pointing at the same install URL) was later found and collapsed into one entry. shadcnuikit and shadcn-space were evaluated for a second product-UI expansion and excluded outright: a real per-item availability check found genuine paywalls on 40% and 33.3% of a sample from each. shadcn-ui-blocks' combined free-and-paid index was excluded the same way (82% paywalled), but a separate free-only index the vendor also publishes was verified clean (100% installable) and is indexed instead. cult-ui is excluded because its index sits behind a bot challenge; a headless browser does pass it, but building a tool specifically to bypass an anti-bot control the vendor put there on purpose was a line not crossed, so this stays unindexed by choice, not by inability. uiable's descriptions are mostly name-echoed templates rather than hand-written text, so its tags carry less real signal than the rest of the catalog, though a full-scale confidence measurement found this does not show up as measurably lower tag confidence. Visual density was historically the weakest tagged dimension; reformulating it from a 3-label choice to a continuous probability closed most of that gap. Non-English briefs were measurably weaker until a real translation step was added; detection is restricted to the languages this project actually supports translating, after real Polish and Russian briefs were confidently misdetected as unsupported languages when the detector was allowed to consider all languages it knows, silently skipping translation. Detection on short or ambiguous phrases within the supported set can still occasionally misfire, though translation is never worse than doing nothing, since a failed detection or translation falls back to the original text unchanged. A separate catalog measurement found the ranking function returning no-match far too often for how large the catalog is (40% across a mixed-difficulty real sample), traced to the tagged dimensions alone being unable to separate near-identical structural variants; adding a TF-IDF-weighted text-relevance signal (see the ranking section above) cut that rate to 13% on the same sample without any change to tag data or an extra network call. Short or inaccessible registry descriptions can reduce tagging evidence.
There is no implemented compatibility guarantee for React, Tailwind, or other dependency versions; no accessibility-quality score; and no general code-quality ranking. A domain dimension (auth, scheduling, commerce, messaging, analytics, content, settings, search, marketing, or general-purpose) separates same-shape, different-purpose components, such as a calendar and a login form, that six purely-structural dimensions alone could not tell apart. The tool does not generate UI code, host component source, or replace the original registry's installer.
The roadmap discusses additional dimensions, registry coverage, and evaluation. Those are future possibilities, not shipped capabilities or release commitments. The landing page is documentation and an installation entry point, not the searchable catalog UI that the source roadmap lists as a possible future feature.
matchcn is an independent MIT-licensed project. It is not affiliated with or endorsed by shadcn, the indexed registries, classifier.dev, or TypeSafe. Its license does not replace the individual licenses of components installed from other publishers.
Project: matchcn.dev. Updates: @matchcndev. Built by @whosfranki. Source: github.com/francesco0242/matchcn.
For citation, use the relevant section of this reference and the linked implementation or report. Attribute the figures to the September 26, 2026 development snapshot. Distinguish implemented behavior from intended behavior, fit confidence from accuracy, and local ranking from the network-dependent pipeline.