Skip to main content

Generative plugins and shaders

Who can use this feature

Shaders are currently in open beta. Learn more about what's included in the beta.

With the Figma MCP server, your agent can read and write the source code behind generative plugins and shaders, including shader fills and shader effects. You can pull a resource you built with the Figma agent into your own editor, change it with your own tools, and send it back to Figma, where it's rebuilt, versioned, and deployed.

This article explains how these workflows work. For each tool's parameters, see Tools and prompts.

Tools for plugins and shaders​

ResourceListReadCreateUpdate
Generative pluginlist_generative_pluginsget_generative_plugincreate_generative_pluginupdate_generative_plugin
Shader (fill or effect)list_shaders
list_file_shaders
get_shadercreate_shaderupdate_shader
caution

Your agent must load a skill before creating or updating a resource:

  • Shaders: figma-shaders
  • Generative plugins: figma-generative-plugins

The skills contain the required file structure, writing rules, and PropsKit reference. Your agent can load them with the get_figma_skill tool. Learn more about Figma skills for MCP.

note

list_shaders and get_shader work with both shader fills and shader effects. They replace list_shader_effects, list_shader_fills, get_shader_effect, and get_shader_fill, which are deprecated.

Read source code​

Reading source code takes two steps. The list and read tools return a list of the resource's files, each with a URI. Your agent then reads each file from its URI as an MCP resource.

For example, using get_shader on Figma's Glowing wave shader returns:

{
"id": "38c5fa52-a2a8-46db-affb-efd028b890e2",
"name": "Glowing wave",
"description": "Generate luminous wave graphics with on-canvas controls for color, glow, and motion.",
"type": "fill",
"owner": "figma",
"version": "184e861619102db4dcfcb5e967255194dd4478d9",
"files": [
{ "filename": ".build/main.js", "bytes": 8871, "uri": "file://…/.build/main.js" },
{ "filename": "features.json", "bytes": 112, "uri": "file://…/features.json" },
{ "filename": "main.ts", "bytes": 8343, "uri": "file://…/main.ts" }
],
"truncated": false
}
  • main.ts is the source code.
  • .build/main.js is the compiled code.
  • features.json holds settings for the resource, like animation and mouse interaction. It can't be changed through the MCP server.

Who owns a resource​

Every response includes an owner field:

ValueMeaning
Your email addressYou own it. You can read and change the source code.
figmaA resource made by Figma
A public publisher handleA plugin published by someone else

If your client can't read MCP resources​

Ask your agent to set includeSource: true when calling get_shader or get_generative_plugin. The response then includes each file's contents instead of a URI, up to 100 files and 1,000,000 bytes in total. If a limit is reached, the response says which one.

Read a specific version​

Both read tools accept an optional version, a 40-character commit SHA. Leave it out to get the latest version. Use it to read the exact version a file uses, or to compare two versions.

Create and update resources​

Your agent first creates a working starter, then replaces its source code. There's no single step that creates a finished resource.

  1. Get a plan key. Creating a resource requires a planKey for the plan that will own it. Your agent calls whoami and copies a key exactly from the list of plans it returns, for example:

    organization::1234567890
    team::9876543210

    If you belong to more than one plan, your agent should ask which one to use.

  2. Create the starter. For example:

    create_shader({
    name: "Topographic contours",
    description: "Elevation-ring contour lines with adjustable spacing and ruggedness",
    planKey: "team::9876543210",
    kind: "fill"
    })

    This returns an ID. The new resource already exists and runs: it's a starter, not an empty file. The starter has the structure your agent's code needs to match.

  3. Replace the source code. For example:

    update_shader({
    id: "<id from step 2>",
    kind: "fill",
    files: [{ path: "main.ts", content: "<complete file contents>" }],
    commitMessage: "Add contour line shader with spacing and ruggedness controls"
    })

    Each file must include its complete contents, not just the changes. When updating an existing resource, your agent should read the current source first so no code is lost. For shaders, kind must match the existing shader; you can't change a fill to an effect.

    Figma builds, versions, and deploys the update as part of the call. There's no separate publish step. A response without an error means the update worked, even if it doesn't include a version number.

Rename without changing code​

To change only the name or description, your agent sends metadata with an empty files list:

update_shader({
id: "<id>",
kind: "fill",
files: [],
metadata: { name: "Topographic contours v2" },
commitMessage: "Rename"
})

If a build fails​

The response includes the compiler output. Your agent should make the smallest fix it points to and try once more. If it fails again, your agent should show you the error instead of rewriting the resource again and again.

Write shader source code​

A shader's source code is a single file, main.ts. Your agent should read the starter before replacing it, so it uses the right imports and structure.

  • Add controls for values people are likely to change on each layer, and hardcode the rest.
  • Keep number ranges limited and set defaults that look good.
  • For shader effects, use the layer beneath the effect intentionally. For shader fills, don't assume there's a layer beneath.
  • Never include API keys, tokens, or signed URLs. Anyone with access can read the source code.

The figma-shaders skill includes the full writing rules, the WebGPU setup, supported controls, and a troubleshooting checklist.

Write generative plugin source code​

A generative plugin has two files your agent can replace:

FileWhat it does
code.tsRuns the plugin logic. It's the only file that can use the Figma Plugin API.
ui.htmlThe plugin panel. It's the only file that can use browser DOM APIs.

The two files communicate only through messages. code.ts opens the panel with figma.showUI(__html__, …). The plugin also has a manifest.json file, which can't be changed or created through the MCP server.

Every plugin needs a working panel. Even a plugin with no settings needs a clear main action and helpful status, validation, and error messages.

Build the panel with PropsKit​

Plugin panels use PropsKit, a set of fig-* elements that make the panel look and work like the rest of Figma:

<fig-content>
<fig-field>
<label>Count</label>
<fig-input-number id="count" value="3" min="1" max="100"></fig-input-number>
</fig-field>
</fig-content>
<fig-footer>
<label id="status">Ready</label>
<fig-button id="run" type="submit">Create layers</fig-button>
</fig-footer>

Put the controls in <fig-content>, followed by <fig-footer>. Wrap each control in <fig-field> with a <label>, and put the status and actions in the footer.

Common controls include <fig-slider>, <fig-input-number>, <fig-input-text>, <fig-input-color>, <fig-input-gradient>, <fig-input-palette>, <fig-switch>, <fig-options>, <fig-dropdown>, <fig-joystick>, <fig-image>, <fig-input-file>, and <fig-button>.

The figma-generative-plugins skill includes the full list of controls and how to convert their values for the Plugin API. For example, PropsKit colors are hex values and gradient stops go from 0 to 100, but the Plugin API uses values from 0 to 1. To try the controls yourself, use the PropsKit component playground.

note

PropsKit is only for generative plugins. Shaders define their controls in main.ts.

What you can’t change​

Updates can only replace existing files. Files you don't include stay the same.

ResourceCan replaceCan’t replace
Shadermain.tsfeatures.json, which controls animation and mouse interaction
Generative plugincode.ts, ui.htmlmanifest.json

Through the MCP server, you also can’t:

  • Create new files
  • Add imports, dependencies, or build settings that the tools can't deploy
  • Send only the changed part of a file

If a plugin's manifest doesn't support what you want to build, the update tool can't fix it.

Permissions​

Who can read and change source code depends on who owns the resource and whether it's published.

ResourceWho can read the source codeWho can change it
Your own resourcesYouYou
Published resources made by FigmaAnyoneNo one directly. Changes go through the publishing process.
Resources published by othersThe owner only. The compiled code is public.No one directly. Changes go through the publishing process.
Someone else's unpublished shadersAnyone who can open a file that uses them, with list_file_shadersThe owner
  • Source code and compiled code are different. Compiled code is what Figma sends to run a plugin or shader, so anyone who can run it can see it. Source code is the original code and is protected.
  • Ownership and file access are different. get_shader works on shaders you own. list_file_shaders works on shaders in files you can open.
  • Check the owner field in each response to see where a resource came from.
caution

Anyone with access to a plugin or shader can read its source code. Never include API keys, OAuth tokens, signed URLs, or other secrets. For integrations that need authentication, use a static dataset, a public endpoint that doesn't need authentication, or a different approach.

Export shaders to code​

When your selection includes shader fills or effects, get_design_context includes a lightweight Figma shader runtime, written as React components. You don't need to call a separate tool or change any settings.

For example, prompt: "Implement this Figma frame in React using the included shader runtime." Your agent gets the layout, styles, assets, and shader runtime, then connects the runtime to the components it generates.

note

If you already use the MCP server to turn designs into code, this changes your results. Frames that used to come back as an image or a CSS approximation now include a real shader runtime.

To get the right results, tell your agent:

  1. Use the shader runtime, not CSS. On its own, your agent may use a gradient or blur that looks close enough. Ask it to use the runtime and shader source code. This is the most common problem.
  2. HTML-in-Canvas is required. The runtime won't display correctly without it.
  3. Translate the runtime for other frameworks. The runtime is written in React. If your project uses Vue, Svelte, SwiftUI, or another framework, ask your agent to translate the runtime along with the rest of the code.

Usually, your agent should build icons and images from their exported assets. Shaders are the exception: build them from the shader runtime and source code, not from an exported image or a CSS approximation.

Errors​

Common errors and what they mean
SituationWhat happens
The source code doesn't buildAn error with compiler output. Your agent should make the smallest fix it points to and try once more.
Changing a resource you don't ownError
planKey is in the wrong format or isn't one of your plansError. It must match (team|organization)::<numeric-id>.
kind doesn't match the existing shaderError
Updating before creatingError: there's no resource to update
No commitMessageError: it's required
A file path other than main.ts (shaders) or code.ts or ui.html (plugins)Rejected
A file uses more than 100 shaderstruncated: true
at the top of the response
A shader has more than 10,000 filestruncated: true
for that shader
includeSource goes over 100 files or 1,000,000 bytesThe response is cut off and says which limit was reached

A response without an error means success, even if it doesn't include a version.