# Understanding figma-use Skill Critical Rules and API Constraints: A Complete MCP Guide

> Master figma-use skill critical rules and API constraints. Learn about mandatory JSON returns, async/await, and immutable arrays for reliable Figma Plugin API edits. Get the complete MCP guide.

- Repository: [Figma/mcp-server-guide](https://github.com/figma/mcp-server-guide)
- Tags: how-to-guide
- Published: 2026-03-30

---

**The figma-use skill enforces strict JavaScript execution rules—including mandatory JSON returns, async/await requirements, and immutable array handling—to ensure atomic, reliable edits via the Figma Plugin API.**

The `figma-use` skill serves as the primary Model-Centered Programming (MCP) interface for executing JavaScript against Figma files within a controlled, headless plugin environment. According to the `figma/mcp-server-guide` repository, mastering the **figma-use skill critical rules and API constraints** is essential for building reliable automation that prevents partial state corruption and guarantees atomic transaction failures.

## Architecture of the MCP Server Guide

The repository organizes functionality into distinct layers that agents must understand before invoking the `use_figma` tool. The server definition lives in [`server.json`](https://github.com/figma/mcp-server-guide/blob/main/server.json), while skill definitions reside in [`skills/figma-use/SKILL.md`](https://github.com/figma/mcp-server-guide/blob/main/skills/figma-use/SKILL.md). Reference documentation covering API surfaces and edge cases is located in `skills/figma-use/references/`, including the critical [`gotchas.md`](https://github.com/figma/mcp-server-guide/blob/main/gotchas.md) file and complete TypeScript definitions in [`plugin-api-standalone.d.ts`](https://github.com/figma/mcp-server-guide/blob/main/plugin-api-standalone.d.ts).

When an agent loads the **figma-use** skill, the MCP client executes JavaScript snippets in a headless Figma plugin context. The runtime automatically wraps scripts in an async function and returns **only** the value from the final `return` statement, discarding all `console.log` output.

## Critical Rules for Safe Execution

Violating any of these rules results in immediate script termination with atomic rollback—no partial changes persist in the Figma file.

**Return JSON data exclusively.** All output must flow through the `return` statement. Using `console.log` or `figma.notify` causes errors or silent failures.

**Write top-level async code.** The runtime automatically wraps the entire script in an async function. Do not add IIFE wrappers or manual async function declarations.

**Never use `figma.notify`.** This API is stubbed out in the headless environment and throws a "not implemented" error. Use `return` to communicate status.

**Use shared plugin data only.** The methods `getPluginData` and `setPluginData` are unavailable. Use `getSharedPluginData` and `setSharedPluginData` instead.

**Treat fills and strokes as immutable.** Arrays returned by `node.fills` or `node.strokes` are read-only. Clone the array, modify the copy, then re-assign: `node.fills = newFillsArray`.

**Normalize colors to 0–1 range.** All solid color channels use normalized values. Supplying 0–255 integers causes validation errors.

**Reset page context awareness.** Each `use_figma` call starts on the **first** page regardless of previous state. Switch pages explicitly using `await figma.setCurrentPageAsync(page)`.

**Observe layout sizing order.** Set `layoutSizingHorizontal` or `layoutSizingVertical` to `'FILL'` **only after** appending the node to an auto-layout parent.

**Explicitly set variable scopes.** Always define `variable.scopes` explicitly. The default `ALL_SCOPES` value pollutes every variable picker in the Figma UI.

**Await every promise.** Forgetting `await` before asynchronous operations like font loading, page switches, or variable binding creates fire-and-forget bugs that return undefined values.

**Return all affected node IDs.** Scripts must return a structured object containing every created or mutated node ID. Subsequent calls rely on these identifiers for reference.

**Respect atomic failure.** If a script errors, **no changes are applied** to the Figma file. Fix the error and retry the entire operation.

## API Constraints and Limitations

The **figma-use** skill operates with specific API constraints documented in [`skills/figma-use/references/gotchas.md`](https://github.com/figma/mcp-server-guide/blob/main/skills/figma-use/references/gotchas.md). Understanding these limitations prevents common integration failures.

**Forbidden direct page assignment.** Assigning `figma.currentPage = targetPage` throws an error. Use `await figma.setCurrentPageAsync(targetPage)` instead.

**Paint binding returns new objects.** The method `setBoundVariableForPaint` returns a **new** paint object rather than mutating the input. Capture this return value before assigning to `node.fills`.

**Component property keys are strings.** The `addComponentProperty` method returns a string key, not an object. Store this key to reference in `componentPropertyReferences`.

**Resize resets auto-layout modes.** Calling `resize()` on a node resets `primaryAxisSizingMode` and `counterAxisSizingMode`. Call `resize` **before** setting these modes, or use reasonable default sizes.

**Variable collections start with one mode.** New collections created via `createVariableCollection` initialize with a single default mode named "Mode 1". Rename it immediately using `coll.renameMode(coll.modes[0].modeId, 'Light')`.

**Layout grow requires fixed parents.** Setting `layoutGrow` on a child of a hugging parent causes content compression. Only use `layoutGrow` when the parent container uses `FIXED` primary axis sizing.

**Text style variable binding is unsupported.** The `setBoundVariable` method on `TextStyle` objects is not available in headless mode. Assign raw values directly to text style properties.

## Practical Code Examples

### Inspecting File Structure Safely

Read-only inspection scripts must return plain JSON without side effects:

```javascript
// Read-only inspection of pages
const pages = figma.root.children.map(p => ({
  name: p.name,
  id: p.id,
  childCount: p.children.length
}));
return pages;

```

This approach uses only read operations and returns a serializable array, satisfying the rule to return JSON data.

### Creating Variable Collections with Multiple Modes

Design systems require explicit mode management. New collections start with a single mode that requires renaming:

```javascript
// Create collection and configure modes
const coll = figma.variables.createVariableCollection('Colors');

// Rename default mode from "Mode 1" to "Light"
coll.renameMode(coll.modes[0].modeId, 'Light');

// Add secondary mode
const darkModeId = coll.addMode('Dark');

// Return all IDs for subsequent operations
return {
  collectionId: coll.id,
  lightModeId: coll.modes[0].modeId,
  darkModeId
};

```

Note that `await` is unnecessary here because these synchronous methods return immediately.

### Positioning Nodes to Prevent Overlap

New nodes default to coordinates (0, 0), causing them to stack on existing content. Calculate positioning dynamically:

```javascript
// Find rightmost edge on current page
let maxX = 0;
for (const child of figma.currentPage.children) {
  const right = child.x + child.width;
  if (right > maxX) maxX = right;
}

// Create frame with offset
const frame = figma.createFrame();
frame.name = 'New Card';
frame.resize(400, 300);
figma.currentPage.appendChild(frame);
frame.x = maxX + 100;
frame.y = 0;

return { createdNodeIds: [frame.id] };

```

Returning the created node ID allows subsequent scripts to target this specific frame.

### Binding Color Variables to Shapes

Variable binding requires careful handling of paint objects and normalized color values:

```javascript
// Setup collection and variable
const coll = figma.variables.createVariableCollection('Palette');
coll.renameMode(coll.modes[0].modeId, 'Default');
const colorVar = figma.variables.createVariable('Primary', coll, 'COLOR');
colorVar.setValueForMode(coll.modes[0].modeId, { r: 0.2, g: 0.5, b: 0.8, a: 1 });

// Create shape
const rect = figma.createRectangle();
rect.resize(200, 100);
figma.currentPage.appendChild(rect);

// Bind variable to fill (returns new paint object)
const basePaint = { type: 'SOLID', color: { r: 0, g: 0, b: 0 } };
const boundPaint = figma.variables.setBoundVariableForPaint(basePaint, 'color', colorVar);
rect.fills = [boundPaint];

return {
  createdNodeIds: [rect.id],
  variableId: colorVar.id,
  collectionId: coll.id
};

```

Colors use the normalized 0–1 range, and `setBoundVariableForPaint` generates a new paint instance that must be captured.

### Navigating Pages and Auto-Layout

Switching pages requires the async setter, and auto-layout properties must be set in specific order:

```javascript
// Switch to non-first page
const targetPage = figma.root.children.find(p => p.name === 'Components');
await figma.setCurrentPageAsync(targetPage);

// Create auto-layout container
const auto = figma.createFrame();
auto.layoutMode = 'VERTICAL';
auto.primaryAxisSizingMode = 'AUTO';
auto.counterAxisSizingMode = 'FIXED';
auto.resize(400, 1);

// Append child BEFORE setting FILL sizing
const child = figma.createRectangle();
child.resize(380, 80);
auto.appendChild(child);
auto.layoutSizingHorizontal = 'FILL';

figma.currentPage.appendChild(auto);
return { createdNodeIds: [auto.id, child.id] };

```

Setting `layoutSizingHorizontal` only works after the node has a parent with auto-layout enabled.

## Key Reference Files

The following files in `figma/mcp-server-guide` provide authoritative guidance:

- [`skills/figma-use/SKILL.md`](https://github.com/figma/mcp-server-guide/blob/main/skills/figma-use/SKILL.md) – Complete skill definition and critical rules
- [`skills/figma-use/references/gotchas.md`](https://github.com/figma/mcp-server-guide/blob/main/skills/figma-use/references/gotchas.md) – Exhaustive list of API edge cases and incorrect/correct code comparisons
- [`skills/figma-use/references/plugin-api-standalone.d.ts`](https://github.com/figma/mcp-server-guide/blob/main/skills/figma-use/references/plugin-api-standalone.d.ts) – Full TypeScript type definitions for the Plugin API
- [`skills/figma-generate-library/SKILL.md`](https://github.com/figma/mcp-server-guide/blob/main/skills/figma-generate-library/SKILL.md) – Higher-level workflows for design system generation

## Summary

- The **figma-use** skill requires **returning JSON only**—`console.log` and `figma.notify` are unsupported or throw errors.
- **Atomic failure** guarantees that script errors leave the Figma file unchanged, preventing partial corruption.
- **Immutable arrays** for fills and strokes require cloning before modification.
- **Normalized colors** (0–1 range) are mandatory; integer RGB values cause validation failures.
- **Explicit page switching** via `setCurrentPageAsync` is required because each call resets to the first page.
- **Auto-layout constraints** dictate that `layoutSizingHorizontal/Vertical` must be set after appending to a parent container.

## Frequently Asked Questions

### What happens if I forget to return JSON in a figma-use script?

The script executes but returns no data to the MCP client, making it impossible to verify success or obtain node IDs for subsequent operations. Per [`SKILL.md`](https://github.com/figma/mcp-server-guide/blob/main/SKILL.md) rule 1, always use `return` to output structured data.

### Why does `figma.notify` throw an error in figma-use?

The headless plugin environment used by the MCP server does not implement UI notifications. The API is stubbed and throws a "not implemented" error. Use `return` to communicate completion status or data back to the agent.

### How do I handle color values when using the figma-use skill?

All color channels must use normalized values between 0 and 1. For example, white is `{ r: 1, g: 1, b: 1 }`, not `{ r: 255, g: 255, b: 255 }`. Supplying integers in the 0–255 range triggers validation errors as documented in [`gotchas.md`](https://github.com/figma/mcp-server-guide/blob/main/gotchas.md).

### What is the correct order for setting auto-layout properties?

First append the child node to an auto-layout parent, then set `layoutSizingHorizontal` or `layoutSizingVertical` to `'FILL'`. Setting these properties before establishing the parent-child relationship fails silently because the system cannot validate the layout context.