ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

自建Figma MCP服务器:从零到生产可用的AI设计稿桥接实践

自建Figma MCP服务器:从零到生产可用的AI设计稿桥接实践 最近在做一个 AI 辅助设计项目时业务方提了一个有些“紧急”的需求希望 AI 能直接读取 Figma 设计稿根据设计稿里的图层和样式自动生成前端页面代码同时做一轮设计规范检查。这个需求本身不算特别新奇但难点在于我们当时还没有一套稳定的“Figma 数据桥接层”。项目排期已经启动AI 能力也要同步上线整个状态像极了“飞机已经在跑道上滑行引擎还得现场造”。最后我们选择基于 Model Context ProtocolMCP自建一个 Figma MCP 服务器把 Figma 设计数据通过标准协议暴露给 AI 客户端。这个方案最终支撑了后续多个业务场景包括设计稿结构读取、节点样式提取、图片导出以及样式 token 聚合。本文将完整复盘这个“边飞边造引擎”的过程内容包括 MCP 核心概念、Figma API 的调用要点、从零搭建一个可运行的 Figma MCP 服务器、中途遇到的坑以及最终沉淀下来的最佳实践。如果你也在做 AI 与设计工具之间的集成或者正准备给自己的团队搭一个类似的 MCP 服务这篇文章应该能帮你少走不少弯路。1. 背景与核心概念1.1 什么是 Figma MCP 服务器先解释一下 MCP。MCP 的全称是 Model Context Protocol也就是模型上下文协议它由 Anthropic 提出并推动开源主要目的是解决 AI 模型与外部数据、工具之间“接口混乱”的问题。在没有 MCP 之前每个 AI 应用接入一个外部系统往往需要单独写一套接口协议接入方越多重复适配的工作量就越大。MCP 有点像 AI 世界的“USB-C 接口”模型不需要关心对面是数据库、日历还是设计工具只要通过统一的 MCP 协议就能调用外部服务暴露的“工具”。在这个体系里Figma MCP 服务器就是一个运行在本机或远端服务上的中间层。它对外遵循 MCP 协议对内调用 Figma REST API。AI 客户端例如 Claude Desktop、支持 MCP 的 IDE 插件或者你自研的 Agent可以按需发现并调用我们暴露的工具比如“读取指定页面的节点树”“导出某个节点的图片”“获取文件里的颜色样式”等。Figma MCP 服务器拿到参数后会向 Figma API 发起请求把返回的 JSON 结构化数据整理后交回给 AIAI 再基于这些数据继续推理和生成代码。1.2 为什么不自接 Figma API而是选择自建 MCP 服务器有人可能会问既然是调用 Figma API为什么不直接在业务代码里写一堆 fetch 请求非要中间加一层 MCP 服务器这个疑问很自然但结合我们的场景自建 MCP 服务器有几个无法回避的优势。首先AI 客户端天然支持 MCP。如果希望 Claude、Cursor、Trae、CodeBuddy 这类工具直接操作 Figma 数据在它们里面配置一个 MCP 服务器比给每个工具都写一套插件或脚本要通用得多。其次MCP 协议提供了一套标准的“工具描述 参数校验”机制AI 可以根据工具名称和描述自动决定何时调用、传什么参数这比维护一堆“提示词 自定义函数”要稳定。第三我们团队内部还有大量私有设计规范比如颜色命名规则、组件命名规范、字体使用约束直接暴露原始 API 会让 AI 拿到太多无关信息而 MCP 服务器可以按业务需要裁剪数据只返回对当前任务有用的内容。当然官方和社区已经有一些现成的 Figma MCP 服务器热词里也能搜到“open figma mcp”“开源社区 figma mcp (community) 安装”之类的信息。但现成方案通常面向通用场景返回的数据结构未必符合我们的内部诉求。比如有的服务器把所有节点详情一股脑返回AI 很容易被大段 JSON 淹没有的服务器没有做样式聚合AI 很难区分设计 token 和局部样式。最后我们决定“边飞边造”先找一个最小可用版本跑通链路再在真实业务反馈中持续迭代。1.3 适用场景与读者这篇文章适合以下几类读者AI Engineer正在做 AI 与设计工具、协同办公工具之间的能力打通。前端开发者希望让 AI 直接读取设计稿并生成代码。设计系统工程师需要自动化采集 Figma 中的样式 token、组件元数据。对 MCP 协议感兴趣想找一个真实项目练手的开发者。读完本文你应该能理解 MCP 服务器与 Figma API 之间的关系掌握如何用 Node.js 搭建一个具备多工具的 Figma MCP 服务器并知道在真实项目中如何规避认证、性能、安全等方面的坑。2. 环境准备与版本说明2.1 运行环境我们这次采用 Node.js 来开发 MCP 服务器因为 MCP 官方提供了成熟的 TypeScript SDK而且前端团队对 Node 生态比较熟悉便于后续维护。具体环境建议如下Node.js 18 或以上版本因为示例代码会使用全局fetch。npm 或 pnpm用于依赖安装。TypeScript用于开发调试也可以直接写 JavaScript。MCP Inspector用于本地验证 MCP 服务器是否运行正常。Figma 侧需要准备一个可以访问的设计文件以及一个 Personal Access Token。获取 Token 的路径是Figma 右上角头像 → Settings → Security → Personal access tokens → Generate new token。生成时建议只勾选“File content”相关读取权限不要授予写入权限。Token 是一个很长的字符串后续会放到环境变量里不要硬编码到代码中。2.2 项目结构一个比较清晰的 Figma MCP 服务器项目结构大致如下figma-mcp-server/ ├── src/ │ ├── index.ts # 入口创建 MCP Server 并注册工具 │ ├── figma.ts # 封装 Figma API 请求逻辑 │ └── tools/ │ └── design-tools.ts # 设计类工具定义与实现 ├── .env # 环境变量文件 ├── package.json ├── tsconfig.json └── README.md如果你的项目规模不大也可以先只用一个index.ts文件跑通链路。我们第二版才逐步拆分为多个模块保持代码可维护性。2.3 依赖与版本说明核心依赖包括npm install modelcontextprotocol/sdk zod npm install -D typescript tsx types/node其中modelcontextprotocol/sdk是 MCP 官方 TypeScript SDKzod用于工具参数校验tsx用于本地直接运行 TypeScript 文件。需要提醒的是MCP SDK 版本迭代比较快不同版本的 API 可能略有差异。本文示例代码基于当前较为常见的server.tool()写法如果你安装的版本有变化请以官方文档为准。Figma REST API 的接口路径相对稳定但响应字段偶尔会有调整所以代码里应避免依赖未声明字段。3. MCP 与 Figma API 核心原理拆解3.1 MCP 工作模型MCP 的架构可以简单理解为“客户端—服务器”模型。AI 应用比如 Claude Desktop作为 MCP Client负责与用户对话、决定何时调用工具MCP Server 是我们编写的服务负责实际执行工具逻辑。两者之间通过传输层通信常见的传输方式有两种Stdio本地进程间通信。MCP Client 启动我们提供的命令行进程通过标准输入stdin和标准输出stdout传递 JSON 消息。SSE / Streamable HTTP远程通信。MCP Server 作为一个 HTTP 服务运行Client 通过网络请求调用。本地开发阶段使用 Stdio 最方便。但有一个非常关键的点如果使用 Stdio 传输MCP Server 的所有日志输出都不能写到 stdout否则会污染协议消息导致 Client 解析失败。日志必须写入 stderr或者直接写入日志文件。MCP 协议定义了三种核心原语Tools可被 AI 调用的函数需要提供名称、描述、输入参数 JSON Schema。Resources可读取的数据资源类似文件读取。Prompts预设的提示词模板。对于 Figma MCP 服务器最核心的是 Tools。通过注册多个工具AI 就能按需获取设计稿的各个维度信息。3.2 Figma API 常用端点在开始写代码前需要对 Figma REST API 的常用端点有一个整体认识。下面是我们用到最多的几类接口接口作用关键参数GET /v1/files/{file_key}获取文件基本信息与节点树file_key可选depth控制返回深度GET /v1/files/{file_key}/nodes?ids...获取指定节点的详细数据file_keyids逗号分隔节点 IDGET /v1/images/{file_key}?ids...获取节点图片导出 URLfile_keyidsformatscaleGET /v1/files/{file_key}/styles获取文件内使用的样式列表file_keyGET /v1/styles/{style_key}获取样式详情style_keyGET /v1/components/{component_key}获取组件详情component_key调用时需要在 HTTP Header 中携带X-Figma-Token: token。如果返回 200响应体通常是较大的 JSON如果返回 403说明 Token 没有相应文件权限返回 404 则往往是文件 key 写错了或者文件没有分享给当前账号。3.3 设计 MCP 工具集时的取舍一开始我们想把 Figma API 的所有能力都暴露给 AI很快就发现这是一个错误。AI 的上下文窗口有限如果一次返回几 MB 的节点树模型要么被无关数据干扰要么直接报错。更好的做法是“按需提供、精简输出”。我们最终保留了四个核心工具get_figma_file_meta获取文件名、页面列表、最后修改时间等摘要信息。get_figma_node_tree获取指定页面的节点树只保留类型、名称、可见性和关键布局属性。get_figma_node_detail获取某个具体节点的完整样式、文本内容、填充色等。get_figma_image_export导出节点图片返回图片 URL 或 Base64 数据。每个工具的参数都要用zod做严格校验描述信息要写得尽量清楚。因为 AI 是“读描述来决定调用哪个工具”的描述越明确工具被调用的准确率越高。4. 边飞边造从最小可用到生产可用的实战复盘4.1 第一版一个只读文件树的“应急引擎”需求很急所以第一版我们只做了一个功能让 AI 能读取指定 Figma 文件的基本信息和页面列表。这个功能虽然简单但足以验证整条链路是否通畅。下面是第一版完整的src/index.ts代码import { McpServer } from modelcontextprotocol/sdk/server/mcp.js; import { StdioServerTransport } from modelcontextprotocol/sdk/server/stdio.js; import { z } from zod; const FIGMA_TOKEN process.env.FIGMA_TOKEN ?? ; const FIGMA_BASE https://api.figma.com/v1; const server new McpServer({ name: figma-mcp-server, version: 0.1.0, }); async function fetchFigma(path: string) { const res await fetch(${FIGMA_BASE}${path}, { headers: { X-Figma-Token: FIGMA_TOKEN, }, }); if (!res.ok) { const text await res.text(); throw new Error(Figma API ${res.status}: ${text}); } return res.json(); } server.tool( get_figma_file_meta, 获取Figma文件的基本信息包括文件名、最后修改时间、页面列表, { file_key: z.string().describe(Figma文件Key通常从URL中获取), }, async ({ file_key }) { const data: any await fetchFigma(/files/${file_key}?depth1); const pages data.document?.children?.map((page: any) ({ id: page.id, name: page.name, type: page.type, })) ?? []; const summary { name: data.name, lastModified: data.lastModified, thumbnailUrl: data.thumbnailUrl, pages, }; return { content: [{ type: text, text: JSON.stringify(summary, null, 2) }], }; } ); const transport new StdioServerTransport(); await server.connect(transport);这段代码做三件事创建了一个名为figma-mcp-server的 MCP Server。注册了一个get_figma_file_meta工具参数是file_key。工具内部请求 Figma 的/files/{file_key}?depth1接口只取页面级别的节点返回给 AI。注意fetchFigma函数里对错误的处理。如果 Figma API 返回 401、403 或 404我们会把状态码和响应文本直接抛给上层这样 AI 看到错误后能尝试修正参数而不是面对一个空数据。运行这个服务器很简单在项目根目录执行npx tsx src/index.ts此时程序会等待 stdin 的输入看起来像“卡住”这其实是正常现象因为它正在等待 MCP Client 连接。为了验证服务器是否正常可以使用 MCP Inspector 工具。4.2 第二版加入图片导出与样式提取第一版跑通后业务方很快提出了新的要求AI 不能只看页面名称还需要读取具体节点信息甚至要把某个设计图导出来给多模态模型处理。于是我们在第二版加入了两个新工具get_figma_node_detail和get_figma_image_export。新增工具的核心片段如下server.tool( get_figma_node_detail, 获取指定Figma节点的详细数据包括位置、尺寸、样式、文本内容, { file_key: z.string().describe(Figma文件Key), node_id: z.string().describe(Figma节点ID), }, async ({ file_key, node_id }) { const data: any await fetchFigma( /files/${file_key}/nodes?ids${encodeURIComponent(node_id)} ); const node data.nodes?.[node_id]?.document; if (!node) { throw new Error(Node ${node_id} not found); } return { content: [{ type: text, text: JSON.stringify(node, null, 2) }], }; } ); server.tool( get_figma_image_export, 导出指定Figma节点为PNG图片返回可访问的图片URL, { file_key: z.string().describe(Figma文件Key), node_id: z.string().describe(Figma节点ID), }, async ({ file_key, node_id }) { const data: any await fetchFigma( /images/${file_key}?ids${encodeURIComponent(node_id)}formatpngscale2 ); const url data.images?.[node_id]; if (!url) { throw new Error(Image export failed for node ${node_id}); } return { content: [ { type: text, text: JSON.stringify({ node_id, image_url: url }, null, 2), }, ], }; } );这里需要说明一下图片导出逻辑。GET /v1/images/{file_key}接口返回的图片是一个短期有效的 URLAI 拿到这个 URL 后如果需要进一步处理可以再通过 HTTP 请求下载图片。但是如果 Figma 文件权限设置比较严格这个 URL 可能无法被外部访问。一个更稳妥的做法是在 MCP 服务器内部直接下载图片转成 Base64 后返回给 AI。考虑到 MCP 文本消息的容量这种方案更适合小尺寸图片大图还是建议返回 URL 由客户端自行处理。4.3 第三版接入真实 MCP 客户端工具编写完成后我们开始把它接入真实的 AI 客户端。第一次接入的是 Claude Desktop配置方式是在它的 MCP 配置文件中增加一段 JSON{ mcpServers: { figma-mcp-server: { command: npx, args: [tsx, /absolute/path/to/figma-mcp-server/src/index.ts], env: { FIGMA_TOKEN: your_figma_token_here } } } }这里最关键的一点是command和args必须能直接启动我们的服务器进程FIGMA_TOKEN通过环境变量注入而不是写死在代码里。如果你使用的是 IDE 插件或者自研 Agent配置方式大同小异本质都是让 MCP Client 能拉起这个 Stdio 子进程。接入后我们在对话框里测试了一个真实 Prompt请读取 Figma 文件abc123的页面列表然后进入“首页”页面找到所有文本节点列出它们的字号和颜色。AI 会依次调用get_figma_file_meta和get_figma_node_tree把返回的数据汇总成表格。这种体验比人工复制图层信息到对话框里高效得多。4.4 中途踩过的性能与数据量坑第一版上线后我们很快就遇到了性能问题。Figma 的一个复杂文件节点树可能有几万个节点如果 AI 请求的是顶层页面Figma API 返回的 JSON 可能达到几十 MB。这在本地调试时还能忍受一旦通过 Stdio 传给 AI 客户端轻则等待超时重则直接把客户端进程搞崩。我们用了几个办法解决depth参数调用/files/{file_key}时增加depth只获取前几层节点避免一次性拉全量树。节点裁剪在返回给 AI 之前只保留 type、name、id、visible、boundingBox 等关键字段丢弃大量样式辅助字段。分级读取先让 AI 获取页面列表再传入页面 ID 获取具体节点而不是一次取完整棵树。增加缓存对同一个文件的节点树缓存 5 分钟减少重复调用 Figma API。这套组合拳之后AI 读取大文件的速度明显提升也很少再出现客户端超时的情况。5. 常见问题与排查思路5.1 认证与权限类问题现象常见原因解决思路返回 401Token 无效或过期在 Figma 设置里重新生成 Personal Access Token返回 403Token 没有文件访问权限将 Token 所在账号添加到 Figma 文件协作者中返回 404file_key 或 node_id 错误从 Figma URL 中复制正确的 file_key节点 ID 可通过页面 tree 获取工具返回空数据API 响应结构与预期不一致先用 curl 或 Postman 直接调用 Figma API观察真实返回字段在实际项目里Figma 权限问题是最常见的。我们曾经不止一次遇到“MCP 服务器明明启动了但 AI 读不到文件”的情况最后的排查结论都是 Token 对应的账号未被添加到文件分享名单中。所以建议在环境准备阶段就把权限验证步骤写进团队文档避免每个人重复踩坑。5.2 数据读取与性能类问题现象常见原因解决思路调用工具后长时间无响应文件太大Figma API 返回慢使用depth参数或分节点查询返回内容过多导致客户端超时没有裁剪节点数据只返回关键字段限制 JSON 层级图片 URL 无法访问文件权限或 URL 过期改为服务器端下载后返回 Base64频繁调用被限流超过了 Figma API 速率限制增加缓存添加指数退避重试处理这类问题时我建议先把汤 Postman/curl 里调用一次看真实的响应时间和数据量。只有在源头确认了响应规模才能决定是优化 MCP 服务器还是调整 AI 的调用策略。5.3 MCP 接入与调试类问题现象常见原因解决思路MCP Inspector 看不到工具列表Server 启动失败或 stdout 被日志污染把日志改到 stderr重新启动工具参数校验失败参数描述不清晰或参数名不匹配在zodSchema 中增加.describe()AI 不调用工具而乱回答工具描述不明确或输入 UX 不好在 Prompt 中给出工具使用示例连接时提示“closed”子进程退出检查环境变量是否传入路径是否正确这里要特别提一下 stdout 污染问题。因为 Stdio 传输依赖 stdout 传递消息任何console.log都会造成协议解析失败。我们团队在最初调试时习惯性地在代码里加了console.log(server start)结果 MCP Inspector 直接无法连接。改成console.error(server start)后就正常了。6. 最佳实践与工程建议6.1 安全与权限边界Figma Token 属于敏感凭据任何时候都不应该提交到 Git 仓库。我们统一使用环境变量注入并在.env.example中只保留变量名不填入真实值。在权限设计上遵循最小权限原则。如果业务只需要读取设计稿Token 就不要授权写入能力。如果团队有多人协作最好每个成员使用自己的 Token而不是共用一个高权限 Token这样在出现异常调用时能够快速定位到具体责任人。此外如果你把 MCP 服务器部署到远程环境并且通过 SSE / HTTP 方式提供服务一定要在网关层增加访问控制。MCP 服务器本身不会校验调用者身份如果直接暴露到公网任何人都可能调用你的 Figma Token风险很大。6.2 代码可维护性MCP 工具会随着业务需求不断增长如果不做好分类很容易变成一个巨大的“工具垃圾桶”。建议按照业务域拆分文件例如设计工具、标注工具、导出工具、规范检查工具等每个文件只注册自己域内的工具。工具命名也需要统一。我们使用get_前缀表示读取操作export_前缀表示导出操作check_前缀表示校验操作。这样 AI 从工具名就能大致判断其作用减少误用。还要给每个工具写清晰的描述。MCP 的工具描述不是给程序员看的注释而是给模型看的“使用说明书”。描述里应包含这个工具做什么、什么时候该用、关键参数的含义、返回结构是什么。比如get_figma_node_tree获取指定页面的节点树适合需要查看页面整体结构时使用。返回节点包含id、name、type、boundingBox不包含深层样式信息。6.3 生产环境稳定性进入生产环境后稳定性比功能数量更重要。第一需要对 Figma API 的调用做缓存。同一个文件在短时间内被多个 AI 会话调用没有必要反复请求 Figma API。我们在内存里做了一层 Map 缓存并设置 TTL比如 5 分钟对降低限流风险有很大帮助。第二要做好错误重试。Figma API 偶尔会返回 429限流或 5xx 错误简单的指数退避重试就能解决大部分问题。但要注意并非所有错误都适合重试401/403 这类权限错误重试再多也没有意义。第三返回给 AI 的数据要做严格的大小限制。我们会在工具内部把节点树裁剪到最多返回 200 个关键节点超出部分提示 AI 缩小查询范围。这个限制放在服务端处理比依赖 Prompt 约束靠谱得多。第四日志要结构化。虽然 Stdio 模式下日志只能走 stderr但我们建议仍然使用统一格式比如[timestamp] [level] [tool_name] message方便后期写日志采集和分析。7. 总结与下一步规划这次“边飞边造引擎”的过程表面上是搭建了一个 Figma MCP 服务器实际上我们更核心的收益是梳理清楚了“AI 设计数据”这条链路上的关键节点MCP 工具如何设计、Figma API 如何裁剪、客户端如何接入、性能如何优化。从一个最小的get_figma_file_meta工具开始到后来支持节点详情、图片导出、样式聚合整个过程没有一步到位而是根据真实业务反馈不断迭代。现在这个服务器已经成为我们团队 AI 设计辅助能力的基础设施。如果你也想动手做一个自己的 Figma MCP 服务器建议第一步先照着第四节的第一个版本代码跑通 MCP Inspector确认链路正常然后挑一个最常用的场景比如“获取页面节点树”把它做成工具最后再根据实际需要逐步扩展。下一步可以继续探索的方向包括把 Figma 设计变量自动转换成前端的 CSS Variables 或 Design Tokens在 MCP 服务器中增加 Resources让 AI 可以把设计稿当作上下文资源读取以及把 Stdio 传输升级为 SSE 远程服务支撑团队层面的共享调用。真正的工程价值往往不在代码本身而在于我们愿意在模糊需求中快速试错先把最小闭环跑起来再一点一点把引擎修得更强大。
返回列表