1. 设计稿与代码之间的那道墙,终于被这个插件凿穿了
做过前端或者全栈的朋友应该都有过这种体验:设计师在 Figma 里改了一版稿子,标注、间距、颜色、圆角全变了,然后你在群里收到一句“改好了,你看下”。你打开 Figma,对着屏幕一点点量像素、抄色值、数栅格,再回到编辑器里改 CSS。如果只是改个颜色还好,最怕的是结构性的调整——某个卡片从横向排列变成纵向、某个按钮从实心变成描边、某个模块整体挪了位置。这种时候,你不仅要改样式,还要改 DOM 结构,改完还得自己跑一遍看效果,来回折腾大半天。
更让人头疼的是,现在很多团队开始用 AI Agent 辅助写代码,比如让 Agent 根据设计稿生成页面、根据修改意见调整组件。但问题来了:Agent 看不见 Figma。它只能读你贴给它的截图或者文字描述,截图它看不懂精确数值,文字描述又容易漏细节。结果就是 Agent 生成的代码跟设计稿总是差那么点意思,你还得手动去修。
我最近在折腾的一个方案,就是冲着这个痛点去的:Local Figma Agent MCP。这是一个跑在本地的小型服务,通过 MCP(Model Context Protocol)协议把 Figma 的设计数据暴露给 AI Agent,让 Agent 能够直接读取设计稿的图层结构、样式属性、布局信息,甚至反过来修改设计稿。最关键的一点是——它不需要你购买 Figma 的付费套餐。Figma 的 REST API 在免费版上有一些限制,但这个方案走的是本地插件加本地服务的路子,绕开了那些限制,用起来相当顺手。
这篇文章我会把这个方案的来龙去脉讲清楚:它解决什么问题、核心原理是什么、怎么一步步搭起来、实际用起来有哪些坑、以及我踩过之后总结出来的经验。不管你是刚接触 MCP 的新手,还是已经在用 Agent 写代码的老手,应该都能从中拿到可以直接抄作业的东西。
2. 为什么需要 Local Figma Agent MCP:设计稿到代码的断层分析
2.1 传统工作流的三个断点
在聊这个方案之前,先得把问题说透。设计稿到代码的流转,表面上看起来就是“看图写代码”,但实际上中间有三个明显的断点。
第一个断点是信息损耗。设计师在 Figma 里做的稿子,包含了大量结构化信息:图层层级、自动布局的约束、组件的变体、样式的引用关系。但当你把稿子导出成图片或者截图发给开发者时,这些信息全丢了,只剩下像素。开发者看到的是一张扁平的图,得靠肉眼去还原那些原本精确的数值。一个 16px 的间距,你看图可能觉得是 14 也可能是 18,量半天还不一定准。
第二个断点是沟通成本。设计稿里有些东西是“只可意会”的,比如某个交互状态、某个 hover 效果、某个响应式断点下的表现。这些在静态图里看不出来,开发者得反复问设计师,设计师得反复解释。一来一回,时间就耗掉了。
第三个断点是Agent 的盲区。现在大家都在用 AI 辅助编码,但 Agent 的输入要么是自然语言描述,要么是截图。自然语言描述不精确,截图 Agent 又读不懂数值。你让 Agent 根据一张图生成代码,它只能猜,猜出来的东西跟你想要的往往差很远。而且 Agent 没法反过来操作设计稿——你让它改个颜色,它只能告诉你“请把那个按钮改成蓝色”,它自己动不了手。
2.2 MCP 协议为什么适合干这件事
MCP 全称是 Model Context Protocol,简单说就是一套让 AI 模型跟外部工具、数据源对话的标准协议。你可以把它理解成 Agent 的“USB 接口”——只要外部服务实现了这个接口,Agent 就能调用它,读取数据或者执行操作。
为什么用 MCP 而不是直接调 Figma 的 REST API?这里有几个考量。
第一,REST API 有权限和配额限制。Figma 的 REST API 在免费套餐下,对某些接口的调用频率和可访问的数据范围是有限制的。你想让 Agent 频繁读取设计稿的实时状态,走 REST API 可能会碰到配额问题。而本地插件加本地服务的方案,数据在你自己机器上流转,不受这些限制。
第二,MCP 是双向的。REST API 主要是读,你想改设计稿得走另一套逻辑。MCP 的工具体系天然支持“读”和“写”两类操作,Agent 既能获取设计稿信息,也能发起修改请求,交互更自然。
第三,本地化带来的低延迟和隐私性。设计稿数据不出本地,对于有保密要求的团队来说这点很重要。而且本地服务响应快,Agent 调用的时候几乎感觉不到延迟。
2.3 这个方案适合谁用
不是所有人都需要这套东西。如果你只是偶尔切个图,手动量一量也就过去了,没必要折腾。但如果你符合下面几种情况,那这个方案值得花时间搭一下。
一种是频繁跟设计稿打交道的开发者。每天都要从 Figma 里取数值、对样式,手动操作占用了大量时间。另一种是在用 Agent 辅助编码的团队。你已经在用 Agent 写组件、生成页面,但苦于 Agent 读不懂设计稿,生成的结果总需要大量人工修正。还有一种是做设计系统或组件库的团队。设计稿和代码之间的同步是个持续性的工作,自动化程度越高越好。
提示:这个方案的核心价值在于“让 Agent 具备读取和操作设计稿的能力”,它不替代设计师的工作,也不替代开发者的判断,而是把重复性的信息搬运工作自动化掉。
3. 核心原理拆解:本地插件加本地服务是怎么跑通的
3.1 整体架构:三个角色各司其职
这套方案里有三个角色:Figma 插件、本地 MCP 服务、AI Agent。它们之间的关系可以这样理解。
Figma 插件跑在 Figma 的插件沙箱里,它负责跟 Figma 的文档模型打交道。插件能读取当前打开的设计稿里所有图层的信息,也能修改这些图层。但插件本身不能直接跟外部的 Agent 通信,它需要一个桥梁。
本地 MCP 服务就是这个桥梁。它跑在你自己的电脑上,监听一个本地端口。插件通过 WebSocket 或者 HTTP 跟这个服务建立连接,把设计稿数据推过去,或者从服务接收修改指令。同时,这个服务实现了 MCP 协议,对外暴露一组工具(tools),Agent 通过 MCP 协议调用这些工具。
AI Agent 就是最终的使用者。它通过 MCP 客户端连接到本地服务,看到服务暴露出来的工具列表,比如“获取当前选中的图层信息”“修改某个图层的填充色”“创建一个新的矩形”等等。Agent 根据你的指令,决定调用哪个工具、传什么参数。
这三个角色串起来,就形成了一条完整的链路:你告诉 Agent 要做什么,Agent 通过 MCP 调用本地服务,本地服务通过 WebSocket 通知 Figma 插件,插件在 Figma 里执行操作,然后把结果原路返回。
3.2 为什么走本地而不是云端
有人可能会问,为什么不直接做一个云端服务,插件连云端,Agent 也连云端,不是更简单吗?
本地方案有几个云端替代不了的优势。首先是数据不出本地。设计稿往往包含未发布的产品信息,走云端意味着这些数据要经过第三方服务器,对于很多团队来说这是不可接受的。其次是没有网络延迟。本地服务跟插件之间的通信是毫秒级的,Agent 调用工具的时候几乎无感。再者是不受套餐限制。Figma 的云端 API 有调用配额,本地插件走的是 Figma 插件 API,不消耗那些配额。
当然,本地方案也有代价。你得自己把服务跑起来,得处理端口占用、进程管理这些琐事。但对于目标用户来说,这点成本换来的是更大的灵活性和可控性,是划算的。
3.3 插件与服务的通信协议设计
插件和服务之间的通信,我采用的是 WebSocket 加 JSON-RPC 风格的请求响应模型。为什么用 WebSocket 而不是普通的 HTTP?因为需要双向实时通信。Agent 发起一个修改请求,服务要能立刻推给插件,插件执行完要能立刻把结果推回来。HTTP 的请求响应模型在这种场景下不够灵活。
消息格式上,我定义了几种基本的消息类型。一种是request,表示一个操作请求,包含方法名和参数。一种是response,表示操作结果,包含成功状态和返回数据。还有一种是event,表示插件主动推送的事件,比如“用户切换了选中的图层”。
请求和响应通过一个自增的id来配对。服务发出请求后,会把这个id记下来,等插件返回同样id的响应时,再把对应的 Promise resolve 掉。这个模式跟 JSON-RPC 2.0 很像,实现起来不复杂,但足够可靠。
3.4 MCP 工具的设计思路
MCP 服务对外暴露的工具,设计得好不好直接决定了 Agent 用起来顺不顺手。我的思路是:工具要原子化,但也要有高层封装。
原子化的工具比如“获取图层列表”“获取图层属性”“设置图层属性”,这些是基础能力,Agent 可以自由组合。但光有这些不够,因为 Agent 往往需要完成一个完整的任务,比如“把这个设计稿里的所有按钮改成圆角”。如果只有原子工具,Agent 得先列出所有图层,再一个个判断是不是按钮,再一个个改,步骤多、容易出错。
所以我还封装了一些高层工具,比如“按名称查找图层”“批量修改匹配图层的样式”“获取当前选中图层的完整样式树”。这些工具内部做了更多的逻辑处理,Agent 调用一次就能完成一个相对完整的操作。
工具的参数设计也有讲究。能用枚举就不用字符串,能设默认值就设默认值,能约束范围就约束范围。这样 Agent 在调用的时候不容易传错参数,即使传错了,服务端也能给出清晰的错误提示。
4. 从零搭建:环境准备与核心环节实现
4.1 环境准备清单
在动手之前,先把需要的东西列清楚。这些东西都是免费的,不需要购买任何付费套餐。
| 组件 | 用途 | 获取方式 |
|---|---|---|
| Figma 桌面端或网页版 | 运行插件、打开设计稿 | 官方渠道 |
| Node.js 18 以上 | 运行本地 MCP 服务 | 官方渠道 |
| 一个支持 MCP 的 Agent 客户端 | 调用工具、发起指令 | 按需选择 |
| 代码编辑器 | 写插件和服务代码 | 按需选择 |
Node.js 的版本建议用 18 或更高,因为 MCP 的 SDK 用到了较新的语言特性。安装完之后,用node -v确认一下版本。
4.2 本地 MCP 服务的搭建
先建一个项目目录,初始化 npm。
mkdir local-figma-mcp cd local-figma-mcp npm init -y然后安装依赖。核心依赖有两个:一个是 MCP 的 SDK,用来实现协议;一个是 WebSocket 库,用来跟插件通信。
npm install @modelcontextprotocol/sdk ws接下来写服务的主文件。这个文件要做几件事:启动 WebSocket 服务、实现 MCP 协议、注册工具、处理消息路由。
import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { WebSocketServer } from 'ws'; // 存储插件连接 let pluginSocket = null; let requestId = 0; const pendingRequests = new Map(); // 启动 WebSocket 服务,等待插件连接 const wss = new WebSocketServer({ port: 8765 }); wss.on('connection', (ws) => { pluginSocket = ws; console.error('Figma 插件已连接'); ws.on('message', (data) => { const msg = JSON.parse(data); if (msg.type === 'response' && pendingRequests.has(msg.id)) { const { resolve, reject } = pendingRequests.get(msg.id); pendingRequests.delete(msg.id); if (msg.error) { reject(new Error(msg.error)); } else { resolve(msg.result); } } }); ws.on('close', () => { pluginSocket = null; console.error('Figma 插件已断开'); }); }); // 向插件发送请求 function sendToPlugin(method, params) { return new Promise((resolve, reject) => { if (!pluginSocket) { reject(new Error('插件未连接')); return; } const id = ++requestId; pendingRequests.set(id, { resolve, reject }); pluginSocket.send(JSON.stringify({ id, method, params })); // 超时处理 setTimeout(() => { if (pendingRequests.has(id)) { pendingRequests.delete(id); reject(new Error('请求超时')); } }, 10000); }); }这段代码是整个服务的地基。它做了三件事:建立 WebSocket 服务、维护插件连接、提供请求发送的封装。sendToPlugin这个函数是后面所有工具的基础,每个工具最终都是通过它把指令发给插件。
4.3 注册 MCP 工具
有了地基之后,往上注册工具。MCP 的工具注册是通过Server实例的setRequestHandler来做的。
const server = new Server( { name: 'local-figma-agent', version: '1.0.0' }, { capabilities: { tools: {} } } ); // 列出所有可用工具 server.setRequestHandler('tools/list', async () => { return { tools: [ { name: 'get_selection', description: '获取当前在 Figma 中选中的图层信息', inputSchema: { type: 'object', properties: {} } }, { name: 'get_node_by_name', description: '按名称查找图层', inputSchema: { type: 'object', properties: { name: { type: 'string', description: '图层名称' } }, required: ['name'] } }, { name: 'update_node_style', description: '修改图层的样式属性', inputSchema: { type: 'object', properties: { nodeId: { type: 'string', description: '图层 ID' }, property: { type: 'string', description: '属性名,如 fills、strokes' }, value: { description: '新的属性值' } }, required: ['nodeId', 'property', 'value'] } } ] }; }); // 处理工具调用 server.setRequestHandler('tools/call', async (request) => { const { name, arguments: args } = request.params; switch (name) { case 'get_selection': return { content: [{ type: 'text', text: JSON.stringify(await sendToPlugin('getSelection', {})) }] }; case 'get_node_by_name': return { content: [{ type: 'text', text: JSON.stringify(await sendToPlugin('getNodeByName', args)) }] }; case 'update_node_style': return { content: [{ type: 'text', text: JSON.stringify(await sendToPlugin('updateNodeStyle', args)) }] }; default: throw new Error(`未知工具: ${name}`); } }); // 启动 MCP 服务 const transport = new StdioServerTransport(); await server.connect(transport);这里我列了三个工具作为示例,实际用的时候可以按需扩展。get_selection用来获取当前选中的图层,这个在调试的时候特别有用。get_node_by_name用来按名称查找,适合 Agent 根据描述定位图层。update_node_style用来修改样式,是写操作的基础。
4.4 Figma 插件端的实现
插件端要做的事情跟服务端对应:连接 WebSocket、接收请求、操作 Figma 文档、返回结果。
// 插件主逻辑 const socket = new WebSocket('ws://localhost:8765'); socket.onopen = () => { console.log('已连接到本地 MCP 服务'); }; socket.onmessage = async (event) => { const msg = JSON.parse(event.data); const { id, method, params } = msg; try { let result; switch (method) { case 'getSelection': result = await getSelection(); break; case 'getNodeByName': result = await getNodeByName(params.name); break; case 'updateNodeStyle': result = await updateNodeStyle(params.nodeId, params.property, params.value); break; default: throw new Error(`未知方法: ${method}`); } socket.send(JSON.stringify({ id, type: 'response', result })); } catch (err) { socket.send(JSON.stringify({ id, type: 'response', error: err.message })); } }; // 获取当前选中图层 async function getSelection() { const selection = figma.currentPage.selection; return selection.map(node => serializeNode(node)); } // 按名称查找 async function getNodeByName(name) { const nodes = figma.currentPage.findAll(n => n.name === name); return nodes.map(node => serializeNode(node)); } // 修改样式 async function updateNodeStyle(nodeId, property, value) { const node = await figma.getNodeByIdAsync(nodeId); if (!node) throw new Error('图层不存在'); node[property] = value; return serializeNode(node); } // 序列化图层信息 function serializeNode(node) { return { id: node.id, name: node.name, type: node.type, x: node.x, y: node.y, width: node.width, height: node.height, fills: node.fills, strokes: node.strokes, cornerRadius: node.cornerRadius, children: node.children ? node.children.map(c => serializeNode(c)) : [] }; }插件端的核心是serializeNode这个函数。它把 Figma 的图层对象转换成一个纯 JSON 结构,这样服务端和 Agent 才能处理。转换的时候要注意,Figma 的某些属性是只读的,某些属性是异步获取的,得区分对待。
4.5 把服务接入 Agent 客户端
服务跑起来之后,最后一步是让 Agent 客户端知道这个服务的存在。不同的客户端配置方式不一样,但核心都是告诉它:有一个 MCP 服务,通过 stdio 启动,命令是什么。
以常见的配置文件为例,大概长这样:
{ "mcpServers": { "local-figma": { "command": "node", "args": ["/path/to/local-figma-mcp/index.js"] } } }配置好之后重启 Agent 客户端,它就能在工具列表里看到我们注册的那几个工具了。你可以试着让它调用get_selection,如果 Figma 里当前有选中的图层,Agent 应该能返回图层的详细信息。
注意:插件和服务之间的端口要一致,默认用 8765。如果这个端口被占用了,改成一个空闲端口,两边同步改。
5. 实际使用中的典型场景与操作演示
5.1 场景一:让 Agent 读取设计稿并生成组件代码
这是最常用的场景。假设设计稿里有一个卡片组件,你想让 Agent 根据它生成 React 代码。
操作流程是这样的:先在 Figma 里选中那个卡片,然后在 Agent 客户端里输入指令,比如“读取我当前选中的图层,生成对应的 React 组件代码,样式用 CSS Modules”。
Agent 会先调用get_selection,拿到选中图层的完整信息,包括层级结构、每个节点的位置尺寸、填充色、圆角、字体等。然后它根据这些信息生成代码。因为拿到的是精确数值,生成的代码在间距、颜色、圆角这些细节上跟设计稿是一致的,不需要你再手动调。
我实测下来,对于一个中等复杂度的卡片组件,Agent 生成的代码大概能还原到九成以上。剩下的那一成主要是自动布局的约束逻辑,这个需要 Agent 理解 Figma 的 auto layout 语义,目前还需要人工微调。
5.2 场景二:批量修改设计稿中的样式
反过来,你也可以让 Agent 修改设计稿。比如设计稿里有二十个按钮,你想把它们的主色从蓝色改成绿色。
指令可以是“找到所有名称包含 Button 的图层,把它们的填充色改成 #00A86B”。Agent 会先调用get_node_by_name或者类似的查找工具,定位到所有匹配的图层,然后逐个调用update_node_style修改填充色。
这个场景的价值在于批量操作。手动改二十个按钮,你得一个个选中、改色,费时费力还容易漏。让 Agent 来做,几秒钟就搞定,而且不会漏。
5.3 场景三:设计稿与代码的一致性检查
这个场景稍微进阶一点。你可以让 Agent 对比设计稿和现有代码,找出不一致的地方。
思路是:Agent 先读取设计稿里某个组件的样式信息,然后读取代码里对应组件的样式,两边对比,列出差异。比如设计稿里圆角是 8px,代码里是 4px,Agent 就会指出来。
这个场景需要 Agent 能同时访问设计稿和代码库。设计稿这边通过 MCP 工具读取,代码那边通过文件系统工具读取。两个信息一对比,差异就出来了。对于维护设计系统来说,这个能力很实用。
5.4 操作演示:一次完整的读取与修改
我把一次完整的操作过程记录下来,方便你对照复现。
第一步,启动本地 MCP 服务。在终端里运行node index.js,看到“WebSocket 服务已启动”和“等待插件连接”的提示。
第二步,在 Figma 里运行插件。打开设计稿,通过插件菜单启动我们写的插件,插件会自动连接到本地服务。服务端终端会打印“Figma 插件已连接”。
第三步,在 Agent 客户端里发起指令。比如输入“获取当前选中的图层,告诉我它的填充色和圆角”。
第四步,观察 Agent 的调用过程。Agent 会调用get_selection,服务端收到请求后通过 WebSocket 转发给插件,插件读取 Figma 的选中状态,序列化后返回。Agent 拿到数据后,用自然语言告诉你结果。
第五步,发起修改指令。输入“把它的圆角改成 12px”。Agent 调用update_node_style,传入 nodeId、property 为 cornerRadius、value 为 12。插件执行修改,Figma 里的图层实时更新。
整个过程从指令发出到设计稿更新,大概一两秒。相比手动操作,效率提升很明显。
6. 常见问题与排查技巧实录
6.1 插件连不上本地服务
这是最常见的问题。表现是插件启动后一直显示“未连接”,或者服务端一直没打印“插件已连接”。
排查思路分几步。先确认本地服务是否真的在运行,终端里有没有报错。然后确认端口是否一致,插件里写的端口和服务端监听的端口必须是同一个。再确认是否有防火墙或者安全软件拦截了本地连接,这种情况在部分系统上会出现,临时关闭或者加白名单可以解决。
还有一个容易被忽略的点:Figma 插件运行在沙箱环境里,它对网络请求有一些限制。WebSocket 连接本地地址通常是允许的,但如果你的 Figma 是网页版,浏览器的安全策略可能会拦截。这种情况建议用 Figma 桌面端。
6.2 Agent 调用工具时报参数错误
这种问题通常出在工具的参数 schema 定义上。Agent 根据 schema 来构造参数,如果 schema 写得不够清晰,Agent 就可能传错。
解决办法是把 schema 写得更明确。比如property这个参数,不要只写“属性名”,要枚举出可能的值:fills、strokes、cornerRadius、opacity等。value这个参数,要根据 property 的不同给出不同的说明。schema 越清晰,Agent 传错的概率越低。
另外,服务端要做好参数校验。Agent 传了不合法的参数,服务端要返回明确的错误信息,而不是直接崩溃。错误信息里要包含“期望什么”“实际收到什么”,这样 Agent 看到之后能自我修正。
6.3 修改设计稿后没有生效
有时候 Agent 报告修改成功,但 Figma 里看不到变化。这种情况一般是修改的属性不对,或者修改的节点不对。
先确认 nodeId 是否正确。Figma 的节点 ID 在会话之间可能会变化,如果 Agent 用的是之前缓存的 ID,可能已经失效了。解决办法是每次操作前重新获取节点信息,不要依赖缓存。
再确认属性名是否正确。Figma 的插件 API 里,不同节点类型支持的属性不一样。比如矩形有 cornerRadius,但文本节点没有。修改一个不存在的属性,不会报错,但也不会有任何效果。这种情况需要在插件端做类型检查,不支持的属性直接返回错误。
6.4 性能问题:图层多的时候很慢
如果设计稿很复杂,图层数量上千,序列化整个图层树会很慢,Agent 调用一次可能要等好几秒。
优化的思路是按需获取。不要一次性序列化整个文档,而是只序列化 Agent 需要的部分。比如 Agent 要查某个名称的图层,就只返回匹配的图层及其子树,而不是整个页面。
另一个思路是缓存。对于不常变化的图层,可以缓存序列化结果,下次直接返回缓存。但要注意缓存的失效策略,图层被修改后缓存要更新。
6.5 常见问题速查表
| 问题现象 | 可能原因 | 排查方向 |
|---|---|---|
| 插件显示未连接 | 服务未启动、端口不一致、防火墙拦截 | 检查服务进程、端口配置、安全软件 |
| Agent 报参数错误 | schema 不清晰、参数校验缺失 | 完善 schema 定义、增加服务端校验 |
| 修改不生效 | nodeId 失效、属性名错误、节点类型不支持 | 重新获取节点、核对属性名、做类型检查 |
| 响应很慢 | 图层过多、序列化全量数据 | 按需获取、增加缓存 |
| 服务启动报错 | 端口被占用、依赖未安装 | 换端口、重新安装依赖 |
提示:调试的时候,建议在服务端和插件端都加上详细的日志。服务端打印收到的请求和发出的响应,插件端打印执行的方法和结果。出问题的时候,看日志比猜要快得多。
7. 我踩过的坑和几条实用经验
7.1 关于序列化的粒度
一开始我做序列化的时候,是把整个图层树全量转成 JSON。结果发现对于复杂的设计稿,这个 JSON 能有好几兆,Agent 处理起来很吃力,而且大部分数据它根本用不上。
后来我改成按需序列化。Agent 要什么就给什么,不要的不给。比如 Agent 只关心填充色和圆角,那就只返回这两个属性,位置尺寸这些先不返回。这样数据量小了很多,Agent 处理起来也快。
这个经验的核心是:不要假设 Agent 需要所有数据。Agent 的能力有限,给它太多信息反而会干扰它的判断。精准地提供它需要的信息,效果更好。
7.2 关于错误处理
插件端和服务端的错误处理要分开做。插件端的错误主要是 Figma API 调用失败,比如节点不存在、属性不支持。服务端的错误主要是通信失败,比如插件未连接、请求超时。
两边的错误信息要能串起来。插件端报的错,要能通过响应传回服务端,服务端再传给 Agent。Agent 看到错误信息后,要能理解发生了什么,并决定下一步怎么做。
我一开始没做好这个链路,插件端报错后直接吞掉了,Agent 那边只看到超时,完全不知道发生了什么。后来把错误信息透传之后,调试效率高了很多。
7.3 关于工具的命名
工具的命名要直观。Agent 是根据工具名和描述来决定调用哪个工具的,名字起得含糊,Agent 就容易调错。
比如“获取节点”和“获取选中节点”,这两个名字很像,但语义完全不同。前者需要传节点 ID,后者不需要。如果名字起得不够区分,Agent 可能会搞混。我的做法是名字里带上关键信息,比如get_selection、get_node_by_name、get_node_by_id,一看就知道区别在哪。
7.4 关于超时设置
WebSocket 通信要设超时。不设的话,如果插件那边卡住了,服务端会一直等,Agent 也会一直等,整个链路就挂住了。
超时时间设多少合适?我试过 5 秒、10 秒、30 秒。最后定在 10 秒。太短了,复杂操作可能没执行完就超时了;太长了,出问题的时候等太久。10 秒是个比较平衡的值。当然这个可以根据实际情况调,如果你的设计稿特别复杂,可以适当延长。
7.5 关于版本兼容
Figma 的插件 API 会更新,MCP 的 SDK 也会更新。版本不匹配的时候,可能会出现一些奇怪的问题。
我的建议是锁定版本。在package.json里把依赖的版本写死,不要用^或者~。这样即使上游更新了,你的环境还是稳定的。等确认新版本没问题了,再手动升级。
另外,Figma 插件的manifest.json里要声明正确的 API 版本。版本声明不对,插件可能加载不了,或者某些 API 调不了。
7.6 一个提效的小技巧
如果你经常需要让 Agent 读取设计稿,可以在 Figma 里建一个专门的“Agent 工作区”页面。把需要 Agent 处理的图层都放在这个页面里,Agent 操作的时候只在这个页面里找,不用遍历整个文档。这样既快又不容易误操作到其他页面的内容。
这个技巧是我在实际使用中摸索出来的。一开始 Agent 在全文档里找图层,经常找到一些不相关的同名图层,改错了地方。后来建了独立的工作区,这个问题就没了。
8. 这个方案还能怎么扩展
8.1 支持更多的 Figma 特性
目前这个方案主要覆盖了基础的图层读取和样式修改。Figma 还有很多特性可以接进来,比如组件变体、样式引用、自动布局的约束、原型交互等。
组件变体这块特别有价值。设计系统里一个按钮可能有多种变体,Agent 如果能读取变体信息,生成代码的时候就能对应生成组件的 props。样式引用也类似,Agent 读取到的是样式名称而不是具体的色值,生成的代码就能用设计令牌而不是硬编码。
8.2 双向同步
现在的方案主要是 Agent 读取设计稿、修改设计稿。反过来,代码的改动能不能同步回设计稿?这个方向也值得探索。
比如你在代码里改了一个组件的圆角,能不能让 Agent 把这个改动同步到 Figma 的设计稿里?技术上可行,但需要解决冲突检测的问题——如果设计稿也被别人改了,以谁为准?这个需要一套合并策略。
8.3 多文档支持
目前方案是操作当前打开的文档。如果团队有多个设计稿文件,能不能让 Agent 跨文档操作?比如从 A 文档读取组件样式,应用到 B 文档。
这个需要插件支持打开多个文档,或者服务端维护多个插件的连接。技术上不难,但要注意文档之间的 ID 冲突问题。不同文档里的节点 ID 可能重复,需要加上文档标识来区分。
8.4 与 CI 流程集成
对于设计系统团队来说,可以把这套东西集成到 CI 流程里。每次设计稿更新后,自动触发一次检查,对比设计稿和代码库,生成差异报告。如果发现不一致,自动创建任务或者通知相关人员。
这个场景需要服务能无人值守运行,插件能自动连接。目前插件需要手动启动,如果要集成到 CI,得想办法让插件自动化。Figma 有提供一些自动化的入口,可以研究一下。
8.5 工具集的持续打磨
最后一点,工具集不是一次设计好就完事的。实际用起来之后,你会发现 Agent 经常需要某些组合操作,这时候就可以把这些组合封装成新的工具。
比如 Agent 经常需要“找到某个名称的图层并修改它的某个属性”,这个操作可以封装成一个工具,Agent 调用一次就完成,不用先查再改。工具越贴合实际使用场景,Agent 用起来越顺手。
我个人的体会是,这套方案的价值不在于技术有多复杂,而在于它把设计稿和 Agent 之间的那道墙给拆了。拆完之后,很多之前需要手动做的事情,现在可以交给 Agent 自动完成。当然,它也不是万能的,复杂的布局逻辑、交互逻辑还是需要人来判断。但至少那些重复性的、机械性的信息搬运工作,可以省下来了。如果你也在用 Agent 辅助开发,又经常跟 Figma 打交道,不妨花个下午把这套东西搭起来试试,用起来之后你会发现回不去了。