add write tools — find_nodes and batch_mutation - #29
Open
matiukhov wants to merge 48 commits into
Open
Conversation
fix: ensure `paints` is array when serialize
fix: get_node timeout
feat(server): add save_screenshots tool for batch export to disk
Add missing text style properties to the plugin's node serializer and text style handler. This enables MCP consumers to distinguish font weights, decorations, and spacing when reading Figma text layers. - Add fontWeight, fontStyle, textDecoration, lineHeight, letterSpacing to serializeText in serializer.ts - Add serializeLineHeight and serializeLetterSpacing helpers to handle the LineHeight discriminated union (AUTO vs explicit) and mixed values - Add textDecoration, lineHeight, letterSpacing to get_styles text style output in code.ts
fix: allow in dev mode, and hopp branding
feat: add fontWeight, fontStyle, and other text properties to serializer
…h-tools feat: add more styles in payload and readme update
Replace single WebSocket connection with a Map keyed by fileKey, allowing multiple Figma files to be open and queryable at the same time. - Bridge stores connections per fileKey extracted from WS query params - Plugin sends figma.fileKey when connecting to the WebSocket server - All tools accept optional fileKey param to target a specific file - New list_files tool to discover connected files - Backward compatible: single-file setups work without specifying fileKey
feat: support multiple Figma files connected simultaneously
The leader forwards rpcReq.nodeIds to the bridge, so an RPC call with only params.nodeId would validate locally but fail downstream when nodeIds is empty. Spread params first, then set nodeId from nodeIds?.[0] so the forwarded payload always wins.
startsWith("/ws") accepted unintended paths like /ws-anything. Parse the
URL and compare pathname so query parameters still work without widening
the upgrade endpoint.
Pending requests previously waited the full 30-second timeout when a plugin connection dropped, then surfaced a misleading "Request timed out" error. Tag each PendingRequest with its WebSocket so close/error handlers can eagerly reject the right subset with a clear "plugin disconnected" message — the agent learns immediately and gets the actual cause.
…llback figma.fileKey is null for unsaved files, and the previous fallback to figma.root.name collided whenever two files shared a name. Generate a session-scoped fallback key on first use and emit a console.warn so issues are easy to diagnose from a built plugin. Addresses konsalex's PR gethopp#20 review feedback (the request for an error log on the fallback path) and CodeRabbit's note that the fallback identifier needs to be unique.
When status.fileKey or status.fileName changes, cleanup closed the old socket but its onclose handler could still schedule connect() through a stale closure — that timer would later close the new socket and reconnect to the previous file. Add a disposed flag and guard onclose/onerror against running for a socket that has been replaced. Clear the event handlers in cleanup so in-flight events on the closing socket cannot mutate React state.
…wups fix: address PR gethopp#20 review feedback (multi-file)
Allows toggling visibility of any Figma nodes via MCP. Returns previous visibility state so callers can restore it — enabling workflows like hiding all siblings, exporting an isolated layer, then restoring.
Create image-backed rectangles from local paths, URLs, or data URIs.
New MCP tool that replaces a node's fill (or stroke) with a
LINEAR/RADIAL/ANGULAR/DIAMOND gradient paint. Accepts ordered stops
({position, hex, opacity?}) and an optional 2x3 gradientTransform
matching Figma's format. Lets agents apply gradient fills the same
way they already apply solid fills via set_node_properties.
Dev Mode is read-only — every figma.create*/setter would otherwise throw a confusing low-level error from inside the Figma sandbox. Reject mutating requests up front with a clear message that points the user to switch to the design editor. Read-only tools continue to work in Dev Mode unchanged.
Move the solidFillHex/solidFillOpacity fields out of set_node_properties
into a dedicated set_solid_fill tool, mirroring set_gradient_fill. The
new tool takes { hex, opacity?, target? } where target is "fill" or
"stroke", matching the gradient API. set_node_properties now only
patches geometry/identity properties; paint changes go through
set_solid_fill or set_gradient_fill.
The handler previously only applied stroke params for LINE shapes — RECTANGLE and ELLIPSE silently dropped strokeHex/strokeOpacity/ strokeWeight even though the schema accepted them. It also defaulted LINE strokeHex to "#000000" implicitly, which was a hidden footgun asymmetric with the other shape types. Changes: - Apply strokes uniformly for all shape types (reuses setSolidFill with target="stroke") - Reject fillHex on LINE (Figma lines have no fill) - Require strokeHex on LINE (otherwise invisible) — both at schema level via refine() and at handler level for clear errors
Close the biggest read/write asymmetries — these properties were already
emitted by the serializer (effects, stroke geometry, auto-layout config)
but no tool could write them.
set_effects replaces the full effects array (pass [] to clear), matching
Figma's array semantics. Shadow entries take {color, opacity, offset,
radius, spread, blendMode, visible}; blur entries take {radius, visible}.
set_stroke_properties patches geometry-only stroke fields (weight, align,
dashPattern, cap, join). Paint is still set via set_solid_fill or
set_gradient_fill with target='stroke'.
set_auto_layout configures one frame's layout: direction, gap, padding,
alignment, sizing modes, wrap. Set layoutMode='NONE' to disable.
All three are gated by EDIT_REQUEST_TYPES so they fail fast with a clear
error in Dev Mode.
Four small tools that close obvious gaps: - group_nodes wraps nodes sharing a parent in a new group (or uses an explicit parentId). Returns the new group's id + child ids. - ungroup_node explodes a GROUP or FRAME back to its parent and returns the orphans' ids in their new location. - set_selection sets the page selection by node ids (pass [] to clear). Read-mode safe — works in Dev Mode without the editor-mode gate. - scroll_and_zoom_into_view frames the viewport around the given nodes. Also Dev-Mode-safe. group_nodes/ungroup_node are added to EDIT_REQUEST_TYPES so they fail fast in Dev Mode. set_selection/scroll_and_zoom_into_view intentionally skip the gate so an agent can still direct attention in read-only files.
The Zod regex only matched `^\d+:\d+$`, which rejected valid IDs the plugin already returns from get_selection / get_design_context for nodes inside an INSTANCE (e.g. `I12740:17806;12740:17793`). The bridge was emitting these IDs and then rejecting them on the very next get_node / get_screenshot / save_screenshots call, making instance children unreachable. Widen the regex to accept both forms; reject bare `I<id>` without a `;<child>` segment since the `I` prefix is only meaningful with a child segment. Update the corresponding `.describe(...)` strings and the get_node tool description so model clients know the form is allowed (the old text said "never use hyphens / colon format only", which actively misled the model away from the second form). Fixes gethopp#24
fix(schema): accept instance-child node IDs in figmaNodeId
feat: authoring/edit tools — set_*, create_*, duplicate/reparent/delete
Export Image Clip API Support
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds two new MCP tools that enable write operations on Figma files through the bridge:
Changes