AI 优先的组件发现机制:MCP Server 与编程式 Registry API
前置知识
- ›第 1 篇:架构概览
- ›第 2 篇:registry 系统与依赖解析
- ›对 Model Context Protocol(MCP)概念有基本了解
AI 优先的组件发现机制:MCP Server 与编程式 Registry API
shadcn/ui CLI 从一开始就不只是为人类用户设计的工具。正如第 1 篇所介绍的,这个包通过 7 个子路径导出,服务于三类不同的使用者。本系列的最后一篇文章,将重点聚焦于其中最具前瞻性的接入面:允许 AI 编程助手发现、检查和安装组件的 MCP server,以及可供库作者直接导入使用的编程式 registry API。
MCP Server 架构
位于 packages/shadcn/src/mcp/index.ts 的 MCP server 基于 @modelcontextprotocol/sdk 构建。它创建了一个具备 tools 能力的 Server 实例,并注册了 7 个工具:
graph TD
MCP["MCP Server (shadcn)"]
MCP --> T1["get_project_registries"]
MCP --> T2["list_items_in_registries"]
MCP --> T3["search_items_in_registries"]
MCP --> T4["view_items_in_registries"]
MCP --> T5["get_item_examples_from_registries"]
MCP --> T6["get_add_command_for_items"]
MCP --> T7["get_audit_checklist"]
每个工具都有一个 Zod 输入 schema,并通过 zod-to-json-schema 转换为 MCP 协议所需的 JSON Schema 格式。Server 以 stdio 进程的方式运行——执行 shadcn mcp 时,它会通过 StdioServerTransport 建立连接并等待工具调用。
CallToolRequestSchema 处理器中的错误处理逻辑(第 413–462 行)展示了第 2 篇中介绍的 registry 错误系统与 MCP 响应之间的桥接方式。RegistryError 实例会携带错误码、消息、建议和上下文一并格式化输出,为 AI 助手提供足够的信息来诊断问题并给出修复建议。
7 个 MCP 工具:发现 → 检查 → 安装
这 7 个工具构成了一套自然递进的工作流:
1. get_project_registries — 读取 components.json 并返回已配置的 registry 名称。这通常是 AI 了解可用资源时发起的第一个调用。
2. list_items_in_registries — 分页列出指定 registry 中的所有条目。接受 registries: string[]、limit 和 offset 参数。
3. search_items_in_registries — 跨 registry 进行模糊搜索。其实现位于第 197–240 行,委托给内部使用 fuzzysort 库的 searchRegistries 函数处理。
4. view_items_in_registries — 获取条目的完整详情,包括文件内容。接受带 registry 前缀的条目名称(例如 ["@shadcn/button"])。
5. get_item_examples_from_registries — 搜索 demo/示例条目并返回完整代码。该工具专为 accordion-demo、button example、example-hero 等模式设计。
6. get_add_command_for_items — 返回安装条目所需的 CLI 命令(例如 npx shadcn@latest add @shadcn/button)。
7. get_audit_checklist — 返回安装后的检查清单,涵盖常见问题:import 正确性、next.config.js 图片配置、依赖安装、代码检查、TypeScript 错误等。
flowchart LR
A["1. get_project_registries"] --> B["2. list/search items"]
B --> C["3. view item details"]
C --> D["4. get examples"]
D --> E["5. get add command"]
E --> F["6. User runs command"]
F --> G["7. audit checklist"]
提示: MCP 工具有意不直接执行
shadcn add,而是返回命令字符串供用户手动运行。这是一种安全设计理念:AI 助手负责建议,人类负责审批。
各 IDE 的客户端配置
mcp 命令 提供了一个 init 子命令,可为五种 AI 编程环境生成对应配置。每种环境的配置格式各不相同:
| 客户端 | 配置路径 | 格式 |
|---|---|---|
| Claude Code | .mcp.json |
{ mcpServers: { shadcn: { command, args } } } |
| Cursor | .cursor/mcp.json |
{ mcpServers: { shadcn: { command, args } } } |
| VS Code | .vscode/mcp.json |
{ servers: { shadcn: { command, args } } } |
| Codex | .codex/config.toml |
TOML 格式([mcp_servers.shadcn]) |
| OpenCode | opencode.json |
{ mcp: { shadcn: { type, command, enabled } } } |
第 22–86 行的 CLIENTS 数组定义了每个客户端的配置路径和结构。runMcpInit 函数读取现有配置,深度合并 shadcn server 配置后写回文件,原有的 MCP server 配置不会被覆盖。
Codex 需要特殊处理,因为它的配置文件位于 ~/.codex/config.toml(全局路径),而非项目目录下。对于这种情况,命令会打印手动配置说明,而不是自动写入文件。
编程式 Registry API
packages/shadcn/src/registry/index.ts 的 shadcn/registry 导出重新暴露了公共 API:
export { getRegistries, getRegistryItems, resolveRegistryItems,
getRegistry, getRegistriesIndex } from "./api"
export { searchRegistries } from "./search"
export { RegistryError, RegistryNotFoundError, /* ... */ } from "./errors"
这套 API 与 MCP server 内部使用的完全一致。库作者可以直接导入它来构建自定义工具:
import { searchRegistries, getRegistryItems } from "shadcn/registry"
const results = await searchRegistries(["@shadcn"], {
query: "button",
limit: 10,
})
api.ts 模块在内部组合了 builder、fetcher 和 resolver。getRegistryItems 同时处理带命名空间的条目(如 @acme/button)和 URL 形式的条目,为请求设置包含认证 header 的 registry 上下文,并用 Zod schema 对响应进行校验。
搜索子系统
searchRegistries 函数实现了跨多个 registry 的搜索,流程如下:
- 对每个 registry,通过
getRegistry获取完整的 registry 数据 - 将条目映射为可搜索的格式,附带
addCommandArgument(例如@shadcn/button) - 如果提供了查询词,则通过
fuzzysort对name和description字段进行模糊匹配 - 使用
offset和limit进行分页处理 - 用
searchResultsSchema对结果进行校验
flowchart TD
A["searchRegistries(['@shadcn', '@acme'], {query: 'button'})"]
A --> B["Fetch @shadcn registry"]
A --> C["Fetch @acme registry"]
B --> D["Map to searchable items"]
C --> E["Map to searchable items"]
D --> F["Concatenate all items"]
E --> F
F --> G["fuzzysort.go(query, items)"]
G --> H["Apply pagination"]
H --> I["Return SearchResults"]
fuzzysort 库提供容错式模糊匹配,阈值可配置(默认为 -10000,非常宽松)。返回结果中包含 addCommandArgument 字段,即传给 shadcn add 的精确字符串。
三层接入面设计:CLI、库与 AI
纵观整体架构,shadcn/ui 被有意设计为一个三层接入面系统:
graph TD
subgraph "Shared Internals"
Parser["parser.ts"]
Builder["builder.ts"]
Fetcher["fetcher.ts"]
Resolver["resolver.ts"]
Schema["schema.ts"]
Context["context.ts"]
Search["search.ts"]
API["api.ts"]
end
subgraph "Surface 1: CLI"
Init["init command"]
Add["add command"]
Build["build command"]
end
subgraph "Surface 2: Library"
RegExport["shadcn/registry"]
SchemaExport["shadcn/schema"]
end
subgraph "Surface 3: AI"
MCP["shadcn/mcp"]
Tools["7 MCP tools"]
end
Init --> API
Add --> API
Build --> Schema
RegExport --> API
SchemaExport --> Schema
MCP --> API
MCP --> Search
Tools --> MCP
API --> Parser
API --> Builder
API --> Fetcher
API --> Resolver
API --> Context
Search --> API
这一架构的核心原则在于:三层接入面共享同一套内部模块。当 resolver 新增功能(比如第 2 篇中介绍的拓扑排序),CLI 用户、编程调用方和 AI 助手可以立即同步受益——没有额外的适配层,也没有独立实现,只是同一套代码的不同入口。
package.json 的子路径导出划定了清晰的边界。导入 shadcn/registry 不会引入 CLI 的 Commander 依赖;导入 shadcn/schema 只会获取 Zod schema,不包含任何运行时代码。tsup.config.ts 的 tree-shaking 确保每个入口点只打包自身所需的内容。
这并非偶然。CLI 入口 index.ts 最后一行 export * from "./registry/api" 是一个刻意为之的选择,目的是让 CLI 模块同时也是一个编程式库。用最小的 API 接入面,覆盖最广泛的使用场景。
提示: 如果你正在围绕 shadcn/ui 构建工具(VS Code 插件、CI 检查、文档生成器等),请从
shadcn/registry而非根路径导入。这样可以获得更小的打包体积,避免引入 CLI 专属的依赖。
系列总结
在这六篇文章中,我们完整梳理了 shadcn/ui 的整体架构:
- 架构概览:一个具备多接入面 CLI 包与 registry 协议的 monorepo
- Registry 协议:命名空间解析、URL 构建、HTTP 请求与拓扑排序
- Transformer:基于 ts-morph 的 AST 级代码改写与 PostCSS 样式映射
- 构建流水线:bases × styles 的笛卡尔积,生成静态 JSON 文件
- 初始化流程:框架检测、模板、preset 与 monorepo 路由
- AI 集成:MCP server、编程式 API 与三层接入面设计
贯穿全系列的核心架构洞察,在于 cn-* 抽象层的设计。通过将组件逻辑与视觉样式解耦——以抽象 CSS 类为媒介——shadcn/ui 实现了一件难得的事:单一组件实现,兼容多种 headless 库、多种视觉风格、多种图标库和多种项目配置,所有适配在安装时完成,而非运行时。最终落入你项目中的代码,没有任何抽象开销——就是组件本身,以你选择的方式精确渲染。