@dankinsoid/claude-talk-to-figma-mcp
v0.3.20
Published
Claude Talk to Figma MCP
Readme
Talk to Figma MCP
A Model Context Protocol (MCP) integration between an AI agent (Claude Code and other MCP clients) and Figma, letting the agent read and modify designs programmatically.
https://github.com/user-attachments/assets/129a14d2-ed73-470f-9a4c-2240b2a4885c
Based on grab/cursor-talk-to-figma-mcp
This is a fork of grab/cursor-talk-to-figma-mcp (itself based on the original by sonnylazuardi). It has diverged substantially. The upstream worked, but in practice it was slow, expensive, and limited:
- it fed the model near-complete node JSON for every read — thousands of tokens per node, with full geometry, paints and styles the agent rarely needed;
- search was rigid — a couple of fixed scans (by type, by text node) that returned heavy results; anything beyond them meant dumping a whole subtree and scanning it by eye;
- editing was limited to a handful of single-purpose setters.
This fork reworks the agent's interface around how an AI agent already works with a codebase — locate cheaply, read narrowly, edit surgically.
What's different:
- Compact, zoomable hierarchy. Reads return a minimal field set per node (id, name, type, color, box/auto-layout, text) instead of raw JSON, with a depth cap, drill-in stubs, and collapsing of icons and repeated component instances. A screen that was tens of thousands of tokens is now around ~5k.
- Powerful, flexible search, code-agent style. In place of the old fixed scans, three composable tools:
glob_nodes(thels -R/glob, filter by type and name pattern),grep_nodes(regex over text content, thegrep), andquery_nodes(arbitrary predicates over node fields — fontSize, fills color, bound variables, key presence). They return flat, line-orientedid:"name".TYPEhits — addresses you feed straight into read/edit, without ever dumping the tree. - A
Read→Edit→Writemodel.read_node,edit_nodes(one path-addressed property writer that replaced ~10 single-purpose setters), andwrite_nodes(create whole subtrees from JSON) mirror the file tools the agent is already trained on. - Short node ids. Long nested instance paths (
I8782:344721;3063:34762;…) are replaced with short counters (n0,n1, …) in all compact output, resolved back server-side. Cuts tokens and keeps the tree readable; every tool accepts short or canonical ids. - Bug fixes. Notably, the original could corrupt text colors: the reaction-highlight animation didn't always restore the original fill. Fixed.
- Small UX touches. The plugin's channel window collapses to a compact widget so it stays out of the way, and the agent can discover the active channel automatically (
get_active_channel) instead of you pasting it.
Project Structure
src/talk_to_figma_mcp/- TypeScript MCP server for Figma integrationsrc/claude_mcp_plugin/- Figma plugin for communicating with the agentsrc/socket.ts- WebSocket server that relays messages between the MCP server and the Figma plugin
How to use
- Install Bun if you haven't already:
curl -fsSL https://bun.sh/install | bash- Run setup — this also installs the MCP config in your active project (
.cursor/mcp.jsonand.mcp.json):
bun setupInstall the Figma plugin — see Figma Plugin below. (Install locally: this fork ships a modified plugin, so the upstream community listing won't include the changes above.)
Run the plugin in Figma and press Connect — that's it. The WebSocket relay is hosted by the MCP server automatically when your agent starts it, so there's no terminal command to run.
Running the relay manually with
bun socketis still supported (e.g. to share one relay across machines), but it's optional — the embedded relay binds port 3055 on first use and any extra agent orbun socketinstance just connects to it.
Manual Setup and Installation
MCP Server
Add the server to your MCP config (~/.cursor/mcp.json for Cursor, .mcp.json for Claude Code):
{
"mcpServers": {
"TalkToFigma": {
"command": "bunx",
"args": ["@dankinsoid/claude-talk-to-figma-mcp@latest"]
}
}
}Or via the Claude Code CLI:
claude mcp add TalkToFigma -- bunx @dankinsoid/claude-talk-to-figma-mcp@latestWebSocket Server (optional)
The MCP server hosts the relay in-process, so you normally don't need this. Run it standalone only if you want a relay that outlives any single agent (e.g. shared across machines):
bun socketFigma Plugin
- In Figma, go to Plugins > Development > New Plugin
- Choose "Link existing plugin"
- Select
src/claude_mcp_plugin/manifest.json - The plugin is now available under your Figma development plugins
Windows + WSL Guide
- Install bun via PowerShell:
powershell -c "irm bun.sh/install.ps1|iex"- Uncomment the hostname
0.0.0.0insrc/socket.ts:
// uncomment this to allow connections in windows wsl
hostname: "0.0.0.0",- Start the websocket:
bun socketMCP Tools
The agent's workflow mirrors editing a codebase: search to locate nodes cheaply, read only what you need, then edit/write. Node ids are short counters (n0, n1, …) that flow between every tool; canonical Figma ids are accepted too.
Read
read_node— theReadtool for the canvas. PassnodeIds(one or many), or omit to read the current selection. Returns the compact, low-token subtree of each node;depthcontrols how far children expand and deeper nodes become drill-in stubs.raw:truereturns the full unfiltered JSON of a single node (all props, children stripped).
Search (locate before reading)
glob_nodes— flat type/name-glob index of a subtree, one node per line asid:"name".TYPE @parent [x,y wxh](thels -R/glob analog). Filter bytypeand a shell-stylenameglob; scope withroot/depth/within.grep_nodes— regex search over the text content of a subtree, line-oriented (thegrepanalog):id:"name".TEXT @parent L<n>: <line>.modeswitches between content / nodes / count.query_nodes— structural search by field predicates ({path, op, value}, AND-combined). Match any node-model field (fontSize, fills color, bound variables, …), including key presence viaexists/absent— e.g. find fills not bound to a variable for a design-system audit.
Edit & Create
edit_nodes— theEdittool for the node model. Passedits: [{nodeId, path, old?, new}].pathaddresses one field (name,characters,x,fills[0].color,cornerRadius,layoutMode,paddingTop,itemSpacing, …);newis the value (#RRGGBB→ Figma rgb; objects/arrays allowed); optionaloldis a guard that rejects only a stale edit. Edits are independent and one call can touch many nodes — this is also how you bulk-replace text (one{path:"characters"}per node). Replaced the former single-purpose setters (move_node,resize_node,set_text_content,set_padding,set_layout_mode, …).write_nodes— theWritetool. Create new nodes from{type, ...props, children?}specs;childrenbuilds a whole subtree in one call. Placement viaparentId/index.INSTANCEneedscomponentId/componentKey.get_write_schema— the write-side schema for a node type: the fieldswrite_nodesaccepts when creating it (with notype, lists the creatable types). Call it before building a node.delete_nodes— delete one or more nodes (chunked with progress for large batches).clone_node— copy an existing node with an optional position offset.
Selection & Channel
get_selection- the current selectionset_selections/set_focus- select nodes (and scroll the viewport to them)get_active_channel- the channel the plugin currently has open (so the agent can join without you pasting it)join_channel- join a channel to communicate with the plugin
Components & Styles
get_styles- local stylesget_local_components- local componentsget_instance_overrides/set_instance_overrides- extract overrides from one instance and apply them to others
Annotations
get_annotations- all annotations in the document or a nodeset_annotations- create/update one or more native annotations (markdown, batched)
Prototyping & Connections
get_reactions- prototype reactions from nodesset_default_connector- set a copied FigJam connector as the default style (required before creating connections)create_connections- FigJam connector lines between nodes
Export
export_node_as_image- export a node (PNG, JPG, SVG, PDF)
MCP Prompts
Helper prompts that guide the agent through common tasks:
read_design_strategy- the explore→modify ladder (glob/grep/query → read_node → edit_nodes)design_strategy- best practices for creating designstext_replacement_strategy- locating and bulk-replacing text, with chunked visual verificationannotation_conversion_strategy- converting manual annotations to native Figma annotationsswap_overrides_instances- transferring overrides between component instancesreaction_to_connector_strategy- turning prototype reactions into connector lines
Best Practices
- Join a channel before sending commands (
get_active_channel→join_channel). - Locate before reading. Start with
glob_nodes(e.g.{type:["SECTION","FRAME"]}for a screen map),grep_nodes, orquery_nodesto get ids — don't dump a whole subtree to find something. - Read narrowly.
read_nodeonly the ids you'll act on; raisedepthor re-request a stub id to zoom. Width of search is cheap (ids only); depth of detail is not. - Edit surgically. Use
edit_nodeswitholdas a guard against stale reads; batch many nodes in one call. Create subtrees withwrite_nodes. - For large designs: narrow with
root/depth/withinand cap withmaxMatcheson the search tools; verify changes with targetedexport_node_as_image. - Prefer component instances for consistency; all commands can throw, so handle errors.
Development
bun install # install dependencies
bun run build # build the MCP server (tsup → dist/)
bun run dev # build in watch modeTo run the server from your local checkout, point the MCP config at it:
{
"mcpServers": {
"TalkToFigma": {
"command": "bun",
"args": ["/path-to-repo/src/talk_to_figma_mcp/server.ts"]
}
}
}The Figma plugin is not bundled — edit src/claude_mcp_plugin/code.js and ui.html directly.
Credits
- Upstream: grab/cursor-talk-to-figma-mcp; original by sonnylazuardi.
- Bulk text replacement and instance-override propagation features by @dusskapark (text demo, overrides demo).
License
MIT
