@refore-ai/talk-to-design-mcp
v0.1.0
Published
Let an AI agent work directly on the design file you have open: find and read nodes, inspect styles, export images — and change properties, edit text, and create, move, group or delete nodes.
Readme
Refore Talk to Design MCP
Let an AI agent work directly on the design file you have open: find and read nodes, inspect styles, export images — and change properties, edit text, and create, move, group or delete nodes.
Works with the Refore Talk to Design plugin on Figma, MasterGo, JSDesign and Pixso.
Requirements
- Node.js 18+
- One of Figma / MasterGo / JSDesign / Pixso, with the Talk to Design plugin installed
Setup
One package covers every platform — the platform is a runtime argument:
claude mcp add refore-talk-to-figma -- npx -y @refore-ai/talk-to-design-mcp --platform figma--platform accepts figma, mastergo, jsdesign, pixso-china, pixso-world. The server name
(refore-talk-to-figma above) is just a local alias — give each platform its own so you can tell them
apart when several are configured at once.
It is required: each platform gets its own port range, so a missing value would silently connect
to the wrong one, which shows up as "the plugin is clearly running but nothing connects" — much
harder to diagnose than an error at startup.
Claude Desktop — add to claude_desktop_config.json, then restart the app:
{
"mcpServers": {
"refore-talk-to-figma": {
"command": "npx",
"args": ["-y", "@refore-ai/talk-to-design-mcp", "--platform", "figma"]
}
}
}Codex — add to ~/.codex/config.toml:
[mcp_servers.refore-talk-to-figma]
command = "npx"
args = ["-y", "@refore-ai/talk-to-design-mcp", "--platform", "figma"]Cursor / Windsurf / others — use the same command / args as the Claude Desktop JSON above.
Then open the Talk to Design plugin in your design tool. It scans for local MCP processes and connects on its own.
Tools
Three groups, all enabled, plus one tool that is always available:
| Tool | Purpose |
| ------------ | -------------------------------------------------------------------------------- |
| get_status | This process's port, the platform it serves, and whether the plugin is connected |
read
| Tool | Purpose |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| get_design_context | Which file is open, what pages it has, which page is current |
| get_selection | What the user has selected right now — this is what "look at this" refers to |
| query_nodes | Find nodes by name / type; with only root it lists that node's direct children |
| get_nodes | Read nodes by id; props returns any platform-native property verbatim |
| get_local_styles | The file's local paint / text / effect styles |
| get_available_fonts | Fonts available in the design tool, grouped by family |
| get_variables | Variable collections and their per-mode values (Figma and Pixso only) |
| export_node_image | Render a node as PNG or SVG; size via the platform's native constraint; saveTo writes it to a file and returns only the path |
navigate — changes the view, never the file
| Tool | Purpose |
| ------------------ | ------------------------------------------------- |
| select_nodes | Sets the selection without moving the viewport |
| scroll_into_view | Moves the viewport without changing the selection |
| set_current_page | Switches to another page |
The first two are separate on purpose: "select it but don't jump my view" and "show me but don't touch my selection" are both real requests, and a combined tool can only do both at once.
write — changes the real document, and this MCP has no undo
| Tool | Purpose |
| --------------------- | -------------------------------------------------------------- |
| set_node_properties | Set properties using platform-native names |
| set_text_style | Text styling (size, weight, colour…), optionally over a range |
| set_node_style_id | Bind a node to a style from get_local_styles |
| create_node | Create a node |
| duplicate_nodes | Duplicate nodes in place |
| reparent_nodes | Move nodes under another parent, keeping their canvas position |
| group_nodes | Group nodes |
| ungroup_node | Ungroup, moving children up to the parent |
| delete_nodes | Delete nodes |
Text styling always goes through set_text_style — do not set fontSize / fontName and friends
via set_node_properties. Those are per-character-range on all four platforms, so plain assignment
behaves inconsistently.
Platform-native properties
get_nodes's props and set_node_properties both use the platform's own property names, with
no translation. The same card's auto-layout is layoutMode on Figma and flexMode on MasterGo:
read a name, write that same name back. For what each property means, the tool descriptions link to
the plugin API docs for whichever --platform you started with.
Two things that are easy to get wrong:
- Coordinates use different frames of reference.
boundsin read results is absolute canvas position, whilex/yyou write are relative to the parent. Passing a value straight back fromboundswill move the node. - Reading a property does not guarantee you can write it. Text properties in particular live on
character ranges rather than on the node — on MasterGo a TEXT node has no
fontSizeat all.
Development
--dev adds get_tail_logs, which reads the plugin's own log buffer. It only works when the
connected plugin is a development build, and it is outside the read-only guarantees of the other
tools — log lines can contain arbitrary internal state.
