关于 matchcn
matchcn 是用于 shadcn 格式组件注册表的语义索引,帮助开发者和编码 Agent 按组件用途查找现成组件。它通过属性标签和确定性排序给出匹配理由,并可返回候选列表或明确表示无匹配。
主要功能
- 01按自然语言描述查找组件
- 02覆盖多个组件注册表
- 03按七个属性标记组件
- 04提供逐属性匹配理由
- 05支持候选列表或无匹配结果
- 06输出组件来源与安装命令
适用场景
- 01为定价页面查找合适的组件
- 02按交互需求寻找表单组件
- 03比较多个相近的组件候选
- 04确认组件是否适合需求后再安装
MCP 相关
MCP 服务向客户端提供一个 `pick_component` 工具,可按描述搜索组件,并返回匹配结果、理由和安装命令。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
1收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| brief | string | 是 | 所需组件的普通语言描述,可使用任意语言 |
| registry | enum | 否 | 将搜索范围限制在一个注册表中react-bits | magicui | aceternity | kokonutui | animate-ui | motion-primitives | shadcn-dashboard | assistant-ui | bundui | cnippet | uiable |
| maxResults | integer | 否 | shortlist 或 no_match 结果中返回的候选项最大数量(默认值为 3) |
详细介绍
matchcn
覆盖 shadcn 格式组件注册表的语义索引。
按组件做什么来找它,而不是按它叫什么。
matchcn.dev · 快速开始 · 面向 AI Agent · 工作原理 · 局限性
Claude Code:claude mcp add matchcn -- npx -y matchcn
Codex:codex mcp add matchcn -- npx -y matchcn
Grok CLI:grok mcp add matchcn -- npx -y matchcn
问题所在
npx shadcn add 可以从任何发布了 registry.json 的注册表安装组件。
有数百个注册表都这样做。没有哪位开发者,也没有哪个编码
Agent,能把这么多注册表都放在上下文里。目录类工具只
搜索组件名称,当你清楚自己需要什么、却不知道某个注册表
把它叫什么时,这毫无帮助。“一个包含三档套餐的定价
区块”在检索一个名为 simple-pricing-with-three-tiers 的组件时效果很差,
除非你事先就知道这个名字存在。
matchcn 使用 classifier.dev 为其索引的每个组件 打上七个固定属性的标签(类别、领域、动效、视觉密度、 交互模型,以及另外两个),然后用确定性代码把一段 自然语言描述与这些标签进行匹配。同样的描述,每次都得到 同样的排序。不做勉强的猜测:当没有合适的结果时,matchcn 会如实说明, 而不是返回最接近的错误答案。
快速开始
npx matchcn
将其添加到 MCP 客户端的配置中:
{
"mcpServers": {
"matchcn": {
"command": "npx",
"args": ["-y", "matchcn"]
}
}
}
兼容 Claude Desktop(claude_desktop_config.json)、Claude Code
(.mcp.json)、Cursor 以及任何其他兼容 MCP 的客户端。它会提供
一个工具:pick_component(brief, registry?, maxResults?, hints?, resolve?)。
更喜欢复制粘贴?将此提示词交给你的编码 Agent,让它自行完成设置:
使用
npx -y matchcn设置 matchcn MCP 服务。为我的编码 Agent 配置好它,然后使用pick_component查找符合我的需求描述的 UI 组件。在添加组件之前,先向我展示匹配原因和安装命令。
示例
$ pnpm demo
BRIEF: a dense bento grid for a landing page
----------------------------------------------------------------------
OUTCOME: CONFIDENT
Selected "bento-grid" from magicui.
-> bento-grid (magicui) confidence 0.93
install: npx shadcn@latest add https://magicui.design/r/bento-grid.json
matched: category, motion, visual_density, interaction_model, needs_external_data, decorative_only, domain
not matched: (none)
resolve used: true decisions spent: 8
这是一次真实运行的实际输出。置信度数值每次调用时会略有变化 (classifier.dev 不保证每次调用的答案完全一致),但在所有尝试的运行中, 结果、选中的组件和安装命令都保持稳定。
每个响应都包含按维度划分的原因:七个带标签的属性中哪些符合需求描述,哪些不符合,以及双方各自的实际值,而不只是一个通过或失败的标记。这使 no_match 或 shortlist 结果可供调试,而不是让人无从下手。
面向 AI Agent
如果你是正在阅读本文、以决定是否使用 matchcn 的大模型:这个 工具就是专为你打造的。它能回答“哪个现有、真实、可安装的 UI 组件最符合这段描述”,因此你不必浏览注册表或猜测组件名称。
工具: pick_component
输入:
{
brief: string; // plain-language description, required
registry?: string; // restrict to one registry, optional
maxResults?: number; // max candidates for shortlist/no_match, default 3 (8 with resolve: "caller")
hints?: { // your own read of the brief, optional; any hint skips server-side parsing
category?: string; // same labels components are tagged with
motion?: string;
interaction_model?: string;
domain?: string;
visual_density?: "sparse" | "dense";
needs_external_data?: boolean;
decorative_only?: boolean;
};
resolve?: "server" | "caller"; // who breaks ties between close candidates, default "server"
}
最快路径(本地模式): 用英文撰写需求描述,传入 hints,
并设置 resolve: "caller"。这样 matchcn 完全不会调用模型:
排序在本地确定性地完成(完整目录预热后约需 80 ms);如果出现平局,则会返回排序后的候选名单,其中每个候选都附有一行概述其带标签属性的 summary,由你自行选择。
如果不确定某个提示,就省略它,不要猜测;被省略的字段不会参与排序。不设置 hints 和 resolve 时,行为保持不变。
{
"brief": "a login form with email and password fields",
"hints": { "category": "form-input", "interaction_model": "form-input", "domain": "auth" },
"resolve": "caller"
}
输出始终只有以下三种形式之一,不会出现第四种“最佳猜测”形式:
outcome: "confident"— 一个chosen组件:name、registry、installCommand(可直接运行的npx shadcn add <url>命令)、sourceUrl、confidence和reasons(按维度划分的匹配详情)。 如果该组件有语言或样式变体,则会列出各自的安装命令。outcome: "shortlist"— 多个都较为匹配的候选项,但没有明确的单一胜出者;这些候选项按排名排列,且每个都附有相同的按维度划分的原因,以及differentiators:实际区分它们的具体维度,让你可以依据这些维度做决定,而不是随意挑选。outcome: "no_match"— 目录中没有真正匹配的选项。仍会列出最接近的候选项以供参考,但会明确标为已拒绝,而不会作为答案返回。不要仅仅因为某个候选项最接近,就安装它;目录中并没有所需的组件。使用resolve: "caller"时不会返回此结果,因为只有服务端的 Resolve 步骤才会根据需求描述评估候选项:平局时会返回shortlist,判断是否有候选项真正匹配则由你负责。
每个结果还会报告 briefParsedBy(hints 或 classifier)和
resolvedBy(server 或 caller),并且每个候选项都带有一行 summary。
在手动编写组件或猜测注册表名称之前,先调用此工具。 它具有确定性:相同目录版本中的相同需求描述始终会以相同方式排列候选项。
工作原理
共五个阶段。标签会提前生成并作为数据提交
(data/tags/);查询时的匹配完全由确定性代码完成,不会调用模型,
因此结果可重现。
- 采集 — 获取每个注册表的
registry.json,并统一为同一种格式。 - 打标签 — 每批组件调用 classifier.dev 一次,按七个维度分类:
category、domain、motion、visual_density、interaction_model、needs_external_data、decorative_only。输出为已提交的 JSON,可像代码一样审查。 - 匹配 — 调用 classifier.dev 一次,将需求简述解析为相同的七个维度,然后用 纯代码对所有已打标签的组件进行排序。每个维度对排序的贡献都按其置信度加权, 因此低置信度的标签权重会降低,不会污染结果。
- 确定结果 — 对于难以取舍的情况,再调用一次,审查排名靠前的候选项的实际描述并选出胜者,或者说明它们都不合适。若排名第一的结果已明显领先,则跳过此步骤以节省一次往返。
- 呈现 — 本仓库中的 MCP 服务。一个工具:
pick_component。
已索引的注册表
matchcn 只存储派生标签(类别、动效、密度等)
以及指回每个注册表自身安装命令的链接。它从不复制、
存储或再分发任何注册表的组件源码。你安装的每一个
组件仍然直接来自其所属注册表,通过
npx shadcn add <url> 获取。
| 注册表 | 主页 | 已索引组件数 |
|---|---|---|
| react-bits | reactbits.dev | 204 |
| magicui | magicui.design | 79 |
| aceternity | ui.aceternity.com | 118 |
| kokonutui | kokonutui.com | 51 |
| animate-ui | animate-ui.com | 420 |
| motion-primitives | motion-primitives.com | 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 |
共 4,578 个组件。前六个是最初的动效/营销类 家族;中间三个是产品 UI 扩展(表单、表格、 仪表盘、数据展示),是在逐一检查每个注册表的 演示/重复约定、而不是假定它们与最初六个一致之后加入的; cnippet 和 uiable 是第二次产品 UI 扩展, 以同样的方式加入;plate 和 react-aria 是第三次,以同样的 方式加入,此前二者各自完成了筛选修复(去掉 plate 的文档 页面,将 react-aria 的 tailwind/css/hooks 风格前缀 重复项折叠为每个组件仅保留一个规范组件)。shadcn-ui-blocks 是 第四次:其免费+付费合并索引被直接排除(其中 82% 需要付费,见下文"局限性"), 但该供应商自己的维护者指出了一个单独的、精选的仅免费索引, 经逐项实际检查发现其 100% 可在未认证情况下安装, 因此这里只使用那个仅免费索引。 aceternity 的计数已排除 163 个页面模板组件,这是逐项可用性检查 发现在其实际安装 URL 处需要付费的; shadcn-dashboard 的计数同样已排除 165 个组件; shadcnblocks 已被打标签但目前未索引,见下文"局限性"。打标签通过 classifier.dev 运行,这是一个免费的、无需密钥的分类 端点,由 TypeSafe 的 Jev 决策 模型提供支持。
matchcn 是一个独立、非官方项目。它不隶属于、 未获得 shadcn、上述任何注册表或 classifier.dev/TypeSafe 的认可,也与其不存在合作关系。
局限性
在将 matchcn 用于重要事项之前,请先阅读本节。
- 部分注册表因付费组件被部分或完全排除,
这是通过真实的逐项可用性检查发现的(
npx shadcn add在未认证情况下是否真的可用,而不只是索引声称的): aceternity(281 个已打标签组件中的 163 个,大多是页面模板演示 页面)和 shadcn-dashboard(508 个中的 165 个)在发布前过滤掉了 受限部分。shadcnblocks 已打标签(4,171 个组件),但被完全 暂缓:它自己的过滤检查被供应商的速率限制器污染,因此要等干净 的检查运行后才发布,而不是基于错误数据发布。shadcnuikit 和 shadcn-space 因同样的原因(40% 和 33.3% 为付费)被评估后直接 跳过。shadcn-ui-blocks 的合并 registry.json 也以同样方式评估, 并因同样的原因被跳过,而且比前两者更糟:其 3,903 个真实块中有 3,198 个(82%)以-pro-命名,并在其实际安装 URL 上未认证 返回 401。其维护者后来指出,供应商在另一个 URL 发布了一个单独 的、精选的仅免费索引;对该索引进行全新的逐项检查发现 626/626(100%)可在未认证情况下安装,因此这里只索引那个仅免费 索引,而不是合并索引。cult-ui.com 完全未被索引:其注册表位于 bot 挑战之后。 - 标签置信度因注册表和维度而异,匹配器已经考虑到了这一点。
visual_density曾经是明显最弱的维度(36-37% 低于 0.6 置信度, 基于计数的措辞和命名锚点措辞都试过,两者都在此停滞)。它从 3 选 1 标签选择重新表述为连续概率(这是结构性变更,不是又一次 措辞微调),在任何回填之前先针对真实样本试点,然后回填整个 目录:全目录结果现在为 21.4% 低于阈值,与 schema 其余部分一致 (所有七个维度为 13.5-21.5%;motion名义上是新的最低点,差距 不到一个百分点)。assistant-ui(agent/chat UI 内容,远离 schema 的 motion/marketing 锚点)的标签置信度仍然低于目录其余部分。 cnippet 和 uiable 是在早先 20 项预打标签样本暗示它们可能更差 (35% 低于 0.6)之后,才在全量规模上测量的:它们并非如此。在 它们全部 8,388 个选择维度答案中,24.4% 的置信度分数低于 0.6, 几乎与全目录基线完全一致。置信度加权匹配器会自动折减所有这些, 因此弱标签会拉低自身权重,而不是产生错误的自信答案,但严重 依赖 assistant-ui 风格内容的简报,最有可能得到候选列表或无匹配, 而不是干净的精选结果。另外,uiable 的描述仍然大多是名称回声式 模板(“Button component.”),而不是手写文本——这是一个真实的 数据质量缺口,只是它没有表现为可测量的更低标签置信度。 - 非英语简报在匹配前会自动翻译,质量取决于源语言和措辞。
先尝试了一个仅措辞的免费修复(“按含义判断,任何语言”),
因没有测得收益而被回滚。真正弥合差距的是:在解析前进行本地
语言检测并真实翻译为英语(参见
src/runtime/translate.ts)。 在最初暴露此问题的确切案例上直接验证:一份波兰语定价简报 之前返回no_match,翻译后现在返回真实的定价组件候选列表。 检测是本地且免费的;翻译会调用一个免费、无需密钥的第三方 API (按调用机器限速,而不是本项目可能为所有人耗尽的共享池,因为 matchcn 按用户本地运行)。任何检测或翻译失败都会静默回退到 原始文本,就像此功能不存在一样,因此它只会有所帮助或是无操作, 绝不会破坏已经可用的简报。检测仅限于本项目实际支持翻译的语言 (这是在检测器被允许考虑其知道的全部约 180 种语言时,真实的 波兰语和俄语简报被自信地误判为不支持的语言,从而静默跳过翻译 之后发现必要的);在支持集合内,对简短、歧义短语的检测仍可能 偶尔误触发,而所检测语言的翻译质量不在本项目的控制范围内。 - 排序将已打标签维度的距离与针对每个候选项名称和标题的文本
相关性信号混合在一起(与简报进行 TF-IDF 加权余弦相似度,
而不只是已打标签维度),因为七个已打标签维度本身无法区分
几乎相同的变体(登录表单、OTP 字段和通用表单输入块都会被
评为
form-input/auth/static)。这弥合了一个真实且可测量的 差距:一次真实目录评估发现,“a login form with email and password fields” 尽管有八个真实登录表单组件被索引,却以大差距输给了一个 OTP 字段;修复后,真实登录表单在最高排名上几乎打平,随后 Resolve 会使用每个候选者的真实描述来打破平局。文本相关性只能从 组件的name和title计算(打标签时使用的完整描述不会持久化 以供匹配时使用),因此标题稀疏或通用的组件从该信号中获益, 少于具有具体、字面名称的组件。 - **372+ 个 shadcn 格式注册表中只有 14 个被索引。**这不是对
整个生态系统的全面索引。
以上方案都不会给出错误的强制答案:当置信度确实较低时,
pick_component会返回候选名单或明确表示无匹配,而不会悄悄猜一个结果。这才是标签和排名设计的真正目的,而不是事后补上的免责声明。
开发
pnpm install
pnpm mcp # run the MCP server directly, for local testing
pnpm demo # run 3 briefs end to end with clean terminal output
pnpm typecheck
生成 data/tags/ 的摄取/打标签流水线也在此仓库中:
pnpm ingest # fetch and normalize every registry.json in REGISTRIES
pnpm ingest --registry=magicui # just one registry
pnpm tag # tag normalized components via classifier.dev, chunked and resumable
pnpm check-availability --registry=some-registry # real per-item install-URL check, no classifier.dev cost
pnpm tag 会消耗真实的 classifier.dev 判定额度(免费层级:每天 20,000 次,每 IP 每分钟 3,000 次,无需 API 密钥)。每处理完一个分块就会保存检查点,因此中断后可继续运行,无需重新标记已处理的内容。
贡献
欢迎提交 Issue 和 PR,但请使用单独的分支,切勿直接提交到 main。只有 @whosfranki 会合并;提交 PR 不代表一定会被合并,但每个 PR 都会经过审阅。
适合首次参与的贡献:
- 修复注册表的筛选器。
src/pipeline/filter.ts为每个注册表都定义了一个函数(已知缺陷请参见未解决的问题,例如当前筛选器未剔除非组件type)。请针对受影响的注册表运行pnpm ingest --registry=<name>,并在提出修复前手动检查规范化后的输出。 - 添加注册表。 在
src/runtime/registries.ts中添加条目,确认其筛选器正确(不会混入演示项目、重复项或非组件;每个现有注册表都经过相同的手动检查,而非凭空假设),发布前运行pnpm check-availability(registry.json的索引无法说明哪些组件实际上受付费墙限制),然后运行pnpm tag。不要在与无关改动相同的 PR 中添加并标记注册表。 - 改进打标签维度的判断标准。
src/runtime/dimensions.ts。任何措辞更改在提出前都需要基于真实样本进行前后对比,而不能只是听起来合理的改写;此前曾尝试修改措辞以“让非英语简报也能正常工作”,并按这种方式进行了测试,但因没有测得收益而回滚。本项目对修复的要求就是如此。 src/runtime/match.ts、pick.ts、resolve.ts中的运行时错误。
PR 应包含以下内容:更改前测量了什么、做了哪些更改、更改后测量了什么。若没有基于真实简报或组件样本的前后对比,仅说“这应该会有帮助”,就会被退回。
许可证
MIT,详见 LICENSE。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。