Figma MCP Bridge

Read and edit open Figma and FigJam files through a desktop plugin instead of the Figma REST API

By Hopp - Remote Pair Programming Tool TypeScript Local · stdio Design

60 popularity score ★ 889 ↓ 1.3k/wk

Connect your client

Local (npm)

Add in one click

Opens the app, which asks before it adds the server.

Or add it by command or config

Claude CodeTerminal
claude mcp add figma-bridge -- npx -y @gethopp/figma-mcp-bridge
Claude Desktopclaude_desktop_config.json
{
  "mcpServers": {
    "figma-bridge": {
      "command": "npx",
      "args": [
        "-y",
        "@gethopp/figma-mcp-bridge"
      ]
    }
  }
}
Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "figma-bridge": {
      "command": "npx",
      "args": [
        "-y",
        "@gethopp/figma-mcp-bridge"
      ]
    }
  }
}
VS Code.vscode/mcp.json
{
  "servers": {
    "figma-bridge": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y",
        "@gethopp/figma-mcp-bridge"
      ]
    }
  }
}
Codex~/.codex/config.toml
[mcp_servers.figma-bridge]
command = "npx"
args = ["-y", "@gethopp/figma-mcp-bridge"]
Gemini CLITerminal
gemini mcp add --scope user figma-bridge npx -- -y @gethopp/figma-mcp-bridge
Local (from source)

Add in one click

Opens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.

Or add it by command or config

FirstTerminal
git clone https://github.com/gethopp/figma-mcp-bridge.git
cd figma-mcp-bridge/server && bun install && bun run build
Claude CodeTerminal
claude mcp add figma-bridge -- node '<ABSOLUTE_PATH_TO_CLONE>/server/dist/index.js'
Claude Desktopclaude_desktop_config.json
{
  "mcpServers": {
    "figma-bridge": {
      "command": "node",
      "args": [
        "<ABSOLUTE_PATH_TO_CLONE>/server/dist/index.js"
      ]
    }
  }
}
Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "figma-bridge": {
      "command": "node",
      "args": [
        "<ABSOLUTE_PATH_TO_CLONE>/server/dist/index.js"
      ]
    }
  }
}
VS Code.vscode/mcp.json
{
  "servers": {
    "figma-bridge": {
      "type": "stdio",
      "command": "node",
      "args": [
        "<ABSOLUTE_PATH_TO_CLONE>/server/dist/index.js"
      ]
    }
  }
}
Codex~/.codex/config.toml
[mcp_servers.figma-bridge]
command = "node"
args = ["<ABSOLUTE_PATH_TO_CLONE>/server/dist/index.js"]
Gemini CLITerminal
gemini mcp add --scope user figma-bridge node -- '<ABSOLUTE_PATH_TO_CLONE>/server/dist/index.js'

Settings 3

FIGMA_BRIDGE_ENABLE_RUN_SCRIPT Optional: Set to 1 to register run_script. Any other value leaves it off. With several clients running the bridge, set it in each configuration. For run_script.
FIGMA_BRIDGE_HOST Optional: Address the leader listens on: 127.0.0.1, ::1, 0.0.0.0 or ::. Any other value stops the server at start. Use an all-interfaces address only when the plugin runs on another host such as a VM. Default 127.0.0.1.
FIGMA_BRIDGE_PORT Optional: Port for the plugin and for other server instances. The server exits on a value outside 1-65535. The stock plugin expects 1994, so another port needs a plugin built to match. Default 1994.

What it does

Figma MCP Bridge, made by the team behind the Hopp pairing app, has two halves: a development plugin you import into the Figma desktop app, and a local Node.js server your AI client starts over stdio. The plugin opens a WebSocket to the server on localhost port 1994 and answers its requests from the open document, so no Figma API token is used and Figma's REST rate limits (which its makers cite as the reason for the project) do not apply.

The server reads the page tree, the selection, single nodes, styles, variables, prototype flows and exports of nodes as images. It can also edit the file: set text, fills, gradients, effects, strokes and auto-layout, create pages, frames, sections, text, shapes, images, SVG layers, FigJam stickies and connectors, move, group, duplicate and delete nodes, and apply animation presets and keyframes (marked beta). Several files can be connected at once. Each tool takes an optional fileKey, and list_files shows which are connected. When several AI clients run the server at once, one becomes the leader that holds the plugin connections and the others forward their calls to it over HTTP.

Since 0.0.25 there is also run_script, which runs whatever Plugin API JavaScript you hand it inside the open file. It stays off by default. In the code the tool is only registered when FIGMA_BRIDGE_ENABLE_RUN_SCRIPT is exactly "1", so with the setting unset the client never sees it (server/src/tools.ts). With it on, v0.0.25 registers 55 tools. That count includes get_layout_tree, which returns absolute positions and layout bounds under a root node.

What it needs

RuntimeNode.js
Runs onmacOS, Windows
FigmaFreeEdit permission on a file is needed for the write tools; no API token is used
Also
  • Figma desktop app open with the bridge plugin running in each file

Import the plugin from the project's GitHub releases in the desktop app via Plugins > Development > Import plugin from manifest. The browser version of Figma cannot import development plugins. Port 1994 must be free on localhost unless FIGMA_BRIDGE_PORT is set, and a different port also needs a plugin built for it.

Limits

  • Not covered Works only on files open in the desktop app with the plugin running. Nothing is read from Figma's cloud.
  • Read only Write tools return an error in Dev Mode, which the plugin treats as read-only.
  • Not covered In FigJam the auto-layout and animation tools fail and the prototype tools are unavailable.
  • Not covered No component or instance editing, no variable or style authoring, no per-segment text styling and no boolean vector operations, per its makers.
  • Early release The animation tools (motion styles, keyframe tracks, timeline duration) are marked beta.
  • Size cap create_svg takes SVG payloads up to 2 MiB.
  • Size cap create_image fetches URLs with a 32 MiB cap, a 15-second timeout and at most 5 redirects, and refuses private, loopback and link-local addresses (server/src/tools.ts).
  • Not covered create_image refuses local paths outside the server's working directory, even absolute ones, though the README says absolute paths are read as given (server/src/tools.ts).
  • Limit run_script gives up waiting after 3 minutes, but a script caught in a loop keeps the plugin busy until it is closed.

Works only on files open in the desktop app with the plugin running; nothing is read from Figma's cloud. Write tools fail in Dev Mode; auto-layout and animation tools fail in FigJam, and prototype tools are unavailable there. Its makers list no component or instance editing, no variable or style authoring, no per-segment text styling and no boolean vector operations. Animation tools are beta. create_svg takes up to 2 MiB. In the code, create_image refuses local paths outside the server's working directory, even absolute ones, though the README says absolute paths are read as given; image URLs are fetched with a 32 MiB cap, a 15-second timeout and at most 5 redirects (server/src/tools.ts).

Who it suits

Suits designers and developers on Figma's free plan or anyone hitting REST API limits, who keep the desktop app open while they work and want an assistant to inspect or build layouts in the live file, including FigJam boards. It needs no token but does need the plugin running, so it does not fit headless or CI use, the browser version of Figma, or Linux. It is not published by Figma. For reading files through Figma's REST API without the desktop app, its README names Figma-Context-MCP as the existing alternative, at the cost of API rate limits.

Tools 55

14 only read, 39 change things, 2 can delete or overwrite. A ? marks an optional parameter.

list_files
List the Figma and FigJam files whose plugin is connected, with their keys
get_document
Read the node tree of the current pagefileKey?: string
get_selection
Read the nodes currently selected in the filefileKey?: string
get_layout_tree
Read absolute positions and layout bounds under a root noderootId: stringmaxNodes?: integerfileKey?: string
get_node
Read one node by ID, optionally with its prototype interactionsnodeId: stringincludePrototype?: booleanfileKey?: string
get_prototype_connections
Read prototype interactions on a node and its childrennodeId?: stringmaxNodes?: integerincludeEmpty?: booleanfileKey?: string
trace_prototype_flow
Follow prototype navigation from a screen and list the screens reachednodeId: stringmaxScreens?: integermaxNodesPerScreen?: integerfileKey?: string
get_styles
Read the file's local paint, text, effect and grid stylesfileKey?: string
get_metadata
Read the file name, its pages and the current pagefileKey?: string
get_design_context
Read a depth-limited tree of the design for contextdepth?: numberfileKey?: string
get_variable_defs
Read variable collections, modes and values (design tokens)fileKey?: string
get_screenshot
Export nodes as PNG, SVG, JPG or PDF and return them base64-encodednodeIds?: arrayformat?: enumscale?: numberclip?: booleanfileKey?: string
set_node_visibility changes
Show or hide nodesitems: arrayfileKey?: string
set_text_content changes
Replace the text of a text node, sticky or shape labelnodeId: stringtext?: stringcharacters?: stringfileKey?: string
set_text_properties changes
Change font, size, alignment, colour and bounds of textnodeId: stringfontFamily?: stringfontStyle?: stringfontSize?: numbertextAlignHorizontal?: enumtextAlignVertical?: enumtextAutoResize?: enumlineHeightPx?: numberletterSpacingPx?: numberfillHex?: stringfillOpacity?: numberx?: numbery?: numberwidth?: numberheight?: numberfileKey?: string
set_node_properties changes
Change name, position, size, opacity or corner radius of one or many nodesnodeId?: stringnodeIds?: arrayname?: stringx?: numbery?: numberwidth?: numberheight?: numberrotation?: numberopacity?: numbervisible?: booleancornerRadius?: numberfileKey?: string
set_solid_fill changes
Set a node's fill or stroke to one solid colournodeId: stringhex?: stringfillHex?: stringopacity?: numberfillOpacity?: numbertarget?: enumfileKey?: string
set_gradient_fill changes
Set a node's fill or stroke to a gradientnodeId: stringgradientType?: enumgradientStops: arraygradientTransform?: arrayopacity?: numbertarget?: enumfileKey?: string
set_effects changes
Replace a node's shadows and blursnodeId: stringeffects: arrayfileKey?: string
set_stroke_properties changes
Change stroke weight, alignment, dashes, caps and joinsnodeId: stringstrokeWeight?: numberstrokeAlign?: enumdashPattern?: arraystrokeCap?: enumstrokeJoin?: enumfileKey?: string
set_auto_layout changes
Configure auto-layout on a framenodeId: stringlayoutMode?: enumitemSpacing?: numbercounterAxisSpacing?: numberpaddingTop?: numberpaddingRight?: numberpaddingBottom?: numberpaddingLeft?: numberprimaryAxisAlignItems?: enumcounterAxisAlignItems?: enumprimaryAxisSizingMode?: enumcounterAxisSizingMode?: enumlayoutWrap?: enumfileKey?: string
create_page changes
Add a page to the documentname?: stringsetAsCurrent?: booleanfileKey?: string
create_frame changes
Add a frame, optionally inside a parentname?: stringparentId?: stringx?: numbery?: numberwidth?: numberheight?: numberfillHex?: stringfillOpacity?: numberfileKey?: string
create_section changes
Add a section containername?: stringparentId?: stringx?: numbery?: numberwidth?: numberheight?: numberfillHex?: stringfillOpacity?: numbersectionContentsHidden?: booleanfileKey?: string
create_text changes
Add a text nodename?: stringparentId?: stringcharacters?: stringfontFamily?: stringfontStyle?: stringfontSize?: numbertextAlignHorizontal?: enumtextAutoResize?: enumfillHex?: stringfillOpacity?: numberx?: numbery?: numberwidth?: numberheight?: numberfileKey?: string
create_shape changes
Add a rectangle, ellipse or lineshapeType: enumname?: stringparentId?: stringx?: numbery?: numberwidth?: numberheight?: numberrotation?: numbercornerRadius?: numberfillHex?: stringfillOpacity?: numberstrokeHex?: stringstrokeOpacity?: numberstrokeWeight?: numberfileKey?: string
create_shape_with_text changes
Add a FigJam shape that carries its own labelshapeType?: enumname?: stringparentId?: stringcharacters?: stringfontFamily?: stringfontStyle?: stringfontSize?: numberx?: numbery?: numberwidth?: numberheight?: numberrotation?: numberfillHex?: stringfillOpacity?: numberstrokeHex?: stringstrokeOpacity?: numberstrokeWeight?: numbertextFillHex?: stringtextFillOpacity?: numberfileKey?: string
create_image changes
Add a rectangle filled with an image from a file, URL or data URIsource: stringname?: stringparentId?: stringx?: numbery?: numberwidth?: numberheight?: numbercornerRadius?: numberscaleMode?: enumfileKey?: string
create_svg changes
Turn SVG markup or a local SVG file into editable vector layerssource: stringname?: stringparentId?: stringx?: numbery?: numberwidth?: numberheight?: numberfileKey?: string
import_html_layers changes
Import a layer tree exported by html-figma as Figma layerssource: stringname?: stringparentId?: stringx?: numbery?: numberfileKey?: string
create_sticky changes
Add a FigJam sticky notename?: stringparentId?: stringcharacters?: stringx?: numbery?: numberisWideWidth?: booleanfileKey?: string
create_connector changes
Join two FigJam nodes with a connectorname?: stringparentId?: stringstartNodeId?: stringendNodeId?: stringstartX?: numberstartY?: numberendX?: numberendY?: numberstartAnchor?: enumendAnchor?: enumstrokeWeight?: numberstrokeHex?: stringfileKey?: string
duplicate_nodes changes
Copy nodes in placenodeIds: arrayfileKey?: string
duplicate_with_offset changes
Copy nodes and shift each copy by a fixed distancenodeIds: arrayoffsetX: numberoffsetY: numberfileKey?: string
fit_to_content changes
Resize a section to wrap its children with paddingnodeId: stringpadding?: numberfileKey?: string
distribute_horizontally changes
Space three or more nodes evenly acrossnodeIds: arrayfileKey?: string
distribute_vertically changes
Space three or more nodes evenly downnodeIds: arrayfileKey?: string
align_to_grid changes
Snap node positions to a gridnodeIds: arraygridSize: numberfileKey?: string
place_below changes
Move a node under another with a gapnodeId: stringrelativeToId: stringgap?: numberalign?: enumfileKey?: string
place_right_of changes
Move a node to the right of another with a gapnodeId: stringrelativeToId: stringgap?: numberalign?: enumfileKey?: string
reparent_nodes changes
Move nodes into a different parentnodeIds: arrayparentId: stringfileKey?: string
group_nodes changes
Wrap sibling nodes in a new groupnodeIds: arrayparentId?: stringname?: stringfileKey?: string
ungroup_node changes
Dissolve a group or frame into its parentnodeId: stringfileKey?: string
set_selection changes
Select a given list of nodesnodeIds: arrayfileKey?: string
scroll_and_zoom_into_view changes
Move the viewport to show given nodesnodeIds: arrayfileKey?: string
delete_nodes deletes
Delete nodes, only when confirm is set to truenodeIds: arrayconfirm: booleanfileKey?: string
run_script deletes
Run your own Plugin API JavaScript in the open file; registered only when FIGMA_BRIDGE_ENABLE_RUN_SCRIPT is 1code: stringallowRemove?: booleanfileKey?: string
get_motion_styles
List the animation presets available (beta)fileKey?: string
get_node_motion
Read a node's animation styles and properties (beta)nodeId: stringfileKey?: string
apply_animation_style changes
Add a preset animation to a node (beta)nodeId: stringstyleId: stringanimationStyleData?: objectfileKey?: string
remove_animation_style changes
Take a preset animation off a node (beta)nodeId: stringanimationStyleId?: stringfileKey?: string
apply_manual_keyframe_track changes
Add a keyframe track to a node property (beta)nodeId: stringfield: objecttrack: objectfileKey?: string
remove_manual_keyframe_track changes
Take a keyframe track off a node property (beta)nodeId: stringfield: objectfileKey?: string
set_timeline_duration changes
Change a timeline's length in seconds (beta)nodeId: stringtimelineId: stringduration: numberfileKey?: string
save_screenshots changes
Export nodes and write the image files into the server's working directoryitems: arrayformat?: enumscale?: numberclip?: booleanfileKey?: string

Similar servers