Skip to main content
Glama

figma-bridge

An MCP server that connects Claude to Figma — read files, and create or edit anything the Figma Plugin API can reach.

Works with any MCP client, including ones Figma's official remote server refuses to serve.


Why this exists

Figma ships an official remote MCP server at https://mcp.figma.com/mcp. It is good, and if your client is on Figma's MCP Catalog you should use it instead of this.

The catch is that the server gates OAuth dynamic client registration by client name. Testing POST https://api.figma.com/v1/oauth/mcp/register:

client_name

Response

Claude Code

200 OK

Claude Desktop

403 Forbidden

Visual Studio Code

403 Forbidden

Cursor

403 Forbidden

Unlisted clients cannot complete the OAuth handshake, so they fail with a bare "Connection to server failed" and no explanation. Figma's docs confirm the policy: "Only clients listed in the Figma MCP Catalog like VS Code, Cursor, or Claude Code can connect to the Figma MCP Server."

figma-bridge sidesteps registration entirely. It talks to Figma two ways you already control: a plugin you install yourself, and a personal access token you issue yourself.


Related MCP server: F_MCP

Architecture

┌────────┐  stdio JSON-RPC   ┌─────────────────┐  WebSocket 127.0.0.1  ┌───────────────┐
│ Claude │ ◄───────────────► │ figma-bridge.js │ ◄───────────────────► │ Figma plugin  │
└────────┘                   └─────────────────┘                       └───────────────┘
                                      │  HTTPS + personal access token
                                      ▼
                              ┌───────────────┐
                              │ api.figma.com │
                              └───────────────┘

Two paths, because of a hard constraint worth understanding:

The REST API cannot create nodes. It is almost entirely read-only. So writes cannot go through a token.

The Plugin API can create anything, but only exists inside a running plugin. There is no way to call it from outside Figma.

So writes are relayed to a plugin over a loopback WebSocket, and reads that REST can answer go straight to api.figma.com. The practical consequence: creating things requires the plugin window to be open; reading does not.

The plugin's main thread has the Plugin API but no network access, so the WebSocket lives in the plugin's UI iframe and messages hop across via postMessage.

Zero dependencies

No npm install. WebSocket framing is implemented directly against RFC 6455 — masking, the three payload-length encodings, continuation frames, and ping/pong. One file, Node's standard library only.


Requirements

  • Node.js 18+ — for the bridge server

  • Figma desktop app — plugin development is not available in the browser

  • A Figma personal access token — optional, enables the REST read tools


Installation

1. Get the code

git clone https://github.com/sinahosseini379/claude-figma-bridge.git

Put it somewhere permanent — the path goes into your MCP config.

2. Create a Figma token (optional)

In Figma: Settings → Security → Personal access tokens → Generate new token.

Scopes needed: File content (read), and Variables (read) if you want design tokens.

Skip this if you only care about writes; the plugin path does not use it.

3. Register the MCP server

Settings → Developer → Add local MCP server:

{
  "command": "node",
  "args": ["C:\\path\\to\\claude-figma-bridge\\server\\figma-bridge.js"],
  "env": {
    "FIGMA_TOKEN": "figd_your_token_here"
  }
}

If the Developer section is missing, an administrator must enable isLocalDevMcpEnabled.

claude mcp add --scope user figma-bridge \
  --env FIGMA_TOKEN=figd_your_token_here \
  -- node /path/to/claude-figma-bridge/server/figma-bridge.js

It speaks MCP 2024-11-05 over stdio with newline-delimited JSON-RPC 2.0. Point your client at:

command: node
args:    ["/path/to/server/figma-bridge.js"]
env:     FIGMA_TOKEN=figd_...

Restart your client afterwards. MCP servers load at startup, so an already-open session will not see the new tools.

4. Install the Figma plugin

In the Figma desktop app: Menu → Plugins → Development → Import plugin from manifest… and pick plugin/manifest.json.

This is a local development plugin. Nothing is published, and nothing leaves your machine.


Usage

Open the plugin from Plugins → Development → figma-bridge. Leave the window open — closing it drops the connection. A green dot means the bridge is live.

Then ask your client for what you want. Read-only requests work with the plugin closed.

Environment variables

Variable

Default

Purpose

FIGMA_TOKEN

Personal access token. Without it the REST tools return an error and only the plugin tools work.

FIGMA_WS_PORT

3055

Loopback port for the plugin bridge. Change it if something else owns 3055; set the same number in the plugin window.


Tools

Tool

Plugin open?

What it does

figma_status

no

Reports whether the plugin is connected and whether a token is configured. Start here when something breaks.

figma_run

yes

Runs JavaScript inside the plugin sandbox with the full Plugin API in scope. The main write tool.

figma_current_selection

yes

The current page, all pages, and what the user has selected.

figma_get_file

no

A file's node tree over REST, depth-limited.

figma_get_node

no

Full detail for specific nodes.

figma_get_images

no

Renders nodes to PNG/SVG/JPG/PDF and returns URLs.

figma_get_variables

no

Published design tokens. Enterprise plans only.

figma_me

no

The authenticated account — use it to verify a token.

File arguments accept a full Figma URL or a bare file key; /file/, /design/, /board/, and /slides/ URLs all work. Node ids copied from URLs (1-23) are converted to API form (1:23) automatically.

figma_run

This is where the power is. The code argument is a function body executed with figma in scope and awaited, so return a value to get it back.

Create a flowchart in FigJam:

const nodes = [];
for (const [i, label] of ['Start', 'Validate', 'Save', 'Done'].entries()) {
  const s = figma.createSticky();
  await figma.loadFontAsync({ family: 'Inter', style: 'Medium' });
  s.text.characters = label;
  s.x = i * 260;
  s.y = 0;
  nodes.push(s);
}
for (let i = 0; i < nodes.length - 1; i++) {
  const c = figma.createConnector();
  c.connectorStart = { endpointNodeId: nodes[i].id, magnet: 'AUTO' };
  c.connectorEnd = { endpointNodeId: nodes[i + 1].id, magnet: 'AUTO' };
}
figma.viewport.scrollAndZoomIntoView(nodes);
return { created: nodes.length };

Build a card component with auto-layout:

await figma.loadFontAsync({ family: 'Inter', style: 'Bold' });
const card = figma.createFrame();
card.name = 'Card';
card.layoutMode = 'VERTICAL';
card.primaryAxisSizingMode = 'AUTO';
card.counterAxisSizingMode = 'FIXED';
card.resize(320, 100);
card.itemSpacing = 8;
card.paddingTop = card.paddingBottom = 16;
card.paddingLeft = card.paddingRight = 16;
card.cornerRadius = 12;
card.fills = [{ type: 'SOLID', color: { r: 1, g: 1, b: 1 } }];

const title = figma.createText();
title.fontName = { family: 'Inter', style: 'Bold' };
title.characters = 'Card title';
card.appendChild(title);

return { id: card.id, name: card.name };

Define colour variables:

const collection = figma.variables.createVariableCollection('Brand');
const modeId = collection.modes[0].modeId;
const created = [];
for (const [name, hex] of Object.entries({ primary: [0.05, 0.6, 1], danger: [0.88, 0.19, 0.19] })) {
  const v = figma.variables.createVariable(name, collection, 'COLOR');
  v.setValueForMode(modeId, { r: hex[0], g: hex[1], b: hex[2] });
  created.push(v.name);
}
return { collection: collection.name, variables: created };

Three rules to keep in mind:

  • Await async Plugin API calls. loadFontAsync, getNodeByIdAsync, and friends. Text operations fail silently if the font is not loaded first.

  • Return plain JSON. Node objects are not serialisable. Return ids and names, not nodes.

  • Colours are 0–1, not 0–255. { r: 1, g: 0, b: 0 } is red.

Reference: Figma Plugin API docs.


Troubleshooting

"Figma plugin is not connected" — the plugin window is closed, or its dot is not green. Reopen it from Plugins → Development → figma-bridge.

The plugin will not connect — the bridge server is not running. Your MCP client normally launches it; to check by hand, run node server/figma-bridge.js and look for bridge listening on 127.0.0.1:3055. You can also open http://127.0.0.1:3055 in a browser — it returns the bridge's status as JSON.

EADDRINUSE — something else has port 3055. Set FIGMA_WS_PORT in the MCP config and the matching port in the plugin window.

REST tools return 403 — the token is wrong, expired, or missing a scope. Call figma_me to tell a bad token apart from other failures.

REST tools return 404 — usually a file key parsed from an unexpected URL shape. Pass the bare key instead.

No figma_* tools at all — the client did not pick up the server. Confirm the config path is absolute, then fully restart the client (quit it, including any tray icon) and start a new conversation.

"sandbox blocks dynamic code evaluation" — some Figma builds disable new Function. figma_run cannot work there; the explicit selection and page_contents commands still do. Open an issue and more first-class commands can be added.


Security

The bridge binds to 127.0.0.1 only, so it is not reachable from the network. Two things are still worth knowing:

There is no authentication on the local port. Any process on the same machine can connect and ask the plugin to run code. This was a deliberate tradeoff for single-user local use, not an oversight. If you share the machine or run untrusted code on it, add a shared secret before using this.

figma_run executes arbitrary code in your file, including destructive operations. It can delete nodes and pages. Work on a duplicate when the file matters. Figma's own undo history covers plugin changes, but do not rely on it alone.

Your token sits in the MCP client's config. Treat that file as a secret. The bridge never logs the token and never writes it anywhere.


Development

node server/test-bridge.js

19 tests covering the MCP handshake and tool listing, error paths before the plugin connects, request/response round-trips, plugin-side error propagation, 20 concurrent in-flight calls, a 200 KB payload (exercising the 64-bit length header), multi-byte UTF-8, and disconnect handling. The harness spawns the real server and stands in for the plugin with a fake WebSocket client, so no Figma access is needed.

Not covered by automated tests: the plugin actually running inside Figma. That needs a human with Figma open.

Layout

server/
  figma-bridge.js    MCP server, WebSocket bridge, REST client
  test-bridge.js     test harness
  start-bridge.ps1   manual launcher for debugging (Windows)
plugin/
  manifest.json      plugin manifest
  code.js            main thread — has the Plugin API, no network
  ui.html            UI iframe — has network, no Plugin API

Adding a tool

Append an entry to the TOOLS array in server/figma-bridge.js with a name, a description the model will read, an inputSchema, and an async handler. Handlers reach Figma via bridgeSend(command, params) or the REST API via restGet(path). To add a first-class plugin command, add it to COMMANDS in plugin/code.js as well.


License

MIT

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • F
    license
    -
    quality
    -
    maintenance
    An MCP bridge that enables Claude Code to directly control Figma via a WebSocket-connected plugin. It allows users to create elements, modify styles, manage layouts, and interact with Figma designs using natural language commands.
    1,107
  • A
    license
    C
    quality
    C
    maintenance
    A comprehensive MCP server that enables Claude to read, create, edit, and generate code from Figma designs. Supports design tokens, code generation to multiple frameworks, and accessibility checks.
    100
    3
    MIT
  • A
    license
    -
    quality
    C
    maintenance
    Read-only Figma MCP server that enables design-to-code workflows by talking to the Figma REST API with a personal access token, for use with Claude Code and GitHub Copilot.
    2,101
    MIT

View all related MCP servers

Related MCP Connectors

  • Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer

  • Augments MCP Server - A comprehensive framework documentation provider for Claude Code

  • Markdown-first MCP server for Notion API with 8 composite tools and 39 actions.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sinahosseini379/claude-figma-bridge'

If you have feedback or need assistance with the MCP directory API, please join our Discord server