Figma Storybook Component Matching MCP Server
Figma → Storybook 组件匹配 MCP 服务器
目标
创建一个远程 MCP 服务器。旨在接收 Figma 设计节点输入,将其与我们团队的 React 组件(已注册在 Storybook 中)进行匹配,并生成使用代码示例。
LLM (Claude) 应能通过此 MCP 处理以下请求:
“分析这个 Figma URL”
“告诉我如何用我们的组件实现这个 Figma 节点”
“展示 3 个候选组件”
技术栈
运行时: Cloudflare Workers
语言: TypeScript (strict mode)
MCP: 使用
@modelcontextprotocol/sdk+agents包传输: Streamable HTTP,端点为
/mcp验证: zod
构建/部署: wrangler
目标框架: React (代码生成时输出 JSX)
认证 (选项 A: Bearer Token)
所有 MCP 请求都需要
Authorization: Bearer <token>头部与
env.MCP_AUTH_TOKEN进行比对,不匹配则返回 401认证失败需返回明确的错误消息 (
{"error": "invalid_token"})
环境变量 (在 wrangler 中定义)
FIGMA_TOKEN: Figma 个人访问令牌 (由服务器保管)STORYBOOK_URL: Storybook 基础 URL (例如:https://storybook.example.com)MCP_AUTH_TOKEN: 用于客户端认证的令牌COMPONENT_IMPORT_PREFIX: 代码生成时的导入路径 (默认为@/components)
本地开发使用 .dev.vars,生产环境通过 wrangler secret put 管理。wrangler.toml 中仅保留虚拟占位符。
暴露的工具 (Tools)
1. get_figma_node
说明: 接收 Figma URL 并以精简格式返回节点的核心信息
输入 (zod):
{
url: string // Figma 노드 URL (예: https://www.figma.com/file/XXX/...?node-id=1%3A2)
}操作:
从 URL 解析
fileKey和nodeId(?node-id=1%3A2→ 解码为1:2)调用 Figma API:
GET https://api.figma.com/v1/files/{fileKey}/nodes?ids={nodeId}头部:
X-Figma-Token: {env.FIGMA_TOKEN}
仅从响应中提取以下内容 (Figma 响应过于冗长,需精简):
节点名称 (
name)节点类型 (
type: FRAME, INSTANCE, TEXT, ...)若为组件,则提取组件名称 (
componentId→componentName)样式: 背景色、边框、圆角、内边距、布局模式 (autolayout 方向)、间距
若为文本,则提取
characters和字体信息子结构: 仅提取子节点名称/类型,深度为 1 (不递归,避免过长)
组件变量/变体信息 (如有)
输出: 包含上述信息的精简 JSON 对象
错误: 区分 URL 解析失败、Figma API 4xx/5xx、令牌过期等错误消息
2. get_figma_subtree
说明: 递归获取节点的完整树结构 (用于分析整个页面/框架)
输入:
{
url: string,
maxDepth?: number // 기본 3, 너무 깊으면 토큰 폭발
}操作: 与 get_figma_node 类似,但递归子节点直到 maxDepth。每个子节点也采用精简格式。
3. list_stories
说明: 返回我们 Storybook 的组件列表
输入: 无 (或 { filter?: string } 用于搜索)
操作:
获取
${env.STORYBOOK_URL}/index.json(失败时回退) 尝试
${env.STORYBOOK_URL}/stories.json从
entries对象中仅提取type: "story"的项 (排除 docs 页面)转换为以下格式:
{
id: string,
componentName: string, // title에서 마지막 "/" 뒤 부분 (예: "Forms/Button" → "Button")
storyName: string, // name 필드
fullTitle: string, // 원본 title
tags: string[]
}[]缓存: 响应在内存中缓存 5 分钟 (无需使用 KV,使用简单变量即可)。Workers 实例生命周期较短,不宜设置过长。
4. get_story_details
说明: 特定 story 的详细信息 (props, args)
输入:
{ storyId: string }操作:
在
index.json中查找对应 ID如可能,从
${STORYBOOK_URL}/stories.json或基于 ID 的元数据中提取 argTypes整理 props 签名:
{
id: string,
componentName: string,
description?: string,
props: {
name: string,
type: string,
required: boolean,
description?: string,
defaultValue?: any
}[]
}若无法获取 argTypes,则 props 为空数组,并添加 note: "argTypes unavailable"。
5. match_figma_to_components
说明: 返回与 Figma 节点数据匹配的组件候选及其评分 (核心工具)
输入:
{
figmaNode: <get_figma_node 출력 형식>,
topK?: number // 기본 3
}操作:
通过
list_stories获取所有组件计算每个组件的匹配得分:
名称相似度 (权重 0.5): Figma 节点名称 vs
componentName精确匹配: 1.0
忽略大小写匹配: 0.9
包含关系: 0.6
基于 Levenshtein 距离: 0~0.5
结构匹配 (权重 0.3): 推断子节点模式
Figma 子节点仅为文本 → “Button”, “Label” 候选 +
图标 + 文本 → “Button”, “Tag”, “Chip” 候选 +
多个卡片形式子节点 → “List”, “Grid” 候选 +
标签匹配 (权重 0.2): Storybook story 标签中包含 Figma 节点名称的关键词
返回前 K 个 (默认为 3):
{
storyId: string,
componentName: string,
score: number, // 0~1
reasons: string[] // 왜 매칭됐는지 사람이 읽을 수 있게
}[]剔除匹配得分低于 0.3 的项 (过滤无意义匹配)。
6. generate_component_usage
说明: 使用匹配的组件 + Figma 节点信息生成 React JSX 代码示例
输入:
{
storyId: string,
figmaNode: <get_figma_node 출력 형식>
}操作:
通过
get_story_details获取 props 签名尝试将 Figma 节点的文本、样式、变体信息映射到 props
Figma 文本 →
children或labelpropFigma 变体名称 → 匹配的 prop 值
生成 JSX 代码字符串
输出:
{
code: string, // <Button variant="primary">Click me</Button>
importStatement: string, // import { Button } from "@/components/Button"
notes: string[] // 매핑 추측이나 빠진 정보 안내
}导入路径基于环境变量 env.COMPONENT_IMPORT_PREFIX (默认值 "@/components")。
项目结构
figma-storybook-mcp/
├── src/
│ ├── index.ts # Worker 진입점, 인증 미들웨어, MCP 라우팅
│ ├── mcp.ts # MyMCP 클래스 (도구 등록)
│ ├── auth.ts # Bearer 토큰 검증
│ ├── figma/
│ │ ├── client.ts # Figma REST API 호출
│ │ ├── url-parser.ts # URL → fileKey + nodeId
│ │ └── normalizer.ts # Figma 응답 → 정제된 형식
│ ├── storybook/
│ │ ├── client.ts # index.json fetch + 캐싱
│ │ └── types.ts
│ ├── matching/
│ │ ├── scorer.ts # 매칭 점수 계산
│ │ └── name-similarity.ts # Levenshtein 등
│ ├── codegen/
│ │ └── react.ts # JSX 코드 생성
│ └── types.ts # 공통 타입
├── tests/
│ ├── url-parser.test.ts
│ ├── normalizer.test.ts
│ └── scorer.test.ts
├── wrangler.toml
├── .dev.vars.example # 실제 .dev.vars는 gitignore
├── package.json
├── tsconfig.json
├── vitest.config.ts
└── README.md实现要求
类型安全: 所有工具输入 zod 模式、输出类型均需明确定义
错误处理:
Figma 401 → “Figma 令牌过期/无效”
Figma 404 → “找不到节点”
Storybook 获取失败 → 明确的消息
所有错误均以 MCP 可理解的格式返回
日志记录: 使用
console.log记录工具调用的开始/结束,错误使用console.error。在 Workers 控制台中可见测试: 使用 vitest 进行核心逻辑单元测试 (URL 解析、匹配评分、精简逻辑)
更新 README:
工具用途说明
环境变量说明
本地运行 (
npm run dev)部署 (
npm run deploy)如何连接到 Claude Desktop / Claude.ai
每个工具的输入输出示例
工作流程 (分阶段报告并进行)
Phase 1: 设置
项目初始化,安装依赖
编写
wrangler.toml,tsconfig.json确认空 MCP 服务器在
/mcp响应 (即使工具数为 0 也可)
Phase 2: 认证
Bearer Token 验证中间件
确认使用错误令牌调用时返回 401
Phase 3: Figma 工具
figma/url-parser.ts+ 单元测试figma/client.ts(实际 API 调用)figma/normalizer.ts(响应精简)注册
get_figma_node工具确认实际 Figma URL 的运行情况
Phase 4: Storybook 工具
storybook/client.ts(index.json 获取 + 缓存)注册
list_stories,get_story_details
Phase 5: 匹配
matching/scorer.ts+ 单元测试注册
match_figma_to_components
Phase 6: 代码生成
codegen/react.ts注册
generate_component_usage
Phase 7: 收尾
添加
get_figma_subtree编写 README
提供
.dev.vars.example
每个阶段完成后,简要报告“已完成此项,接下来进行下一项”。
注意事项
Cloudflare Workers 仅支持部分 Node.js API。不支持 fs, child_process 等。基于 fetch 编写
使用
@modelcontextprotocol/sdk的最新稳定版本MCP 标准更新较快,请遵循
agents包的最新模式不要一次性完成,分阶段验证进行
代码清晰,注释仅用于业务逻辑 (如匹配评分等)
开始
请从 Phase 1 开始。
Related MCP Connectors
The Figma MCP server brings Figma design context directly into your AI workflow.
Serves your design system and coding standards to coding agents, so they stop guessing.
Build and manage your design system with AI: tokens, themes, components, icons, Figma and code.
Live React design-system APIs, patterns, and code validation so AI agents build real UI, not slop.