Skip to main content
Question

Plugin API via Figma MCP: cross-page reads return empty, cross-page clones fail silently, and edits don't reliably persist

  • July 9, 2026
  • 1 reply
  • 14 views

yanbever

When driving a FigJam file through the Plugin API via an MCP integration, I hit three reproducible problems in one working session. Filing together since they all stem from Plugin-API-over-MCP reliability.

1. Cross-page reads return empty. Reading a page's children for any page that is NOT the
currently active page (e.g. figma.root.children[n].children where n is not figma.currentPage) returns 0 nodes, even when the page clearly has content. Only the active page reads correctly. This makes it impossible to reliably inspect or verify content on other pages.
2. Cross-page clone/append fails silently. Calling .clone() on a sticky and appendChild
onto a different page produces no visible node and throws no error. The operation reports success but the content never appears on the target page. Recreating nodes from scratch on the active page works; moving/cloning across pages does not.
3. Edits don't reliably persist / possible transaction rollback. Text edits and deletes
sometimes don't stick. Separately, using throw new Error(...) to surface diagnostic output appears to abort the transaction before the preceding mutation commits, so the operation reports success while the change is actually rolled back.

Net effect: same-page reads and moves are reliable, but anything cross-page, or any mutation followed by a thrown diagnostic, is not, and there's no error to signal the failure.

Environment: FigJam file, Plugin API accessed via an MCP server, macOS.

1 reply

Jaycee Lewis
Figmate

Hey ​@yanbever 👋 Thanks for the great writeup. Very helpful.

For issues 1 and 2, my gut says they are related to the same underlying behaviour. Can you confirm — in your session, did you call setCurrentPageAsync on the target page before reading or appending to it? If not, that may explain both symptoms.

For issue 3, this one, I could confirm as described. A script that mutates a node and then throws — even for something as simple as surfacing diagnostic output — discards that mutation with no error signal that anything was rolled back in my quick test. 

My setup: a 2-page test file (Sticky, Not_Sticky) with one sticky note on Sticky used for all mutation tests, and two additional stickies manually placed on Not_Sticky to serve as ground truth for the cross-page read tests.

My tests for 3:

Requests:

// Baseline — mutate, no throw
const sticky = figma.root.children.find(p => p.id === '0:1').findOne(n => n.id === '1:3');
await figma.loadFontAsync(sticky.text.fontName);
const before = sticky.text.characters;
const marker = 'BASELINE_' + Date.now();
sticky.text.characters = marker;
return { stickyId: sticky.id, before, markerWritten: marker };

// -> fresh read afterward confirms sticky.text.characters === marker (persisted normally)
 // Suspect — mutate, then throw a diagnostic error
const sticky = figma.root.children.find(p => p.id === '0:1').findOne(n => n.id === '1:3');
await figma.loadFontAsync(sticky.text.fontName);
const before = sticky.text.characters;
const marker = 'SUSPECT_' + Date.now();
sticky.text.characters = marker;
throw new Error('Diagnostic: wrote "' + marker + '", was "' + before + '"');

// -> error confirms the write executed before throwing
// -> fresh read afterward: sticky.text.characters is back to the BASELINE value, not the SUSPECT marker
// -> the pre-throw mutation was discarded

Responses:

Baseline (mutate, no throw):

json

{
"stickyId": "1:3",
"before": "",
"markerWritten": "BASELINE_1783612914532"
}

Fresh follow-up read:

{
"currentValue": "BASELINE_1783612914532"
}

→ persisted exactly as written.

Suspect (mutate, then throw):

Error: Diagnostic: wrote "SUSPECT_1783613320601", was "BASELINE_1783612914532"
at <anonymous> (PLUGIN_1_SOURCE:8:16)

Fresh follow-up read:

{
"currentValue": "BASELINE_1783612914532"
}

→ still shows the baseline value — the SUSPECT_... write was discarded.

Screenshot after both tests for issue #3

I took all 3 issues to the MCP team for guidance. I’ll post back here with any updates or next steps for us. Thanks again! — Jaycee