feat: add get_pages and set_current_page, and fix get_document_info's single-page index - #186
Open
juansilvadesign wants to merge 1 commit into
Open
feat: add get_pages and set_current_page, and fix get_document_info's single-page index#186juansilvadesign wants to merge 1 commit into
juansilvadesign wants to merge 1 commit into
Conversation
…s page index honest
get_document_info is page-scoped: it reads figma.currentPage and builds its
`pages` array from that same single page, so the response looks like a document
summary while describing one page. Auditing a real file, that produced a ~100x
undercount — 6 frames reported against an actual 764.
- get_pages enumerates figma.root.children document-wide. Top-level child counts
are opt-in because documentAccess: "dynamic-page" requires loadAsync() per
page; the opt-in path emits progress heartbeats so the server's inactivity
timeout does not fire while pages load on large documents.
- set_current_page wraps figma.setCurrentPageAsync. Together with get_pages this
lets a client sweep every page unattended, which was previously impossible:
set_focus refuses cross-page selection ("The selection of a page can only
include nodes in that page"), so switching page required a human in the
Figma UI.
- get_document_info now indexes every page, marking each child count
"available" (current page) or "not_requested", so the index can never be
mistaken for a complete child census.
Additive: no existing field changes meaning or is removed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
juansilvadesign
added a commit
to juansilvadesign/cursor-talk-to-figma-mcp
that referenced
this pull request
Jul 27, 2026
…rdict Folds findings that were living only in session memory into the plan, so they survive a context clear: - 5.1 authoring-session clustering on get_local_components. The tool counts every variant including bulk-pasted kits (KAT: 3,849 of 4,094 were Untitled UI), and the working split is the id prefix. pages scoping only covers this when the kit happens to sit on its own page. - 5.2 bound get_document_info payloads — the last document-wide read that can still blow the context budget, and the one that forces the spill-to-jq workaround because Read cannot chunk single-line JSON. - 5.3 the two cosmetic wording nits found during the PR-4 verification. - 5.4 runtime/distribution: npm @latest has none of this work, so .mcp.json stays on the fork dist and the DEV plugin until upstream cuts a version bump. - 5.5 the two write-layer defects that are out of scope but kept costing debugging time (mixed-font set_multiple_text_contents, CROP normalisation). Also marks the "neither tool is a superset" A/B verdict as superseded by the f430682 fix recorded further down the same section. It reads as the standing conclusion when skimmed, and it is not — post-fix the fork is a strict superset on that node. Nothing in Milestone 5 is started, and none of it blocks the grab#186 to PRs 2-5 cadence. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
The bug
get_document_inforeadsfigma.currentPageand then builds itspagesarray from that same single page:So the response has the shape of a document summary while describing exactly one page — and it never errors, so a caller has no signal that anything is missing.
Auditing a real multi-page file, this produced a ~100x undercount: the tool reported 6 frames where the file's mobile page alone holds 764. The number was well-formed, confident, and wrong.
What this adds
get_pages— enumeratesfigma.root.childrendocument-wide. Top-level child counts are opt-in, becausedocumentAccess: "dynamic-page"requiresloadAsync()per page and that cost shouldn't be mandatory. The opt-in path emits progress heartbeats so the server's inactivity timeout doesn't fire while pages load.set_current_page— wrapsfigma.setCurrentPageAsync, validating that the target is actually aPAGE.get_document_info— now indexes every page, marking each child count"available"(current page) or"not_requested". The index can no longer be mistaken for a complete child census.Why the pair matters
Together these make an unattended multi-page sweep possible for the first time. Previously
set_focusrefused cross-page selection:…so switching page required a human clicking in the Figma UI, which meant any document-wide automation had a manual step in the middle of it.
Compatibility
Additive. No existing field is removed or changes meaning —
get_document_infogainsscope,document, andpageCount, and its existingpagesentries gainchildCountStatus. Callers readingpages[].id/.nameare unaffected; callers that assumedpageshad length 1 were reading a bug.Verification
This repo has no test suite or linter, so this was validated against live Figma files, including the one that produced the undercount above:
get_pagesreturns 6 pages whereget_document_infopreviously reported 1. Top-level child counts: 1 / 826 / 764 / 81 / 1 / 35 — the 764-child page is the one that had been summarised as "6 frames".get_pages({ includeChildCount: true })completed for every page, so the opt-inloadAsync()cost is real but tolerable, and the heartbeats keep the inactivity timeout from firing.get_document_infoalso reported as 1 page.set_current_pageswitches pages, and subsequent page-scoped reads operate on the new page.bun run buildsucceeds.Source-only — no
dist/changes, matching the convention from #185.