shadcn/ui CLI 的 MCP Server 实战解析:让 AI 助手直接搜索、查看与安装 Registry 组件
shadcn/ui 的 CLI 内置了一个基于 Model Context Protocol(MCP)的服务器,它把 Registry 的搜索、浏览、查看与安装能力封装成 7 个标准化工具,供 Claude Code、Cursor、VS Code 等 AI 客户端直接调用。本文以仓库中 skills/shadcn/mcp.md 的官方说明为主体,结合 MCP 服务器源码实现 与 CLI 的 mcp 命令,完整讲清它的接入方式、每个工具的输入输出契约、components.json 中的 Registry 配置规则,以及工具调用在源码层面的真实执行路径,帮助你把组件选型和安装流程无缝交给 AI 完成。
一、MCP Server 是什么,与 CLI 的关系
在 shadcn/ui 的工作流中,组件以源码形式通过 CLI 添加到用户项目(npx shadcn@latest add button),而组件来源是各种 Registry。当用户用 AI 助手开发时,助手需要回答三类问题:有哪些组件可用?这个组件长什么样、怎么用?怎么安装?MCP Server 正是为这三类问题提供的程序化接口——它本身不做项目初始化或主题配置,只覆盖 Registry 操作。
从源码结构看,服务器实现在 packages/shadcn/src/mcp/index.ts,使用 @modelcontextprotocol/sdk 的 Server 构建,声明了 logging、resources、tools 三种能力:
// packages/shadcn/src/mcp/index.ts
export const server = new Server(
{
name: "shadcn",
version: "1.0.0",
},
{
capabilities: {
logging: {},
resources: {},
tools: {},
},
}
)
所有工具描述通过 zod 定义入参 schema 并转换为 JSON Schema 暴露给客户端(zodToJsonSchema),工具调用由统一的 handleCallTool 分发处理。值得注意的是,源码中专门处理了 GitHub 认证通知:由于 stdio 通道被协议占用,认证信息通过 MCP 的 logging 能力发送给客户端,而不是打印到控制台:
// stdout 承载协议,console 不可用,认证通知走 logging 通道
async function onGitHubAuthNotice(message: string) {
try {
await server.sendLoggingMessage({ level: "info", data: message })
} catch {
console.error(message)
}
}
另外,仓库中保留了旧的 shadcn registry:mcp 命令,见 packages/shadcn/src/commands/registry/mcp.ts——它已被标记为 DEPRECATED,执行时只会提示改用 shadcn mcp,因此新接入一律使用 mcp 命令。
二、接入配置:shadcn mcp 与 shadcn mcp init
文档给出的启动方式只有两条命令:
shadcn mcp # start the MCP server (stdio)
shadcn mcp init # write config for your editor
shadcn mcp 以 stdio 传输启动服务器,支持 -c, --cwd <cwd> 指定工作目录(默认为当前目录)。在 命令实现中可以看到它启动前的一个关键动作:
// packages/shadcn/src/commands/mcp.ts
.action(async (options) => {
await loadEnvFiles(options.cwd) // 先加载 .env 文件
const transport = new StdioServerTransport()
await server.connect(transport)
})
这里调用的 loadEnvFiles 会按 .env.local、.env.development.local、.env.development、.env 的顺序读取项目环境文件。这就是后文 Registry 配置中 ${VAR} 环境变量占位符能被解析的机制来源——即使 token 只存在于 .env 文件而没有导出为系统环境变量,MCP Server 启动时也能取到。
shadcn mcp init 负责把服务器注册到各编辑器。官方支持的客户端与配置文件对应关系如下(与源码中 CLIENTS 数组一一对应):
| Editor | 配置文件 | 说明 |
|---|---|---|
| Claude Code | .mcp.json |
写入 mcpServers.shadcn |
| Cursor | .cursor/mcp.json |
写入 mcpServers.shadcn |
| VS Code | .vscode/mcp.json |
写入 servers.shadcn(注意键名不同) |
| OpenCode | opencode.json |
写入 mcp.shadcn,含 $schema 与 enabled: true |
| Codex | ~/.codex/config.toml(手动) |
只能打印指引,不能直接写入 |
生成后的配置内容(以 Claude Code 为例):
{
"mcpServers": {
"shadcn": {
"command": "npx",
"args": ["shadcn@latest", "mcp"]
}
}
}
Codex 的配置则是 TOML 格式,shadcn mcp init --client codex 会安装依赖并提示手动追加到 ~/.codex/config.toml:
[mcp_servers.shadcn]
command = "npx"
args = ["shadcn@latest", "mcp"]
写入逻辑见 runMcpInit:它先读取已有配置文件,用 deepmerge 与目标客户端的配置合并(数组采用覆盖策略),再写回并自动创建缺失的父目录,因此重复执行 mcp init 不会破坏编辑器里已有的其他 MCP 服务器配置。--client 取值限定为 claude, cursor, vscode, codex, opencode;不指定时会交互式询问。
三、七个工具的完整输入契约
MCP Server 暴露 7 个工具,工具名在客户端中会带上 shadcn: 前缀。官方文档同时强调了一条重要边界:
Tip: MCP tools handle registry operations (search, view, install). For project configuration (aliases, framework, Tailwind version), use
npx shadcn@latest info— there is no MCP equivalent.
即:项目级配置查询(别名、框架、Tailwind 版本)没有 MCP 对应物,AI 助手必须回到 CLI 的 info 命令。以下按工具逐一说明,输入契约以 源码中的 zod schema 为准。
3.1 shadcn:get_project_registries
返回 components.json 中配置的 Registry 名称列表。输入:无。 若项目根目录不存在 components.json,工具不会抛错中断,而是返回指导性文本:提示先用 init 命令创建 components.json,或手动在其中写入 registries 段。成功时除了列出 Registry 名称,还会附带 npx shadcn@latest view @shadcn 等后续操作建议命令,帮助 AI 决定下一步动作。
3.2 shadcn:list_items_in_registries
列出 Registry 中的全部条目。Registry 可以是 components.json 中配置的命名空间(如 @acme)、形如 owner/repo 的公开 GitHub 源,或直接给出 Registry 目录 URL。
输入参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
registries |
string[] | 否 | 要列出的 Registry 名称数组;省略时列出 components.json 中配置的全部 Registry |
types |
string[] | 否 | 按条目类型过滤,如 ["ui", "block"] |
limit |
number | 否 | 返回上限,默认 100;源码 schema 中明确 use 0 for no limit,即传 0 表示不限制 |
offset |
number | 否 | 分页跳过的条目数 |
输出由 formatSearchResultsWithPagination 格式化:带 Found N items matching "..." 头部、Showing items x-y of N 区间、每个条目的类型/描述/所属 Registry,并在 hasMore 为真时追加 More items available. Use offset: N to see the next page. 的分页提示——这套文本是专门为 LLM 阅读设计的,让助手能自主翻页。
3.3 shadcn:search_items_in_registries
跨 Registry 的模糊搜索,是最高频的工具(例如让 AI “帮我找一个 hero”)。搜索范围同样由 registries 参数决定,省略即搜索全部已配置 Registry。
输入参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
registries |
string[] | 否 | 要搜索的 Registry;省略为全部已配置 |
query |
string | 是 | 模糊匹配条目名称与描述的查询串 |
types |
string[] | 否 | 类型过滤,如 ["ui", "block"] |
limit |
number | 否 | 默认 100,0 为不限 |
offset |
number | 否 | 分页偏移 |
两个源码层面的行为细节值得注意:
- 类型校验与 CLI 完全一致。 合法的
types取值来自 SEARCHABLE_TYPES,即registryItemTypeSchema的全部选项去掉registry:example、registry:internal等内部类型后的短名形式(如ui、block)。传入未知类型时工具返回isError: true并列出合法类型,对应实现见 findUnknownTypesMessage。 - 全量搜索时容错继续。 省略
registries时源码设置continueOnError: true:某个 Registry 加载失败不会使整个搜索失败,而是在结果末尾追加Skipped N registries that failed to load:及逐个失败原因。该行为有专门的单元测试覆盖(见 utils.test.ts 中formatSkippedRegistries用例)。
3.4 shadcn:view_items_in_registries
查看条目详情,包含完整文件内容。
输入: items (string[]) —— 必须带 Registry 前缀,如 ["@shadcn/button", "@shadcn/card", "owner/repo/item"]。
内部调用 getRegistryItems 拉取条目,输出经 formatRegistryItems 组织为 Markdown 结构:标题、描述、**Type:**、文件数量、**Dependencies:** 与 **Dev Dependencies:**。若一个条目都找不到,会返回带纠正提示的文本(提醒补全 @shadcn/button 这类前缀)。
3.5 shadcn:get_item_examples_from_registries
查找用法示例与 demo,返回完整源码。省略 registries 时搜索全部已配置 Registry。
输入:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
registries |
string[] | 否 | 省略为全部已配置 |
query |
string | 是 | 示例查询,如 "accordion-demo"、"button example" |
该工具的实现是“搜索 + 拉取”两步:先 searchRegistries 找到匹配的示例条目,再对其 addCommandArgument 调用 getRegistryItems 取回全量文件,最后由 formatItemExamples 把每个示例渲染成 ## Example: <name> 段落,并把有 content 的文件以 ### Code (<path>): 加 ```tsx 代码块的形式完整展开。源码 schema 中还给出了推荐查询模式:'{item-name}-demo'、'{item-name} example'、'example {item-name}'。搜不到时返回的提示文本会引导 AI 转用 search_items_in_registries 或 view_items_in_registries,形成工具间的自引导闭环。
3.6 shadcn:get_add_command_for_items
返回 CLI 安装命令。
输入: items (string[]) —— 如 ["@shadcn/button"]。
实现很直接:把 items 拼进 npx shadcn@latest add ... 并返回(具体 runner 由 npxShadcn 按项目实际的 package manager 生成)。注意这是“返回命令”而非代为执行——真正落地安装仍由 AI 助手在用户终端中跑 CLI 完成,这与 shadcn 一贯的“安装交给 CLI、保证 import 重写与依赖安装”的边界一致。
3.7 shadcn:get_audit_checklist
输入:无。 返回一份组件验证检查清单,源码中的原文包括:
- 确认导入正确(named vs default imports);
- 若使用
next/image,确认next.config.js的images.remotePatterns配置正确; - 确认所有依赖已安装;
- 检查 lint 错误与警告;
- 检查 TypeScript 错误;
- 如果可用,使用 Playwright MCP 做验证。
工具描述明确建议“在创建或生成代码文件之后、所有步骤完成时调用”,把它当作 AI 工作流的收尾自检环节。
四、Registry 配置:components.json 的 registries 段
上面所有工具里 registries 参数的解析,最终都落到 components.json。官方文档给出的配置示例如下,可直接照抄:
{
"registries": {
"@acme": "https://acme.com/r/{name}.json",
"@private": {
"url": "https://private.com/r/{name}.json",
"headers": { "Authorization": "Bearer ${MY_TOKEN}" }
}
}
}
两条形式并存:值是 URL 字符串(公开 Registry),或 { url, headers } 对象(需要鉴权的私有 Registry)。规则有四点:
- 命名必须以
@开头(如@acme、@private); - URL 必须包含
{name}占位符,CLI 用具体条目名替换后请求; ${VAR}引用从环境变量解析——对应上文shadcn mcp启动时loadEnvFiles读取.env文件的行为,token 可以只写在项目.env中;@shadcnRegistry 是内置的,无需配置即可使用。
此外还有一类零配置来源:公开的 GitHub Registry。只要仓库根目录存在 registry.json,owner/repo 可直接作为 Registry 源使用,不必写入 components.json。这一点在工具描述中也反复出现(如 view_items_in_registries 的示例输入 "owner/repo/item")。
社区 Registry 索引则由本仓库自身的 Registry 端点提供:apps/v4 站点下的 r/registries.json 路由目录即对外发布该索引,可用于发现公开可用的社区 Registry。
五、一次典型调用的源码路径
以“AI 助手搜索 button 并生成安装命令”为例,shadcn:search_items_in_registries 在 handleCallTool 中的执行链是:
- 用 zod 校验入参(
registries、query、types、limit、offset); findUnknownTypesMessage(args.types)校验类型过滤值;getMcpConfig(process.cwd())读取当前目录components.json的registries段(useCache: false,保证读到最新配置);resolveSearchRegistries(args.registries ?? [], config)解析出目标 Registry 列表;空列表时直接返回“请先配置 Registry”的引导文本;searchRegistries(...)执行搜索,limit缺省补 100,continueOnError取决于是否为全量搜索;- 空结果返回换词建议;有结果则格式化为带分页提示的文本,并追加被跳过 Registry 的失败说明。
整个 CallToolRequestSchema 处理被 withRegistryContext 包裹以注入 GitHub 认证上下文;异常统一转为 MCP 错误文本返回而非崩溃:zod 校验失败返回逐条字段错误,RegistryError 会附带 💡 suggestion 与上下文 JSON,其他错误返回 Error: <message>。所有分支均以 isError: true 标记,方便客户端区分。
测试侧,utils.test.ts 覆盖了分页头部、区间钳制(如 Showing items 21-25 of 25)、hasMore 分页提示、未知类型报错文案、跳过 Registry 的提示等。其中还有一处值得注意的诚实记录:测试用 it.fails 标注了一个已知缺陷——formatSearchResultsWithPagination 中 npxShadcn 是异步函数但插值时未 await,导致条目行里的 “Add command” 一度渲染为 [object Promise]。这提示使用者:MCP 返回文本中的命令字符串建议复制前先人工核对 runner 前缀,或直接用 get_add_command_for_items 获取权威安装命令。
六、组合成完整工作流与适用边界
把 7 个工具串起来,AI 助手处理“加一个登录卡片”的完整流程是:
get_project_registries—— 确认项目配置了哪些 Registry(也用于探测components.json是否存在);search_items_in_registries(query: "login",可加types: ["block"])—— 在全部已配置 Registry 中模糊搜索;view_items_in_registries(items: ["@shadcn/..."])—— 查看条目构成与依赖;get_item_examples_from_registries(query: "login example")—— 获取完整示例源码作为生成参考;get_add_command_for_items—— 生成npx shadcn@latest add ...命令,由助手在终端执行完成安装;get_audit_checklist—— 安装后按清单核对导入、依赖、lint 与 TypeScript。
适用边界需要说清楚:
- 前提是项目根目录存在
components.json(通常由npx shadcn@latest init生成)。没有它时各工具会返回引导文本而非报错,但搜索与列出功能无法工作; - 传输协议为 stdio,适合本地 AI 客户端,不适合作为远程 HTTP 服务暴露;
- MCP 只覆盖 Registry 操作。别名、框架、
base(radix/base)、Tailwind 版本等项目配置查询仍须走 CLI 的info命令,文档与 skills/shadcn/SKILL.md 中都明确把二者分工:SKILL 文件负责“项目上下文 + 编码规则”,MCP 负责“组件检索与安装”。
这套设计的实际效果是:AI 助手不再需要猜测组件名或手写安装命令,而是通过结构化工具拿到 Registry 的权威数据(条目、文件内容、示例、依赖清单),再交由 CLI 完成源码落盘——Registry 生态的可发现性与 AI 工作流由此打通。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00