Skip to main content
Glama

figma_execute_code

Destructive

Runs JavaScript in the open Figma document to create, edit, move, or style nodes in one call, returning a screenshot so the change can be verified visually.

Instructions

WRITE tool: run JavaScript in the open Figma document (Figma Desktop + 'Mokido' plugin) to create, edit, move, style or delete nodes. To READ (explore a section, list children, find layers, check texts / fonts / variants / table columns) call figma_inspect instead: every id in one call, one line per node, view:"table" for tables; a read script here costs a model turn per question and its reply names the figma_inspect call to use (use_instead). Every call is a full model turn, so make the whole change in ONE call — all screens / breakpoints, verified in the same code with bridge.check — and put capture_node_ids on that same call instead of a separate figma_screenshot. Globals: figma, await ensureFont(family, style), getFreePosition(w, h), bridge: bridge.check({ '1:2': { width: 320, fill: '#FFFFFF' } }) -> pass/fail list; bridge.define(name, src) + bridge.require(name) keep helpers between calls (each call is a fresh function body — never eval); return bridge.info() lists the rest. Macros: bridge.replaceWithInstance(target, comp, {props, text}), bridge.setProps(inst, {Status: 'Dropdown'}), bridge.setText(root, {layer: '…'}) or bridge.setText(textNode, 'new text') (keeps mixed font styles by words: THE way to replace the text of a label with several font styles — never characters =, which flattens them, and never a per-character getRangeFontName/setRangeFontName loop), bridge.shift(ids, {dx, dy}), bridge.moveInto(ids, section, {layout, gap}), bridge.fitSection(s), bridge.context(id), bridge.componentize(nodeObject) -> new COMPONENT, same name/size/look, NEW id (never raw createComponentFromNode), prototype links: await bridge.openOverlay(triggerId, overlayFrameId, { position: 'BOTTOM_CENTER', dim: 0.4, closeOnOutside: true }) (the overlay look is read-only in the Plugin API: the reply names the MANUAL STEP for the user), bridge.closeOverlay(id), bridge.setReaction(id, { to: frameId, nav: 'NAVIGATE' }); read links with figma_inspect view:"flow". Call macros directly, don't read their source. Never findAll the whole page — scope to a section. Return only the ids/flags you need: responses over max_output_bytes (3500) are shrunk, the full value stays in bridge.state.lastResult.

Input Schema

NameRequiredDescriptionDefault
codeYesJavaScript to run in the Figma sandbox, compiled as an async function body (top-level await and return allowed; import/export are not). Example: const frame = figma.createFrame(); frame.resize(400, 600); frame.name = 'Card'; figma.currentPage.appendChild(frame); return 'Created frame';
diffNoCurrently ignored (the "before" screenshot stalls the plugin); the reply has the after image only.
asyncNoReturn { status: 'running', job_id } immediately instead of waiting — collect it later with figma_job_status. Calls that run past 45s do this automatically.
scaleNoScreenshot resolution scale (default: 1).
max_pxNoLongest side of each returned image in px (default: 1024). Image tokens grow with pixel count, not file size.
targetNofileName of a specific connected Figma document to run this in, when more than one is open (see figma_list_targets). Defaults to whichever is currently focused.
captureNoSet to true to capture a PNG of what this call created/modified and return it for visual verification. Never touches the user's selection — see capture_node_ids.
descriptionNoShort human-readable description of the action (e.g. 'Create login modal', 'Update brand colors') shown in Figma toasts and logs.
capture_node_idsNoNode ids to screenshot instead of the default (whatever this call created/modified, falling back to the user's current selection only if neither exists). The user's selection is never mutated to enable a capture.
max_output_bytesNoCap on the whole text response in UTF-8 bytes (default: 3500 — under the ~4 KB at which some clients spill output to a file and cost an extra turn; in clients that spill big outputs to a file, 0 and values above 3900 become 3900). Larger results are shrunk structurally (multi-line text is cut by whole lines), cuts marked with ….

Schema Changelog

Changes observed during successful MCP inspections.

  1. First observedv0.1.0

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover the safety profile (write, destructive, non-idempotent), and the description adds substantial context they cannot carry: every call is a full model turn so batch the whole change, responses over max_output_bytes are shrunk with the full value in bridge.state.lastResult, overlay appearance is read-only and yields a manual step, and state persists between calls via bridge.define/require. It also discloses hazards: never eval, never findAll the whole page, never assign `characters`.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The critical framing (WRITE tool, use figma_inspect to read, do it in one call) is front-loaded, but the body is a dense semicolon-chained wall enumerating every bridge macro, which is hard to scan. Most sentences carry load-bearing information, yet the macro catalog dilutes the routing guidance an agent needs first.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 10-parameter, high-destructiveness write tool with no output schema, the definition covers execution model, return-value behavior, size limits, batching expectations, and the read/write split against siblings. Nothing an agent needs to invoke it safely or correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so parameters are already documented. The description still adds real meaning: it specifies the sandbox globals available inside `code` (figma, ensureFont, getFreePosition, bridge) and the specific bridge macros to prefer over raw Plugin API calls, plus where to put capture_node_ids and why output size matters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with an explicit label ('WRITE tool') and a precise verb list (create, edit, move, style, delete) against a named resource (nodes in the open Figma document). It immediately draws the boundary against the sibling that could be confused with it (figma_inspect for reads).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

States when to use the alternative explicitly ('To READ ... call figma_inspect instead') and enumerates the read tasks that belong there (list children, find layers, check fonts/variants/table columns). It also routes specific sub-tasks to other tools/calls: capture_node_ids instead of a separate figma_screenshot, and figma_job_status for async results.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.