使用说明
figma-pilot-mcp
Read and edit Figma designs through MCP and a local plugin.
Figma Pilot connects your AI agent to the open document in Figma Desktop through a local WebSocket relay.
Agent: "Read the Card component and build a matching Modal."
→ pilot_get_selection inspect what's selected
→ pilot_create_node_tree build the new frame in one call
→ pilot_set_auto_layout match the spacing
Five design stages exported during a live MCP session in Figma Desktop: create a canvas, chain commands, add text, apply auto layout, and refine colors and copy.
Features
- Full read-write access — 97 tools covering nodes, styles, variables, components, prototypes, and export
- Bidirectional — read a design to generate code, or generate a design from a prompt
- Batch operations — chain commands with result references (
$0.id) in one round trip - Flexible deployment — all-in-one, or split MCP and WebSocket for multi-agent setups
How It Works
The MCP server uses stdio to talk to your agent and WebSocket to reach the plugin's UI iframe. The plugin main thread reads and edits the document:
graph LR
A[AI Agent] <--stdio--> B[MCP Server]
B <--ws--> C[Figma Plugin]
C <--> D[Figma Document]
The plugin joins a channel shown in its UI; the MCP server connects to that same channel. The name uses the file key when available, otherwise the document name. Copy the displayed value to avoid connecting to a different document.
Prerequisites
- Bun 1.0+ — the server uses
Bun.serve; development is verified with the version inpackageManager. - Figma Desktop — import and run the development plugin here.
Getting Started
Clone or download this repository, then run commands from its root.
-
Install dependencies and build the plugin:
bun install bun run build -
Import the plugin into Figma Desktop:
- Plugins → Development → Import plugin from manifest...
- Select the
dist/plugin/manifest.jsonin this project folder
-
Configure your AI agent (see below)
-
Run the plugin and connect:
- Open a design file in Design mode, run Plugins → Development → Figma Pilot
- The plugin UI shows a channel name (e.g.,
figma-pilot-abc123) - In your AI agent, use
pilot_connectwith the channel name
Verify the setup at any time with bunx --package figma-pilot-mcp figma-pilot doctor.
Usage
Once connected, drive it in plain language — the agent picks the tools. A few things it handles well:
Design to code — read what exists, then generate from it:
"Read the selected frame and write a React component that matches it."
Code to design — build new UI from a description:
"Create a 320×180 card with a title, divider, and body text, using auto layout with 12px spacing."
Bulk edits — most modification tools accept an array of node IDs:
"Find every frame named
Button/*and set its corner radius to 8."
Chaining commands
pilot_batch runs commands in sequence and lets later steps reference earlier results with $N:
{
"commands": [
{
"command": "create_frame",
"params": { "name": "Card", "width": 300, "height": 200 },
},
{
"command": "create_text",
"params": { "parentId": "$0.id", "characters": "Title" },
},
{
"command": "set_auto_layout",
"params": { "nodeId": "$0.id", "mode": "VERTICAL" },
},
],
}
$0.id resolves to the id field of the first command's result. Dot paths may also index arrays: $0.children.0.id.
A reference must be the entire value. "prefix-$0.id" is left as a literal string, and "$0.id-suffix" is an error — the trailing text is read as part of the property name.
The batch stops on the first error by default. Set stopOnError: false to continue with later commands; failed entries occupy a null slot in results, so references keep their original indexes. Any failure sets isError: true and appears in errors, including reference resolution failures. executed counts processed entries, including failures.
Trimming responses
Read tools accept a fields array to cut response size — useful when a node has more properties than you need:
{ "nodeId": "1:23", "fields": ["id", "name", "width", "height"] }
Configure Your AI Agent
Mode 1: All-in-one (recommended)
graph LR
A[AI Agent] <--stdio--> B[MCP + WS Server] <--ws--> C[Figma Plugin]
{
"mcpServers": {
"figma-pilot": {
"command": "bunx",
"args": ["--package", "figma-pilot-mcp", "figma-pilot", "start"],
},
},
}
Mode 2: Separate WS + MCP (multi-agent)
graph LR
A[AI Agent A] <--stdio--> C[MCP only]
B[AI Agent B] <--stdio--> D[MCP only]
C <--ws--> E[WS Server]
D <--ws--> E
E <--ws--> F[Figma Plugin]
-
Start the WebSocket server:
bunx --package figma-pilot-mcp figma-pilot start --mode=ws -
Configure AI agents:
{ "mcpServers": { "figma-pilot": { "command": "bunx", "args": [ "--package", "figma-pilot-mcp", "figma-pilot", "start", "--mode=mcp", ], }, }, }
Reference
Mode Summary
| Mode | CLI | MCP | WS Server | WS Client | Use Case |
|---|---|---|---|---|---|
all |
--mode=all |
Yes | Yes | No | Single-agent |
mcp |
--mode=mcp |
Yes | No | Yes | Multi-agent / remote WS |
ws |
--mode=ws |
No | Yes | No | Standalone relay |
CLI Commands
| Command | Description |
|---|---|
bunx --package figma-pilot-mcp figma-pilot init |
Install dependencies and build the plugin |
bunx --package figma-pilot-mcp figma-pilot build |
Rebuild the Figma plugin |
bunx --package figma-pilot-mcp figma-pilot start |
Start the server (default: all-in-one mode) |
bunx --package figma-pilot-mcp figma-pilot doctor |
Run diagnostics checks |
Configuration
| Variable | Default | Description |
|---|---|---|
FIGMA_WS_PORT |
3846 |
WebSocket port |
FIGMA_WS_HOST |
localhost |
WebSocket host |
FIGMA_REQUEST_TIMEOUT |
30000 |
Request timeout (ms) |
FIGMA_PILOT_MODE |
read-write |
Tool mode: read-write / write-only (omits read tools) |
FIGMA_RUN_MODE |
all |
Run mode: all / mcp / ws |
Troubleshooting
Start with bunx --package figma-pilot-mcp figma-pilot doctor — it checks the runtime, the plugin build, and port availability.
| Symptom | Cause and fix |
|---|---|
Not connected to Figma. Use pilot_connect first. |
The server is running but no channel is joined. Run the plugin and call pilot_connect with its channel name. |
No Figma plugin connected to this channel. |
The plugin is disconnected or the channel name does not match. Connect the plugin and copy the current channel from its UI. |
Port 3846 is already in use. |
Another instance is running, or a previous one did not exit. Stop it, or set FIGMA_WS_PORT. |
Figma plugin disconnected. |
The plugin was closed or Figma crashed mid-command. Re-open the plugin and reconnect. |
| Agent has no read tools | FIGMA_PILOT_MODE is set to write-only. Unset it, or set it to read-write. |
| Plugin missing in Figma | Import dist/plugin/manifest.json, not the copy under src/. Run bunx --package figma-pilot-mcp figma-pilot build if dist/ is absent. |
figma-pilot requires the Bun runtime |
You ran it under Node.js. Install Bun and use bunx --package figma-pilot-mcp figma-pilot, not npx. |
| Commands time out after 30s | The document may be very large. Raise FIGMA_REQUEST_TIMEOUT, or narrow the operation to fewer nodes. |
Available Tools
Connection
| Tool | Description |
|---|---|
pilot_connect |
Connect to Figma plugin via WebSocket. Required before other operations. |
pilot_disconnect |
Disconnect from Figma plugin. |
pilot_status |
Get WebSocket connection status. |
Creation
| Tool | Description |
|---|---|
pilot_create_shape |
Create shape: frame/rect/ellipse/polygon/star/line/vector |
pilot_create_text |
Create a text layer with content, font, and size |
pilot_create_component |
Create a new empty component |
pilot_create_component_from_node |
Convert an existing node into a reusable component |
pilot_create_instance |
Create / place an instance of a component |
pilot_create_page |
Create a new page in the document |
pilot_create_section |
Create a section container |
pilot_create_slice |
Create export slice |
pilot_create_from_svg |
Import / create a node from an SVG string |
pilot_create_image |
Create image from base64 or URL |
pilot_create_table |
Create table (FigJam) |
pilot_create_sticky |
Create FigJam sticky note |
pilot_create_connector |
Create FigJam connector between nodes |
pilot_create_shape_with_text |
Create FigJam shape with text |
pilot_create_node_tree |
Create nested node tree in one call |
Text
| Tool | Description |
|---|---|
pilot_set_text |
Edit text: content, font family/size/weight, color, line height, letter spacing, alignment, case, and decoration [BATCH] |
Modification
| Tool | Description |
|---|---|
pilot_set_fill |
Set fill / background color of a node: solid color or gradient [BATCH] |
pilot_set_stroke |
Set stroke / border color and weight: solid color or gradient [BATCH] |
pilot_set_corners |
Set corner radius / rounded corners (uniform or per-corner) [BATCH] |
pilot_move_node |
Move node to position |
pilot_resize_node |
Resize node [BATCH] |
pilot_set_rotation |
Rotate a node (degrees) [BATCH] |
pilot_set_opacity |
Set opacity / transparency (0-1) [BATCH] |
pilot_set_blend_mode |
Set blend mode (multiply, overlay, screen, etc.) [BATCH] |
pilot_set_visible |
Show or hide a node (visibility) [BATCH] |
pilot_set_locked |
Lock or unlock a node against editing [BATCH] |
pilot_set_name |
Rename a node (set layer name) |
pilot_set_effect |
Add drop shadow or blur effect, or clear all effects [BATCH] |
pilot_set_auto_layout |
Set auto layout on a frame: direction, spacing, padding, alignment [BATCH] |
pilot_set_constraints |
Set resize constraints / pinning relative to parent [BATCH] |
pilot_delete_node |
Delete / remove a node from the document [BATCH] |
pilot_clone_node |
Clone / duplicate a node |
pilot_group_nodes |
Group multiple nodes into a group |
pilot_ungroup_node |
Ungroup a group, releasing its children |
pilot_flatten_nodes |
Flatten to single vector |
pilot_boolean |
Boolean operation on nodes |
pilot_set_current_page |
Set current page |
pilot_set_viewport |
Set viewport center/zoom |
pilot_scroll_to_node |
Scroll and zoom the viewport to show a node |
pilot_set_selection |
Select nodes on the canvas (set current selection) |
pilot_notify |
Show notification |
pilot_set_image_fill |
Set image fill on node (by hash, base64, or URL) |
pilot_set_image_filters |
Set filters on existing IMAGE fill [BATCH] |
Layout
| Tool | Description |
|---|---|
pilot_set_layout_child |
Set auto layout child behavior: fill/hug sizing, min/max size, align, or absolute positioning. One group per call [BATCH] |
pilot_set_layout_wrap |
Set layout wrap mode |
pilot_set_clips_content |
Set frame clips content [BATCH] |
pilot_set_overflow |
Set overflow direction [BATCH] |
pilot_set_guides |
Set guides on frame/page |
Node Hierarchy
| Tool | Description |
|---|---|
pilot_move_child |
Append/insert/reorder child in parent |
Instance Operations
| Tool | Description |
|---|---|
pilot_detach_instance |
Detach instance from component |
pilot_reset_overrides |
Reset instance overrides |
pilot_swap_component |
Swap instance to different component |
Styles
| Tool | Description |
|---|---|
pilot_create_style |
Create paint/text/effect/grid style |
pilot_apply_style |
Apply style to node |
pilot_move_style |
Reorder style in list |
Variables & Properties
| Tool | Description |
|---|---|
pilot_create_variable_collection |
Create variable collection |
pilot_create_variable |
Create variable |
pilot_set_variable_value |
Set variable value for mode |
pilot_create_variable_alias |
Create variable alias |
pilot_bind_variable |
Bind variable to property/paint/effect/grid |
pilot_set_component_properties |
Set instance properties |
Team Library
| Tool | Description |
|---|---|
pilot_import_library |
Import component/style/variable from library |
pilot_import_style_by_key |
Import style by key |
pilot_import_variable_by_key |
Import variable by key |
Export & Prototype
| Tool | Description |
|---|---|
pilot_set_export_settings |
Set export settings |
pilot_set_reactions |
Set prototype reactions |
Reading
| Tool | Description |
|---|---|
pilot_get_node |
Read a node: geometry, styles, fills, text, and layout properties |
pilot_get_selection |
Get the nodes currently selected on the canvas |
pilot_find_nodes |
Search / find nodes by type or name pattern (supports wildcards) |
pilot_get_children |
List direct children of a node (traverse the layer tree) |
pilot_get_top_frame |
Get top-level frame containing node |
pilot_get_current_page |
Get current page info |
pilot_get_pages |
List all pages in the document |
pilot_get_local_styles |
List local paint, text, effect, and grid styles |
pilot_get_local_components |
List local components in the file |
pilot_get_local_variables |
Get local variables |
pilot_get_variable_collections |
Get variable collections |
pilot_get_viewport |
Get viewport center and zoom level |
pilot_export_node |
Export / render a node as a PNG, JPG, SVG, or PDF image |
pilot_get_component_properties |
Get component/instance properties |
pilot_get_export_settings |
Get export settings of node |
pilot_get_reactions |
Get prototype reactions of node |
pilot_get_library_variable_collections |
Get library variable collections |
pilot_get_library_variables |
Get library variables by collection |
pilot_get_component_set_variants |
Get variants of library component set |
pilot_get_image |
Get image info/bytes by hash |
pilot_list_available_fonts |
List available font families and styles (searchable) |
pilot_get_selection_colors |
Get all colors used in the current selection |
pilot_parse_color |
Parse color string to RGB/RGBA |
pilot_get_event_subscriptions |
Get event subscription status |
Events & Utilities
| Tool | Description |
|---|---|
pilot_event |
Subscribe/unsubscribe to events |
pilot_create_solid_paint |
Create solid paint object |
pilot_combine_as_variants |
Combine components as variants |
Batch
| Tool | Description |
|---|---|
pilot_batch |
Execute multiple commands in sequence. Use $N to reference previous result (e.g., $0.id). |
Development
bun install --frozen-lockfile
bun run check
bun run build
check runs TypeScript checks for the server and plugin, Biome, and tests.
The TypeScript dependency uses npm:@typescript/typescript6@^6.0.2, and checks invoke tsc6 to stay on TypeScript 6.
The build uses the installed esbuild dependency and writes dist/plugin; reload the development plugin after rebuilding.
Use bun run dev for the server, or bun run dev:ws and bun run dev:mcp for separate relay and MCP processes.
The plugin implementation notes describe the message flow, API helpers, and how to add a tool.
The manifest currently enables the Figma editor; FigJam commands require an appropriate editor configuration.
License
MIT