genable-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| jsxA | Create design trees with nested JSX markup. One jsx call builds a complete subtree atomically — nesting is the hierarchy. Keep a single logical unit inside one call; the returned root's children are already built, not stubs to be filled in later. Examples: jsx({markup: ""}) jsx({markup: "Account"}) Elements: frame, text, rect, ellipse, line, icon, image, instance, component, group, section, vector Attributes (frame): layout, justify, items, wrap, w, h, minW, maxW, p, gap, bg, fill, rounded, stroke, shadow, blur, bgblur, opacity, layoutPositioning Attributes (text): size, weight, lineHeight, font, fill, w (w="fill" for wrap), maxLines, textTruncation Effects: shadow="0,8,32,0,#0006" or shadow={shadow(0,8,32,0,'#0006')}; blur={10} for layer blur; bgblur={20} for frosted-glass/glassmorphism background blur. Multiple effects merge automatically. Decoration in auto-layout: floating orbs/blobs/decorative shapes inside a row/column parent need layoutPositioning="absolute" so they don't get stacked into the main-axis flow. Full-frame backgrounds: set the parent frame's bg directly. Don't add a separate backdrop. Supported gradient strings (CSS-like subset, not full CSS):
Swap an existing subtree: jsx({replaceId: "", markup: "..."}) replaces the old node at the same parent and sibling index atomically, preserving position in one call. Markup must have a single root. Use jsx for tree creation; edit for property updates on known nodes. |
| inspectA | Read design node(s) — choose what to surface with Default (no facets) returns a skeleton: id, name, type, role, children. For anything else, list the facets you need — nothing else is included. Facets: structure name, type, size, layout shorthand — cheap overview layout layoutMode/gap/padding/align/sizing (row/column, fill/hug, etc.) paint|fill fills + Paint.boundVariables.color (see bound tokens) stroke strokes, strokeWeight, strokeAlign, dashPattern effects shadows, blurs typography|text fontFamily, fontSize, fontWeight, lineHeight, letterSpacing appearance opacity, visible, blendMode, cornerRadius, clipsContent variables node-level boundVariables + explicitVariableModes (token bindings) all everything Parameters: node "/" for page root, or node ID from jsx/inspect results (e.g. "100:5"). facets array of facet names listed above. depth Max tree depth (default: 5, max: 10). Examples: inspect({node: "/"}) → page skeleton inspect({node: "100:5"}) → one-node skeleton inspect({node: "100:5", facets: ["variables"]}) → token bindings only inspect({node: "100:5", facets: ["layout", "paint"]}) → layout + fills inspect({node: "100:5", facets: ["all"]}) → full properties Use |
| describeA | Validate a design subtree — semantic description, role detection, and lint rules. Checks for layout conflicts, overflow, missing properties, and structural issues. Parameters: node: Node ID to describe (e.g. "100:5"). Required. depth: How deep to check children (default: 3, max: 8). Returns per-node: role, visual summary, layout summary, and issues (severity: error/warning/info). Examples: describe({node: "100:5"}) → validate subtree, depth 3 describe({node: "100:5", depth: 1}) → shallow check (root + direct children only) |
| editA | Batch update properties on multiple nodes. For single-property changes, prefer focused setters: set_text — text content set_fill — fill/background color set_stroke — border set_layout — padding, gap, direction Use edit for batch fixes or properties not covered by setters (sizing, radius, opacity, effects, component props): edit({nodes: [ {node: "1:1", props: {w: "fill", corner: 8}}, // Figma native props {node: "1:2", props: {opacity: 0.6}}, {node: "1:3", props: {Label: "Sign In"}}, // instance TEXT prop (by display name) ]}) For instances, use component property DISPLAY NAMES (e.g. "Label") — edit resolves them to Figma's internal keys automatically. Component props can be mixed with Figma props in the same call. |
| find_nodesA | Search nodes by name or type. Scoped to the current page — call switch_page first if your target lives on a different page. Examples: find_nodes({query: "Button"}) find_nodes({query: "frame", scope: "1:2"}) |
| discover_propsA | Discover unique property values in a subtree. Examples: discover_props({node: "1:2", props: ["fillColor", "fontSize"]}) Searchable properties: fillColor, textColor, strokeColor, strokeWeight, opacity, cornerRadius, gap, fontSize, fontFamily, fontWeight. |
| replace_propsA | Bulk find-and-replace property values across a subtree (target node + all descendants). Destructive batch mutation — no preview, no undo across many nodes. Returns per-rule match counts. Use when:
Returns: { data: { replacements: [{ rule: 0, matched: 12 }, { rule: 1, matched: 0 }] } } Parameters beyond schema:
Skip when:
Examples: // single rule, white -> black replace_props({node: "1:2", rules: [{prop: "fillColor", from: "#FFF", to: "#000"}]}) // batch theme update — both rules applied in one pass replace_props({node: "1:2", rules: [ {prop: "fillColor", from: "#FFF", to: "#000"}, {prop: "fontSize", from: "14", to: "16"} ]}) |
| find_referencesA | Find every node on the current page that references a given variable. This is the REVERSE of inspect: inspect asks "what does this node bind?", find_references asks "who uses this variable?". Use it when renaming, auditing, or swapping tokens — you need to know all the binding sites before you touch the variable. Scan scope: currentPage only. Invisible nodes are skipped by default. Node-level bindings (e.g. boundVariables.paddingLeft) and per-paint color bindings (fills[i].boundVariables.color, strokes[i].boundVariables.color) are both returned. Parameters: variable — VariableID (e.g. "VariableID:1:5"). Required. Returns: {variable, variableName, variableType, referenceCount, references: [{nodeId, nodeName, nodeType, path}, ...]} path values look like: "boundVariables.paddingLeft" "fills[0].boundVariables.color" "strokes[2].boundVariables.color" Examples: find_references({variable: "VariableID:1:5"}) |
| delete_nodeB | Delete a node and its children. Examples: delete_node({node: "1:2"}) |
| move_nodeA | Relocate a node without recreating it. Preserves IDs, bound variables, and component instances across the move, so callers tracking the node by ID never need to re-discover it. Use for: (a) changing child order within a container, (b) moving a subtree into a different parent, (c) fixing a placement mistake after jsx. Examples: move_node({node: "1:3", name: "NewTitle"}) — rename in place move_node({node: "1:3", parent: "1:4"}) — move into parent 1:4 move_node({node: "1:5", index: 0}) — reorder within current parent |
| clone_nodeA | Deep-copy a node with optional property overrides. Examples: clone_node({node: "1:2"}) — clone to page root, same name clone_node({node: "1:2", parent: "/"}) — clone to page root explicitly clone_node({node: "1:2", parent: "/", name: "Hero Copy"}) — clone to root with custom name clone_node({node: "1:2", parent: "1:4"}) — clone into parent node 1:4 clone_node({node: "1:2", parent: "1:4", overrides: {"bg": "#D9D9D9"}}) |
| skillA | Load a procedural skill — workflow + tool sequence + anti-patterns. Use FIRST when the user is changing/adjusting existing canvas, OR before creating a new design if a matching skill exists. Example: skill({ name: "restyle" }) |
| styleA | Load a visual style preset as INSPIRATION — color tokens, typography, shape, depth. Treat as a reference library, not a cage: pick one wholesale, mix elements, or invent your own. You are not restricted to the menu. Example: style({ name: "neon-cyber" }) |
| guidelineA | Load a page-type design guideline — layout patterns for landing pages, dashboards, login flows, forms, etc. Example: guideline({ name: "form" }) |
| helpB | Load narrow how-to / process help — tool usage rules, edge cases, naming conventions. Example: help({ name: "interaction-model" }) |
| list_variablesA | List variables as a flat array with referenced collections. Returns {data: {variables[], collections[], nextCursor?}}. Each variable carries its full Figma shape: id, name, variableCollectionId, resolvedType, valuesByMode. collections[] only includes collections referenced by the returned variables (use for mode-name resolution). Parameters: collection — VariableCollectionId to filter by filter — substring match on variable name (case-insensitive) cursor — opaque pagination cursor from a previous call limit — max variables per page (default 100) Examples: list_variables() list_variables({collection: "VariableCollectionId:1:2"}) list_variables({filter: "bg"}) list_variables({cursor: "100"}) |
| create_collectionA | Create a VariableCollection with named modes. The first mode in the array becomes the default mode. Returns {data: {id, modes: [{modeId, name}]}} — use those modeIds with set_variable_value and set_variable_mode. Examples: create_collection({name: "Theme", modes: ["Light", "Dark"]}) create_collection({name: "Device", modes: ["Desktop", "Tablet", "Mobile"]}) |
| create_variableA | Create a variable in an existing collection. No value is set here — use set_variable_value after. Returns {data: {id}}. Examples: create_variable({collection: "VariableCollectionId:1:2", name: "Theme/bg", type: "COLOR"}) create_variable({collection: "VariableCollectionId:1:2", name: "spacing/md", type: "FLOAT"}) |
| ensure_collectionA | Idempotent VariableCollection creation — safe to retry. Returns existing collection if one with the same name + identical mode list already exists, otherwise creates a new one. Spec §3.1. Prefer this over create_collection — re-running with the same name + modes returns the existing collection instead of creating a duplicate. Omit idempotency_key — the handler computes it canonically from (name, modes). Pass it only if you need strict concurrency-safety validation (LLMs should not try to compute SHA-256 inline; placeholder strings are rejected). Returns {data: {collection_id, modes: [{modeId, name}], reused?: true}}. Examples: ensure_collection({name: "Theme", modes: ["Light", "Dark"]}) |
| ensure_variableA | Idempotent variable creation — populates values_by_mode in one shot. Prefer this over create_variable — re-running with the same args returns the existing variable instead of creating a duplicate. Behavior (spec §3.1):
values_by_mode keys can be either mode NAMES (e.g. "Light") or modeIds (e.g. "1:0"). Each value must match the variable type (hex/RGBA for COLOR, number for FLOAT, string for STRING, boolean for BOOLEAN). Omit idempotency_key — the handler computes it canonically from (collection_id, name, type, values_by_mode). Pass it only if you need strict concurrency-safety validation (LLMs should not try to compute SHA-256 inline; placeholder strings are rejected). Mode coverage policy (spec §6.2):
Returns {data: {variable_id, name, type, collection_id, mode_coverage[], mode_coverage_required, reused?: true}, warnings?: [...]}. Examples: ensure_variable({collection_id: "VariableCollectionId:1:2", name: "Text/Primary", type: "COLOR", values_by_mode: {Light: "#111", Dark: "#EEE"}}) ensure_variable({collection_id: "VariableCollectionId:1:2", name: "Spacing/desktop", type: "FLOAT", values_by_mode: {Desktop: 24}, mode_coverage_required: "opt-in-fallback", fallback_reason: "Desktop-only metric; fallback to Desktop in Mobile mode."}) |
| set_variable_valueA | Set a variable's value for a specific mode. Thin wrapper over Figma's variable.setValueForMode(modeId, value). Call once per mode. Value is a raw value (COLOR/FLOAT/STRING/BOOLEAN) OR an alias object {type: "VARIABLE_ALIAS", id: "VariableID:x:y"}. Hex strings are accepted for COLOR and normalized to {r,g,b,a} in 0-1 range. Examples: set_variable_value({variable: "VariableID:1:5", mode: "1:0", value: "#FFFFFF"}) set_variable_value({variable: "VariableID:1:5", mode: "1:1", value: {r: 0.1, g: 0.1, b: 0.1, a: 1}}) set_variable_value({variable: "VariableID:1:6", mode: "1:0", value: 16}) set_variable_value({variable: "VariableID:1:7", mode: "1:0", value: {type: "VARIABLE_ALIAS", id: "VariableID:1:9"}}) |
| bind_variableA | Bind a FLOAT, BOOLEAN, or STRING variable to a node property. prop is a flat Figma bindable field (e.g. fontSize, itemSpacing, paddingTop, cornerRadius, opacity, visible, width, height, characters). Shorthands: gap → itemSpacing, padding → paddingTop, corner → cornerRadius, font-size → fontSize. COLOR variables are NOT bound here — they live inside Paint objects. To apply a color token, specify it at the source instead: • At creation: jsx <frame bg="$TokenName" ...> or fill="$TokenName" • Post-hoc: set_fill({node, bg: "$TokenName"}) or set_stroke When selecting which variable to bind: if the node is a Tablet or Mobile variant (name or variant property contains "Tablet"/"Mobile"), match the node's property value against the Tablet/Mobile mode column from list_variables — not Desktop. Examples: bind_variable({node: "1:2", prop: "fontSize", variable: "VariableID:1:6"}) bind_variable({node: "1:3", prop: "paddingTop", variable: "VariableID:1:7"}) bind_variable({node: "1:4", prop: "visible", variable: "VariableID:1:8"}) bind_variable({node: "1:5", prop: "characters", variable: "VariableID:1:9"}) |
| set_variable_modeA | Set a node to use a specific mode of a variable collection. This controls which variable values the node displays. For example, set a frame to use "Dark" mode of the "Theme" collection so all bound variables show dark values. Examples: set_variable_mode({node: "1:2", collection: "VariableCollectionId:1:2", mode: "1:1"}) set_variable_mode({node: "1:5", collection: "VariableCollectionId:1:3", mode: "1:2"}) |
| create_componentC | Convert a frame or group to a Figma component. Examples: create_component({node: "1:2"}) |
| combine_componentsB | Combine multiple components into a variant set (ComponentSet). Examples: combine_components({nodes: ["1:2", "1:3", "1:4"], name: "Button"}) |
| add_component_propA | Add a component property and bind it to a child node. For TEXT properties: binds to the target text node's characters, so instances can override the text content. For BOOLEAN properties: binds to the target node's visibility. Parameters: node: The component node ID (must be COMPONENT or COMPONENT_SET). name: Property display name. type: TEXT, BOOLEAN, or INSTANCE_SWAP. default: Default value. bind: Child node ID to bind this property to. For TEXT, binds to text content. For BOOLEAN, binds to visibility. Examples: add_component_prop({node: "1:2", name: "Label", type: "TEXT", default: "Click me", bind: "1:5"}) add_component_prop({node: "1:2", name: "Show Icon", type: "BOOLEAN", default: "true", bind: "1:6"}) |
| list_component_propsA | List properties and variants of a component, component set, or instance. Examples: list_component_props({node: "1:2"}) |
| create_instanceA | Create an instance of an existing component. Mutates the canvas — appends a new InstanceNode as the last child of Use when:
Returns: { data: { id: "5:42", name: "Button", componentId: "1:2" } } Parameters beyond schema:
Skip when:
Examples: create_instance({node: "1:2"}) // at page root create_instance({node: "1:2", parent: "1:4"}) // inside frame 1:4 |
| set_textA | Set text content on one or more nodes. set_text({node: "1:2", text: "Hello World"}) set_text({nodes: [{node: "1:2", text: "Title"}, {node: "1:3", text: "Subtitle"}]}) Use this when changing what text says. For text styling (font, size, weight), use edit. |
| set_fillA | Set fill or background color on a node. set_fill({node: "1:2", bg: "#F5F5F5"}) set_fill({node: "1:2", fill: "#333333"}) set_fill({node: "1:2", bg: "linear-gradient(135deg, #8B5CF6 0%, #F97316 100%)"}) // Batch — bulk paint update in one call: set_fill({nodes: [{node: "1:2", bg: "#FFF"}, {node: "1:3", bg: "#F5F5F5"}]}) fill = text color or shape fill. bg = frame background. For stroke color, use set_stroke. Accepted color formats (for fill or bg): hex "#FFF", "#F5F5F5" gradient string CSS-like subset, not full CSS: "linear-gradient(deg, <#hex> %, ...)" "linear-gradient(to , ...)" directions: top/right/bottom/left + corners "radial-gradient()" centered, no position/shape modifiers "radial-gradient(circle, )" circle shape only "conic-gradient(from deg, ...)" Rejected: "circle at X% Y%", "ellipse at ...", named colors, hsl(). variable token qualified bare name "$Surface/Card" transparent "transparent" (bg only) |
| set_strokeA | Set stroke (border) on a node. set_stroke({node: "1:2", stroke: "1 #E0E0E0"}) set_stroke({node: "1:2", stroke: "2 #333 inside"}) set_stroke({node: "1:2", color: "#E0E0E0", weight: 1, align: "inside"}) set_stroke({node: "1:2", color: "linear-gradient(90deg, #8B5CF6 0%, #F97316 100%)", weight: 1.5, align: "inside"}) // Batch — bulk stroke update in one call: set_stroke({nodes: [{node: "1:2", color: "#E0E0E0", weight: 1}, {node: "1:3", color: "#333", weight: 2}]}) Shorthand: "weight color align" (e.g. "1 #E0E0E0 inside"). Hex only in shorthand. Accepted color formats (for the explicit To bind a variable to the stroke color, use the explicit |
| set_layoutB | Set auto-layout properties on a container. set_layout({node: "1:2", gap: 16, p: 24}) set_layout({node: "1:2", layout: "row", justify: "space-between"}) set_layout({node: "1:2", layout: "column", gap: 8, p: "16 24", align: "center"}) set_layout({node: "1:2", layout: "grid", cols: 3, rows: 2, gap: 16}) // Batch — bulk update in one call: set_layout({nodes: [{node: "1:2", gap: 16, p: 24}, {node: "1:3", gap: 8, p: 12}]}) Controls spacing, padding, direction, and alignment of a container's children. Grid: use layout:"grid" with cols/rows + gap (or rowGap/colGap for asymmetric). Children fill the grid in insertion order. |
| get_selectionA | Get the user's currently selected nodes in Figma. Returns node names, types, and IDs of selected elements. Call this when the user's intent involves modifying existing elements:
Skip for fresh design requests ("design a login page", "create a dashboard") — a new canvas has no selection to read, so the call returns nothing and burns an iteration. Examples: get_selection() |
| switch_pageA | Navigate between pages in the Figma file. ID-driven — names are not addressable (they can collide and change). Two modes:
Pages are top-level containers under the file root. Most read/write operations default to figma.currentPage. Call this when you need to operate on nodes that live on a different page than the current one. Returns:
Typical flow:
When to call:
Don't call:
|
| read_plugin_dataA | Read plugin data (private or shared) from a Figma node. Use for: i18n metadata, design-system tags, custom plugin annotations, anything stored via setPluginData / setSharedPluginData. If Returns Examples: read_plugin_data({node_id: "1:5", key: "ref"}) read_plugin_data({node_id: "1:5", namespace: "i18n", key: "ref"}) |
| write_plugin_dataA | Write plugin data (private or shared) to a Figma node. If Pass an empty string as Examples: write_plugin_data({node_id: "1:5", key: "ref", value: "home_title"}) write_plugin_data({node_id: "1:5", namespace: "i18n", key: "ref", value: "home.welcome_title"}) |
| create_vectorA | Create a vector node from SVG path data or a list of points. Use for chart lines, custom icon paths, freeform curves, or any shape that needs path data. Examples: // Polyline (chart trend line) create_vector({ parent: "1:23", name: "TrendLine", x: 40, y: 20, width: 550, height: 240, points: [[0,144],[90,96],[180,120],[270,64],[360,80],[450,40],[540,72]], stroke: "#6366F1", strokeWeight: 2 }) // Raw SVG path (custom shape) create_vector({ parent: "1:23", name: "Wave", width: 200, height: 60, data: "M 0 30 Q 50 0 100 30 T 200 30", stroke: "linear-gradient(90deg, #8B5CF6 0%, #F97316 100%)", strokeWeight: 1.5 }) Path input — provide ONE of: points: [[x,y], ...] compiled to "M x0 y0 L x1 y1 ..." (polyline shortcut) data: "M ... L ..." raw SVG path (LLM-native; supports M, L, C, Q, A, Z) Stroke / fill (same formats as set_stroke / set_fill): hex "#6366F1" gradient "linear-gradient(angle, #color stop%, ...)" variable qualified bare name "$Brand/Primary" Default fill is "transparent" so the vector shows only its stroke. Pass an explicit fill if you want it filled. When NOT to use:
|
| get_screenshotA | Capture a PNG screenshot of a node. Use after style changes to visually verify the result instead of reading properties back. Returns base64 PNG data embedded in the response. Parameters: node: Node ID from jsx/inspect results (e.g. "100:5"). Page root ("/") is not supported. scale: Export scale 0.5–2 (default 1). Higher = larger file. padding: Reserved for future use — currently ignored. Examples: get_screenshot({node: "100:5"}) → PNG at 1x get_screenshot({node: "100:5", scale: 2}) → PNG at 2x (sharper) |
| ask_userA | Ask the user 1-3 questions in a single form. Each question has its own options and can be single- or multi-select. Bundle related decisions in ONE call instead of multiple turns. Use when:
Returns one of:
Each question:
Conventions:
Example: ask_user({ questions: [ { question: "Who is this for?", options: [{label:"B2B SaaS"},{label:"Consumer"},{label:"Developer tool"}] }, { question: "What visual direction?", options: [{label:"Minimal"},{label:"Bold/Brutalist"},{label:"Neon/Cyber"}] } ]}) Skip when the prompt is already actionable — asking adds a turn and costs momentum. |
| subtaskA | Delegate a focused sub-task to a typed child agent. Each type has its own tools, iteration budget, and behavioral constraints. Available agent types:
Use when the prompt names 3+ distinct regions (e.g. header, sidebar, main) that share no nodes, or when specialized behavior is needed (audit, token ops). For 1-2 tool-call operations, inline calls finish faster than the subtask spin-up cost. |
| session_noteA | Read / write your own session scratchpad. Persists across turns within one design session ("New Design" resets it). Notes are how state carries from this turn into the next — the next session loads them as context. Actions: action: "read" → read({key}) returns the current value (empty string if unset) action: "write" → write({key, value}) replaces or deletes (pass value:"" to delete) action: "list" → list({}) returns [{key, chars}] for all existing notes Slots — FORWARD-LOOKING (what we plan / commit to):
Slots — BACKWARD-LOOKING (what happened, write AT TURN END — AUTO-MERGE on write):
BACKWARD-LOOKING slots auto-merge: writing to REQUIRED behavior:
Examples: session_note({action: "write", key: "decisions", value: "Style: fintech-dark.\nAccent: #3B82F6 (style.accent — NOT indigo).\nFont: Space Grotesk display / Inter body.\nHero treatment: split (overrides anatomy VERTICAL — desktop convention).\nH1 size: 32 (style.display)."}) session_note({action: "write", key: "failures", value: "jsx #6 align='stretch' rejected (DSL valid: center|start|end|space-between|baseline) — retried with 'center'. Same CSS-prior class as gradient: model has CSS values that DSL doesn't accept."}) session_note({action: "write", key: "gotchas", value: "8 LOW_CONTRAST warnings on nav links + secondary CTA (2.5:1 against dark bg). Left as-is — user prompt didn't require WCAG pass; flagging in case next iteration tightens contrast."}) session_note({action: "write", key: "learnings", value: "layoutPositioning='absolute' children render correctly inside auto-layout frame, but parent needs clipsContent=true to suppress overflow on big glow ellipses."}) session_note({action: "read", key: "decisions"}) session_note({action: "list"}) |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/musepy/genable'
If you have feedback or need assistance with the MCP directory API, please join our Discord server