Bridge AI assistants to Figma Desktop via MCP — draw UI with JavaScript, read designs as structured data, extract screenshots and tokens
Scanned 9/8/2026
Install to Claude Code
npx -y skills add Aradotso/design-skills --skill figma-ui-mcp-bridge --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Figma Ui Mcp Bridge?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/aradotso-figma-ui-mcp-bridge)More formats (shields.io, HTML) on the badges page.
---
name: figma-ui-mcp-bridge
description: Bridge AI assistants to Figma Desktop via MCP — draw UI with JavaScript, read designs as structured data, extract screenshots and tokens
triggers:
- "connect to Figma and draw a UI"
- "create a design in Figma using AI"
- "read the selected Figma frame"
- "extract design tokens from Figma"
- "take a screenshot of the Figma canvas"
- "generate a design system rule sheet"
- "draw a mobile app screen in Figma"
- "get component instances from Figma"
---
# Figma UI MCP Bridge
> Skill by [ara.so](https://ara.so) — Design Skills collection
Bidirectional MCP bridge between AI assistants and Figma Desktop. Let Claude Code, Cursor, Windsurf, VS Code Copilot, or any MCP-compatible IDE draw UI directly on Figma canvas via JavaScript and read existing designs back as structured data, screenshots, or code-ready tokens. Works entirely over localhost — no Figma API key required.
**Requires Figma Desktop** (web app cannot access localhost).
## Architecture
```
AI Agent ─figma_write─▶ MCP Server ─HTTP (localhost:38451)─▶ Figma Plugin ─▶ Figma Document
AI Agent ◀figma_read──── MCP Server ◀HTTP (localhost:38451)─ Figma Plugin ◀─ Figma Document
```
The MCP server starts an HTTP server on `localhost:38451`. The Figma plugin uses long polling (8s hold, <100ms latency). Multi-instance support — multiple Figma files can connect simultaneously via `sessionId`.
## Installation
### Step 1: Add MCP Server
**Claude Code (CLI):**
```bash
# Project scope
claude mcp add figma-ui-mcp -- npx figma-ui-mcp
# Global scope
claude mcp add --scope user figma-ui-mcp -- npx figma-ui-mcp
```
**Claude Desktop:**
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
```json
{
"mcpServers": {
"figma": {
"command": "npx",
"args": ["-y", "figma-ui-mcp"]
}
}
}
```
**Cursor:**
Edit `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global):
```json
{
"mcpServers": {
"figma": {
"command": "npx",
"args": ["-y", "figma-ui-mcp"]
}
}
}
```
**VS Code / Copilot:**
Edit `.vscode/mcp.json`:
```json
{
"mcp": {
"servers": {
"figma": {
"command": "npx",
"args": ["-y", "figma-ui-mcp"]
}
}
}
}
```
**Windsurf:**
Edit `~/.codeium/windsurf/mcp_config.json`:
```json
{
"mcpServers": {
"figma": {
"command": "npx",
"args": ["-y", "figma-ui-mcp"]
}
}
}
```
**⚠️ MUST restart IDE/AI client after adding MCP server** (quit and reopen — saving config is not enough).
### Step 2: Install Figma Plugin
1. Download `plugin.zip` from https://github.com/TranHoaiHung/figma-ui-mcp/raw/main/plugin.zip
2. Unzip anywhere on your machine
3. Open **Figma Desktop** (required)
4. **Plugins → Development → Import plugin from manifest...**
5. Select `manifest.json` from unzipped folder
6. Run **Plugins → Development → Figma UI MCP Bridge**
Green dot = connected. Orange = server not reachable.
### Step 3: Verify Connection
```javascript
// AI will call this automatically when you say "connect to Figma"
figma_status()
// Returns: { status: "ok", fileName, pageName, pluginVersion, sessions: [...] }
```
## Core MCP Tools
### `figma_status`
Check connection status and list active sessions.
```javascript
figma_status()
// Response:
// {
// status: "ok",
// fileName: "My Project",
// pageName: "Page 1",
// pluginVersion: "2.5.12",
// sessions: [
// { sessionId: "abc123", fileName: "My Project", pageName: "Page 1" }
// ]
// }
```
### `figma_docs`
Get full API reference and examples. Call once at session start to load capabilities.
```javascript
figma_docs()
// Returns: markdown reference with all operations, params, examples
```
### `figma_rules`
Generate design system rule sheet — color tokens, typography styles, variables (all modes), component catalog. Equivalent to official Figma MCP's `create_design_system_rules`. Call once per file.
```javascript
figma_rules({ sessionId: "abc123" }) // optional sessionId
// Returns: markdown rule sheet with all design tokens
```
### `figma_write`
Execute JavaScript operations on Figma canvas. Takes `operation` (string) and `params` (object).
**Single operation:**
```javascript
figma_write({
operation: "create",
params: {
type: "FRAME",
name: "Login Screen",
width: 390,
height: 844,
fill: "#FFFFFF",
children: [
{
type: "TEXT",
name: "Title",
characters: "Welcome Back",
fontSize: 32,
fontFamily: "Inter",
fontWeight: 700,
fill: "#000000",
x: 40,
y: 100
}
]
}
})
```
**Batch operations:**
```javascript
figma_write({
operations: [
{
operation: "create",
params: { type: "FRAME", name: "Container", width: 800, height: 600 }
},
{
operation: "modify",
params: { id: "result[0]", fill: "#F5F5F5" }
}
]
})
```
Use `result[0]`, `result[1]` to reference previous operation results.
### `figma_read`
Read data from Figma. Takes `operation` and `params`.
**Get page structure:**
```javascript
figma_read({
operation: "get_page_nodes",
params: {}
})
// Returns: { nodes: [...], totalNodes: 42 }
```
**Get selection:**
```javascript
figma_read({
operation: "get_selection",
params: {}
})
// Returns: [{ id, name, type, x, y, width, height, ... }]
```
**Take screenshot:**
```javascript
figma_read({
operation: "screenshot",
params: { nodeId: "123:456", scale: 2 }
})
// Returns: { base64: "data:image/png;base64,..." }
```
**Get design context (AI-optimized):**
```javascript
figma_read({
operation: "get_design_context",
params: { nodeId: "123:456" }
})
// Returns: flex layout, token-resolved colors, typography with style names,
// component instances with variant properties — best for code generation
```
**Get component map:**
```javascript
figma_read({
operation: "get_component_map",
params: { frameId: "123:456" }
})
// Returns: { instances: [{ componentSetName, variantLabel, properties, suggestedImport }] }
```
**Get CSS:**
```javascript
figma_read({
operation: "get_css",
params: { nodeId: "123:456" }
})
// Returns: { css: "display: flex; flex-direction: column; ..." }
```
## Common Operations
### Create Nodes
**Frame with auto-layout:**
```javascript
figma_write({
operation: "create",
params: {
type: "FRAME",
name: "Card",
width: 320,
height: 240,
fill: "#FFFFFF",
cornerRadius: 16,
layoutMode: "VERTICAL",
paddingTop: 24,
paddingRight: 24,
paddingBottom: 24,
paddingLeft: 24,
itemSpacing: 16,
effects: [
{
type: "DROP_SHADOW",
color: "rgba(0,0,0,0.1)",
offsetX: 0,
offsetY: 4,
blur: 12
}
]
}
})
```
**Text with typography:**
```javascript
figma_write({
operation: "create",
params: {
type: "TEXT",
name: "Heading",
characters: "Design System",
fontSize: 48,
fontFamily: "Inter",
fontWeight: 700,
lineHeight: { value: 120, unit: "PERCENT" },
letterSpacing: { value: -2, unit: "PERCENT" },
fill: "#1A1A1A"
}
})
```
**Rectangle with gradient:**
```javascript
figma_write({
operation: "create",
params: {
type: "RECTANGLE",
name: "Gradient BG",
width: 800,
height: 600,
fill: {
type: "LINEAR_GRADIENT",
angle: 135,
stops: [
{ position: 0, color: "#667EEA" },
{ position: 1, color: "#764BA2" }
]
}
}
})
```
**Icon from library:**
```javascript
figma_write({
operation: "createIcon",
params: {
name: "home",
library: "ionicons", // ionicons | fluent | bootstrap | phosphor | tabler-filled | tabler-outline | lucide
size: 24,
fill: "#000000",
x: 100,
y: 100
}
})
```
**Component instance with overrides:**
```javascript
figma_write({
operation: "instantiate",
params: {
componentKey: "abc123",
overrides: {
"ButtonLabel": { text: "Submit", fill: "#FFFFFF" },
"Icon": { visible: false }
}
}
})
```
### Modify Nodes
**Change properties:**
```javascript
figma_write({
operation: "modify",
params: {
id: "123:456",
fill: "#FF5733",
width: 400,
opacity: 0.8
}
})
```
**Apply design tokens:**
```javascript
figma_write({
operation: "applyVariable",
params: {
nodeId: "123:456",
field: "fills", // fills | strokes | width | height | cornerRadius | paddingTop | etc.
variableName: "color/primary"
}
})
```
**Apply text style:**
```javascript
figma_write({
operation: "applyTextStyle",
params: {
nodeId: "123:456",
styleName: "Heading/H1"
}
})
```
### Setup Design Tokens
**Color tokens (all modes):**
```javascript
figma_write({
operation: "setupDesignTokens",
params: {
colors: {
"color/primary": {
Light: "#667EEA",
Dark: "#A5B4FC"
},
"color/background": {
Light: "#FFFFFF",
Dark: "#1A1A1A"
}
}
}
})
```
**Typography tokens:**
```javascript
figma_write({
operation: "setupDesignTokens",
params: {
fontSizes: {
"size/xs": { Compact: 12, Comfortable: 14, Large: 16 },
"size/sm": { Compact: 14, Comfortable: 16, Large: 18 },
"size/md": { Compact: 16, Comfortable: 18, Large: 20 }
},
fonts: {
"font/primary": { Compact: "Inter", Comfortable: "Inter", Large: "SF Pro" }
},
textStyles: [
{
name: "Heading/H1",
fontFamily: "font/primary",
fontSize: "size/md",
fontWeight: 700,
lineHeightPercent: 120
}
]
}
})
```
### Prototyping
**Add click interaction:**
```javascript
figma_write({
operation: "setReactions",
params: {
nodeId: "123:456",
reactions: [
{
trigger: "ON_CLICK", // ON_CLICK | ON_HOVER | ON_PRESS | ON_DRAG
action: "NAVIGATE", // NAVIGATE | OVERLAY | SWAP | SCROLL_TO | CLOSE
destinationId: "789:012",
transition: "SMART_ANIMATE", // SMART_ANIMATE | DISSOLVE | SLIDE_IN | PUSH | etc.
duration: 300,
easing: "EASE_OUT"
}
]
}
})
```
**Set scroll behavior:**
```javascript
figma_write({
operation: "setScrollBehavior",
params: {
nodeId: "123:456",
overflow: "VERTICAL" // HORIZONTAL | VERTICAL | BOTH | NONE
}
})
```
### Component Variants
**Set variant properties:**
```javascript
figma_write({
operation: "setComponentProperties",
params: {
instanceId: "123:456",
properties: {
"State": "Primary",
"Size": "Large"
}
}
})
```
**Swap component:**
```javascript
figma_write({
operation: "swapComponent",
params: {
instanceId: "123:456",
newComponentKey: "def789"
}
})
```
## Read Operations Reference
| Operation | Purpose | Key Params |
|-----------|---------|------------|
| `get_page_nodes` | List all top-level nodes | `{ maxDepth }` |
| `get_selection` | Get selected nodes | `{}` |
| `get_node_detail` | Full node data with resolved variables/styles | `{ nodeId }` |
| `get_design_context` | AI-optimized payload for code generation | `{ nodeId }` |
| `get_component_map` | List component instances with variants | `{ frameId }` |
| `get_unmapped_components` | Find components missing code mapping | `{ frameId }` |
| `get_css` | Generate CSS from node | `{ nodeId }` |
| `screenshot` | Capture PNG | `{ nodeId, scale }` |
| `get_variables` | All variables (all modes) | `{}` |
| `get_styles` | All color/text/effect styles | `{}` |
## Multi-Instance Sessions
When multiple Figma files are open, each plugin instance has a unique `sessionId`. Target specific files:
```javascript
// List all sessions
figma_status()
// { sessions: [{ sessionId: "abc123", fileName: "App Design" }, ...] }
// Write to specific session
figma_write({
operation: "create",
params: { type: "FRAME", name: "Test" },
sessionId: "abc123"
})
// Read from specific session
figma_read({
operation: "get_page_nodes",
params: {},
sessionId: "abc123"
})
```
Omit `sessionId` to use the first connected session.
## Common Patterns
### Design System Bootstrap
```javascript
// Step 1: Generate rule sheet
figma_rules()
// Step 2: Setup color tokens
figma_write({
operation: "setupDesignTokens",
params: {
colors: {
"color/primary": { Light: "#667EEA", Dark: "#A5B4FC" },
"color/text": { Light: "#1A1A1A", Dark: "#F5F5F5" }
}
}
})
// Step 3: Setup typography
figma_write({
operation: "setupDesignTokens",
params: {
fontSizes: {
"size/h1": { Compact: 32, Comfortable: 40, Large: 48 }
},
textStyles: [
{
name: "Heading/H1",
fontSize: "size/h1",
fontWeight: 700
}
]
}
})
```
### Design-to-Code Workflow
```javascript
// Step 1: Get design context
const context = await figma_read({
operation: "get_design_context",
params: { nodeId: "123:456" }
})
// Returns: flex layout, resolved color tokens, typography with style names
// Step 2: Get component map
const components = await figma_read({
operation: "get_component_map",
params: { frameId: "123:456" }
})
// Returns: { instances: [{ componentSetName: "Button", variantLabel: "State=Primary", suggestedImport: "@/components/Button" }] }
// Step 3: Get CSS
const css = await figma_read({
operation: "get_css",
params: { nodeId: "123:456" }
})
// Returns: { css: "display: flex; ..." }
```
### Batch Create + Reference
```javascript
figma_write({
operations: [
// Create container
{
operation: "create",
params: {
type: "FRAME",
name: "Container",
width: 800,
height: 600,
layoutMode: "VERTICAL",
itemSpacing: 24
}
},
// Create child, insert into container
{
operation: "create",
params: {
type: "RECTANGLE",
name: "Header",
width: 800,
height: 80,
fill: "#667EEA",
parentId: "result[0]" // Reference first operation's result
}
}
]
})
```
## Troubleshooting
### Plugin shows orange dot
- **Cause:** MCP server not running or wrong port
- **Fix:** Restart IDE/AI client (MCP server loads on startup). Check server logs for port conflicts.
### "Plugin not connected" error
- **Cause:** Plugin not running in Figma Desktop
- **Fix:** Figma Desktop → Plugins → Development → Figma UI MCP Bridge. Must be Figma Desktop (web app cannot access localhost).
### Operations fail silently
- **Cause:** Invalid node ID or operation params
- **Fix:** Call `figma_read get_page_nodes` first to get valid node IDs. Check `figma_docs` for param schema.
### Font not found
- **Cause:** Font not installed on system
- **Fix:** Use `fontFamily: "Inter"` (ships with Figma) or install custom fonts locally.
### Multi-instance targeting wrong file
- **Cause:** No `sessionId` specified with multiple files open
- **Fix:** Call `figma_status` to list sessions, then pass `sessionId` to `figma_write`/`figma_read`.
### Variable binding fails
- **Cause:** Variable doesn't exist or wrong type
- **Fix:** Call `figma_read get_variables` first. Ensure `FLOAT` variables for dimensions, `COLOR` for fills.
## Best Practices
1. **Always call `figma_docs` at session start** to load API reference into AI context
2. **Call `figma_rules` once per file** to get design system tokens before generating code
3. **Use `get_design_context` for code generation** — single call returns all layout/color/typography data
4. **Use `get_component_map` for import statements** — returns `suggestedImport` paths
5. **Batch operations when possible** — reduces round-trips (single `figma_write` with `operations` array)
6. **Reference previous results** with `result[0]`, `result[1]` in batch operations
7. **Use design tokens** (`applyVariable`) instead of hardcoded colors for maintainability
8. **Check `figma_status` first** to verify connection and list sessions
9. **Use `sessionId`** when multiple Figma files are open to avoid ambiguity
10. **Take screenshots** to verify AI-generated designs match intent
## Version Updates
```bash
# Get latest version + plugin path
npx figma-ui-mcp@latest --version
# Re-link Figma plugin (manual step required)
# Figma Desktop → Plugins → Development → Manage plugins in development
# Remove old → Import from manifest → Select new plugin path
```
Plugin does **not** auto-update — must re-link after npm update.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!