figma-reader-mcp
figma-reader-mcp is a read-only Figma inspection MCP server for reading, searching, comparing, and exporting data from Figma files without a plugin or API token.
Check account, browser, and login status; log in to figma.com for this project's account.
List local
.figfiles or the account's recently viewed Figma files.Export/decode a file key or URL, or read a local
.fig, returning a summary of pages, node counts, variable collections, styles, and components.Read a compact layer-tree outline with depth, node, and max-node limits.
Get normalized design data for a node/subtree: geometry, fills/strokes/effects, auto-layout, text, instances, variables, styles, and Dev Mode annotations/measurements.
Locate node IDs and report whether each exists and where.
Search nodes by name and optionally text, with regex, case, type, page, subtree, hidden-layer, and instance-text options.
Read variables/tokens as JSON, CSS, or DTCG; read styles as JSON or CSS; read components, variants, and library component usage.
Aggregate raw token-like values (colors, typography, radii, spacing, effects) from a subtree or whole file.
Read Dev Mode status: Ready for dev, Completed, removed, or never marked, with history.
Extract all text under a node/file, expanding component instances and reporting unresolved instances.
Take PNG screenshots of nodes from the live file via Figma's Copy as PNG.
Export original bitmap assets used by image fills/strokes to a directory.
Diff two snapshots of one file for added, removed, renamed, or moved layers and removed subtrees.
Find top-level layers created or edited since an ISO date or duration.
Optionally write token/style output, screenshots, or image exports to chosen local files/directories.
Provides read-only access to Figma files, including document trees, variables, styles, components, text, image fills, and screenshots, from local .fig files or live Figma files via a browser.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@figma-reader-mcpshow me the component list for https://figma.com/file/abc"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
figma-reader
Read-only Figma access for AI agents and people. No Figma plugin, no API token, no Dev Mode seat, no Enterprise plan.
It ships in two forms that share the same tools and code. Use whichever fits:
Command | Best for | |
MCP server |
| MCP clients (Claude Code, Claude Desktop, Cursor, ...). One long-lived process keeps decoded files in memory and the browser and editor tab warm, so repeated calls are fast |
CLI |
| Shells, scripts, CI, and agents that prefer running commands over loading MCP tools. Nothing to register; output is JSON/text on stdout. Each call decodes the file again, seconds on a large one |
Two ways to feed it:
Local
.figfile (File › Save local copy in Figma, then pass the path). Fully offline, no browser. Everything except screenshots.Figma file key / URL. It drives figma.com in a headless Chromium-family browser over the DevTools protocol, and shows a visible window only when you need to log in:
Data | How |
Document tree, variables, styles, components, text, image fills | File › Save local copy (triggered via Quick actions) → |
Screenshots | Copy as PNG on the node; the PNG is intercepted in the page, the system clipboard is never touched |
Recent files, account | Figma's internal web API with the browser's session cookies |
Variables come straight out of the file, so modes, aliases and scopes are available on any plan (the REST variables endpoint is Enterprise-only).
Install
Pick the line for how you want to use it. Everything below needs Node 22+, and a Chromium-family browser only for the calls that read figma.com.
You want | Run |
The CLI on your PATH |
|
To try it without installing |
|
An agent that knows how to drive it |
|
The MCP server in one project |
|
To work on it |
|
The skill line writes .agents/skills/figma-reader/ and registers it for Claude Code and the other agents that read that directory; it teaches the CLI, so it pairs with either of the first two lines. skills/figma-reader/SKILL.md is the file, if you would rather copy it in by hand or paste it into an AGENTS.md.
First run on a file key or URL will say it is not logged in and open a normal browser window on the Figma login page. Log in there; the window closes itself and everything after that is headless. figma-reader login --wait-seconds 300 does the same deliberately and waits for you.
Working with more than one Figma login is the same two commands in each directory:
cd ~/work/acme && figma-reader use client-acme && figma-reader loginuse writes .figma-reader.json, which binds that directory and everything below it to its own browser profile and snapshot cache, so accounts never see each other's sessions or files. Nothing is created on disk until you log in. See Accounts.
Related MCP server: ai-sdlc-figma-mcp-server
Tools
MCP tool names and CLI commands map one to one: figma_get_tree is figma-reader get-tree.
Tool | Purpose |
| Account, browser mode, running browser, logged-in user. |
| Open the visible login window / wait for login. Its JSON answers carry |
| Local |
| Export + decode, summary (pages, counts, collections, styles). For a snapshot exported through the browser, |
| Compact layer outline, under a one-line |
| Normalized design data: geometry, fills/strokes/effects, auto-layout, text runs, instance props, bound variables, style names. Dev Mode handoff data where a node has it: |
| Look up a list of |
| Find nodes by name / text; with |
| Collections, modes, values, resolved aliases; |
| FILL, STROKE, TEXT, EFFECT and GRID styles; |
| Local components, variant sets, and |
| Dev Mode status: nodes marked Ready for dev or Completed, and those unmarked since, newest change first, each with |
| Aggregate raw values in use (colors, type, radii, spacing, effects) to derive tokens from files without variables |
| All copy under a node, component instances expanded, with |
| PNG of a node via Copy as PNG |
| Original bitmap assets, from fill and stroke paints; per image the |
| Two snapshots of one file compared by node id: pages and top-level layers (a page's children and what its sections hold) added, removed, renamed (same id, other name) or moved (same id, other parent), and |
| Top-level layers created or edited since an ISO date or a duration ( |
Every tool that reads a file takes one as a local .fig path, a file key, or a figma.com/design/... URL. A node-id in that URL is used by the seven tools that take a node_id — figma_get_tree, figma_get_node, figma_search, figma_token_usage, figma_get_text, figma_screenshot, figma_export_image_fills — when the argument is omitted. The seven that answer about the whole file (figma_load_file, figma_get_variables, figma_get_styles, figma_get_components, figma_dev_status, figma_diff, figma_changes) have no node to scope to and ignore it, and so does figma_locate, which takes its ids in node_ids. figma_status, figma_login and figma_list_files name no file at all; figma_list_files lists local .fig files by default (source: "web" for the account's recent files). figma_screenshot is the exception among the rest: the image always comes from the live file in the browser, so it takes a key or URL, and a local path only when its name carries the key. The MCP server says how file and refresh are read once, in its instructions, as figma-reader help does in its overview; each tool's file and refresh say in a line what they take and point there.
A path (in figma_get_node, figma_locate, figma_dev_status, figma_diff and figma_changes) joins layer names from the page down with /. A name can hold / itself (component naming: 256 names in one real 67 MB export), or end in /, and then splitting the path on / does not give its names back. Exactly then pathIds follows it, the id of each name in it, page first; a path without it splits on / into its names. An id per name on every result would have made those answers 20–53% larger on that export, for the 99.6% of paths that split right.
MCP inputs are strict: every tool's schema is additionalProperties: false, so an unknown argument is an error rather than a silently dropped one. Only the tools that cannot write are published with readOnlyHint: true — the ones taking out_file, out_dir or save_path are not, nor are figma_status and figma_login, which write account state.
MCP results are compact JSON, without the indentation the CLI prints: on a real export that was 17–41% of the bytes of figma_search, figma_get_text, figma_dev_status, figma_diff and figma_get_node answers, which an MCP client, unlike a shell with jq, cannot strip. A text answer (figma_get_tree's outline, CSS, JSON followed by out_file's note) is as the CLI prints it, and a call is refused alike on both: figma_get_node's 200 KB limit is on the indented JSON.
Linking local files to Figma URLs
Name saved copies <anything> [<file key>].fig (the key is the id after /design/ in the URL) and put them under FIGMA_FILES_DIRS:
~/Downloads/My App [AbCdEf1234567890XyZ].figThen a pasted URL such as https://www.figma.com/design/AbCdEf1234567890XyZ/My-App?node-id=8-77 is served from that file offline (newest match wins); node ids are identical. refresh: true ignores local copies and exports the live file, and is answered only by an export that begins after it was asked for, never by one already under way; on a path to a .fig there is nothing to export from, so it is ignored and the result says refreshIgnored: true.
A dated result names the date after what it dates, because the two are not the same claim. exportedAt is the ISO-8601 time this tool exported that snapshot through the browser: report what the design said then rather than as current, and figma_load_file adds source and snapshotAgeMinutes beside it. A .fig the user supplied carries fileModifiedAt instead, that copy's own file time, and no age: copying, syncing or re-downloading the file resets it, so the design data can be older than the field says and nothing here can date it. Beside exportedAt stands account, the Figma account the snapshot was read through (see Accounts); a local .fig carries none. Ten tools date their results — figma_load_file, figma_get_node, figma_locate, figma_search, figma_get_components, figma_dev_status, figma_token_usage, figma_get_text, figma_changes, and figma_get_tree, whose first line is # followed by the same fields as JSON (# {"exportedAt":"…","account":{…}}), with the outline unchanged below it — and figma_diff dates each of its two sides, under old and new. figma_get_variables, figma_get_styles and figma_export_image_fills answer with neither date nor account, since their answer is the data itself (a token file, a stylesheet, the images written), so an answer built on them cannot be dated from the result, nor told apart by account. The one exception is the note out_file adds after the answer of figma_get_variables and figma_get_styles, which is not written to the file: (written to <path>; exportedAt <time>, account "acme" (source: …)), or (written to <path>; fileModifiedAt <time>) for a local .fig. The MCP server states this rule once, in its instructions, as figma-reader help does in its overview; each dated tool's description says only that it is dated and points there.
figma_screenshot always renders the live file and works from a local path only when its name carries the key.
Setup
Install has the one-liners. This section is what each form needs beyond them.
Node 22+ throughout. For web mode, a Chromium-family browser: on Linux the first of Brave, Chromium, Chrome found on PATH, on macOS the same and then Brave, Chromium, Google Chrome or Microsoft Edge in /Applications or ~/Applications, on Windows brave.exe, chrome.exe, chromium.exe or msedge.exe on PATH or in the usual install directories, or whatever FIGMA_BROWSER_PATH names. A browser that cannot start is passed over for the next one, and a confined build (snap, flatpak) is tried only after an ordinary one, since it cannot reach a profile outside its own sandbox. Playwright's "Chrome for Testing" is a last resort because Google sign-in rejects it as insecure.
From a clone, npm link puts figma-reader and figma-reader-mcp on PATH; without it, run node /path/to/figma-reader/dist/cli.js.
CLI
figma-reader help # all commands
figma-reader help get-node # one command's arguments
figma-reader load-file ~/Downloads/app.fig
figma-reader get-tree "https://www.figma.com/design/<key>/App?node-id=8-77" --depth 1
figma-reader search <file> "sign in" --include-text --types TEXT
figma-reader get-variables <file> --format css > tokens.css
figma-reader screenshot <file> --node-id 8:77 --save-path out/login.png
figma-reader locate <file> --node-ids 8:77,8-78,9:12 # which of these ids the file has, and whereArguments are the MCP tool arguments in kebab-case. Required strings are positional (<file>, then <query> or <out_dir>), booleans are bare flags (--refresh, --no-refresh) or take a value (--refresh=false), lists repeat or take commas (--types FRAME,TEXT) and are given empty with --no- in front (--no-exclude-page; an empty --exclude-page= is bad usage, and a list that cannot be empty, such as get-text's --fields, has no --no- form), and --json '{"node_id":"8:77"}' passes raw arguments. -- ends the options, so a query such as --help can follow it. Results go to stdout (pipe JSON into jq), errors to stderr. Exit code 0 is success, 1 a failed call, 2 bad usage. Images go to --save-path or, without it, to a new file in a private per-user temp directory ($TMPDIR/figma-reader-<uid>/, mode 0700), whose path is printed.
Installed from a clone without npm link, run node /path/to/figma-reader/dist/cli.js. The CLI reads the same environment variables as the server (see below).
Each CLI call is its own process, and decodes the .fig (a local file or a cached snapshot) again. That cost grows with the file: a small one answers in a fraction of a second, but every call on a 67 MB export takes 3.4 to 4.7 s, almost all of it decoding, whatever the command asks. A call that needs figma.com also starts the headless browser and loads the editor, so it takes tens of seconds. The browser closes when the call ends, unless an MCP server on the same profile is still using it. The MCP server decodes a file once and keeps it in memory while the file is unchanged (as many files as FIGMA_DECODED_MAX_MB holds), and keeps the browser warm, so for many calls on a large file, or many web calls in a row, use the server rather than the CLI.
figma-reader batch runs many calls in one process instead, so a file is decoded once rather than for every call (each call decodes it again otherwise: about 4 s for a 67 MB export) and web calls share one browser. The process keeps the four files used last decoded, fewer when they are large (as many as FIGMA_DECODED_MAX_MB holds: about two 67 MB exports by default on a machine with 16 GB of RAM, one with 8 GB), and always the one in use, so group calls by file. It reads one call per line of stdin, {"tool": "get-text", "args": {"file": "app.fig", "node_id": "1:2"}}, with the tool as a command or MCP name and the arguments under their MCP names and as JSON values, a list as an array even of one id (figma-reader help batch names every list argument), checked as strictly as a single call's. It writes one JSON line per call, in order: {"i": 0, "ok": true, "result": ...}, where result is what the command alone prints (its JSON as a value, text such as get-tree's outline as a string, and any image written to save_path or a private temp file and listed by path in images), or {"i": 1, "ok": false, "error": "..."}. A line that is not JSON, names no tool or has bad arguments fails alone and the rest still run; login is refused, since it waits for a person. Exit code 0 when every call succeeded, 1 when any failed, 2 for bad usage of batch itself or when any call was refused because no account was chosen (see Accounts): that line holds the refusal, nothing was tried on it, and running the batch again is refused the same way until the account is chosen. On that export, with the machine busy, ten get-text calls took 43–66 s as ten processes and 5–7 s as one batch.
printf '%s\n' \
'{"tool":"locate","args":{"file":"app.fig","node_ids":["1:2","3:4"]}}' \
'{"tool":"get-text","args":{"file":"app.fig","node_id":"1:2"}}' |
figma-reader batch | jq -c .resultFor agents
skills/figma-reader/SKILL.md is a ready-made agent skill that teaches the CLI. Install it into a project with
npx skills add https://github.com/LeoGCode/figma-reader --skill figma-readerwhich writes .agents/skills/figma-reader/ and registers it for Claude Code and the other agents that read that directory. Or copy the directory into .claude/skills/ (project) or ~/.claude/skills/ (user) by hand, or paste SKILL.md into another agent's instructions (AGENTS.md, rules files). SKILL.md stays short, since an agent re-reads it on every turn; every output shape and flag is in references/output.md beside it, which the skill tells the agent to read when it needs one. Agents without a skill can also run figma-reader help.
MCP server, per project
Register it only in the projects that need it (writes .mcp.json in the project root, shareable in git):
cd /path/to/project
claude mcp add --scope project figma-reader -- npx -y @leogcode/figma-reader@latest figma-reader-mcpInstalled globally, -- figma-reader-mcp works instead; from a clone, -- node /path/to/figma-reader/dist/mcp.js.
or add to the project's .mcp.json by hand (Claude Code expands ${VAR}):
{
"mcpServers": {
"figma-reader": {
"command": "npx",
"args": ["-y", "@leogcode/figma-reader@latest", "figma-reader-mcp"],
"env": { "FIGMA_FILES_DIRS": "${PWD}/design:${HOME}/Downloads" }
}
}
}Accounts: one Figma login per project
If different projects need different Figma accounts (a client's workspace, your personal one), give each its own account. An account is a name with its own browser profile, so its own Figma login, and its own cache of exported files. Projects on different accounts never share a session, and a file exported by one account is never served to a project using another.
A project picks its account with a .figma-reader.json in its root, found by walking up from the working directory:
cd ~/work/acme-app
figma-reader use acme # writes .figma-reader.json: { "account": "acme" }
figma-reader login # opens a browser window to sign "acme" into Figma, once
figma-reader accounts # every account, its login and email, and which one this directory usesThe same file serves the CLI and the MCP server: Claude Code and most MCP clients start the server in the project directory, so no extra MCP configuration is needed. The account is fixed when the server starts; after changing it, restart the server (in Claude Code, /mcp). figma_status reports the account in use and where the choice came from.
An answer that came through figma.com or the account's snapshot cache says which account it was, as "account": { "name": "acme", "source": "/home/me/work/acme-app/.figma-reader.json" }, where source is FIGMA_ACCOUNT (which --account sets), the project file, or default when nothing chose one, plus profileOverride when FIGMA_USER_DATA_DIR or FIGMA_CDP_URL supplies the login. That field is in the JSON of figma_load_file, figma_get_node, figma_locate, figma_search, figma_get_components, figma_dev_status, figma_token_usage, figma_get_text and figma_changes given a key or URL, on each side of figma_diff read through the account (previous included), of figma_list_files with source: "web", and of figma_status and figma_login; figma_get_tree carries it in its header line, and the text of figma_screenshot's note and of figma_login's messages ends with or names account "acme" (source: …). figma_get_variables, figma_get_styles and figma_export_image_fills do not carry it: their answer is the artifact itself (a token file, a stylesheet, the list of images written) and stays exactly that, except in the (written to …) note out_file prints after it, which names the account and is not written to the file. The check below guards them all the same, so none of them reads through a default nothing chose. Once a call has passed that check, any error it ends in names the account too, as [account "acme" (source: …)] at the end, whether figma.com raised it or it came later (a node missing from a cached snapshot); figma_status reports its errors inside its answer instead. An answer read from a local .fig, by its path or by a key that a local <name> [<key>].fig serves, names no account, and neither does an error it ends in, since no account takes part in reading it.
Which account applies, first match wins:
--account <name>on any CLI commandFIGMA_ACCOUNT, e.g. in the MCP server'senvfor clients that do not start servers in the project directoryaccountin the nearest.figma-reader.jsondefault, unless other accounts exist (below)
default is only a fallback, and with other accounts in <data>/accounts/ it is a guess: run from a directory outside the project, a call would read the project's files through whichever login was set up first. So when nothing chose an account and others exist, any call that needs figma.com or the snapshot cache (a file key or URL, either side of diff and diff previous included, screenshot, login, list-files --source web, and each such line of a batch) fails before touching either, and before reading any other file it was given, saying where no project file was found and which accounts exist; the CLI exits 2, as for bad usage. The call is refused the same way, naming the error, when <data>/accounts/ is there but cannot be read (permissions, I/O): that proves nothing about whether other accounts exist. A chosen account never reads it. Run it from the project's directory, or pass --account <name> / set FIGMA_ACCOUNT; --account default (FIGMA_ACCOUNT=default) is the explicit way to use default. An MCP server resolves its account once, when it starts, so its tools say to set FIGMA_ACCOUNT in the server's env or start it in the project directory, then restart it. Local .fig files (by path, or by a key a local <name> [<key>].fig serves without refresh), status (which reports the refusal as webCallsRefused), accounts, use and help work from any directory. With default the only account, or a login named by FIGMA_USER_DATA_DIR or FIGMA_CDP_URL, nothing is refused.
.figma-reader.json can also set the project's .fig folders; relative paths resolve against the file's directory:
{ "account": "acme", "filesDirs": ["design", "~/Downloads"] }It can also name the pages figma_search, figma_diff and figma_changes skip by default, such as archives and templates whose hits or changes would otherwise fill the limit: "excludePages": ["Archive", "Templates"]. A name a file does not have is ignored for that file. A call that gives exclude_pages, page or (for search) a node_id other than the document's own is not affected, exclude_pages: [] (on the CLI, --no-exclude-page) covers every page, and an answer that skipped any names them in excludedPages. Only those three read it: figma_get_text (which takes exclude_pages from the call alone) and figma_token_usage on a whole file still cover every page.
Only the nearest file applies; files further up are not merged in. So figma-reader use in a subdirectory of a project that already has a .figma-reader.json writes a new file there that starts as a copy of the project's other settings (relative filesDirs rebased), so only the account changes for that subdirectory, and says which file it copied. Later edits to the project's file do not reach the subdirectory.
Commit it if your team uses the same account names, or add it to .gitignore (or .git/info/exclude) to keep it to yourself.
Account data lives in <data>/accounts/<name>/ (profile, last verified email) and <cache>/accounts/<name>/ (snapshots, under $FIGMA_READER_CACHE/accounts/<name>/ when that is set). Delete those two directories to remove an account. The three roots are the ones the platform itself keeps such files in:
Linux, macOS | Windows | |
|
|
|
|
|
|
|
|
|
macOS keeps the Linux paths rather than ~/Library: they work there, and moving them would leave every account logged in somewhere the tool no longer looks.
On macOS a browser encrypts its saved logins with a key from the login Keychain, which a session over SSH (or a job outside the desktop session) cannot reach: there the login window would take the sign-in and save nothing. So each account's profile settles once where its key lives, and keeps it (in figma-reader-key-store inside the profile). A profile first signed in from a terminal on the Mac uses the Keychain like any browser there. One first signed in where the Keychain is out of reach uses Chromium's mock keychain (--use-mock-keychain, as Playwright launches Chromium on a Mac), so its login is protected by the profile directory's permissions alone, and it works from either session. A profile whose login is in the Keychain, used over SSH, fails saying so rather than opening login windows that cannot save: run it from a terminal on the Mac, or security unlock-keychain in that session first. A FIGMA_USER_DATA_DIR profile always keeps the Keychain.
Account names are compared the way the filesystem compares them, so acme and Acme are two accounts on Linux and one on Windows and macOS.
help, and reading a local .fig with any command but screenshot, write to none of them, and nowhere else but the files asked for (--out-file, the directory given to export-image-fills): <state> and <cache> are first written by a call that goes through the browser (an export, any screenshot, list-files --source web, login, status), so local reads work in a read-only sandbox, CI job or container. Such a call that may not write <state> where it registers with the browser, or an export that may not create, in <cache>, the empty file its download is then moved onto, fails there (exit 1), before the browser is asked to export anything, saying what needed which directory, with the system's error and its code (EROFS, EACCES, EPERM), and what reads without writing. So do its later writes in <state> (the browser's record, the lease it holds while it works in the browser), status and login where they cannot record the account's user in account.json under <data> (status fails then, rather than call a login it has just checked unknown), and an image given no --save-path where the temp directory takes no file.
Browser and login
Mode | Set | Behavior |
Managed (default) | nothing | Launches the detected browser headless on the account's profile, |
Managed, own browser/profile |
| Same, with that executable and profile (an existing logged-in profile skips the login step) |
Attached |
| Uses a browser you started with |
Login flow (managed): the first web call checks the session cookies. If the profile is not logged in, the headless browser is closed and the same profile opens in a normal visible window on figma.com/login, with no DevTools port (Google and others refuse sign-in in remotely controlled browsers). Log in and retry: once Figma's auth cookie shows up in the profile's cookie DB (read-only, no DevTools needed) the window is closed gracefully and the login is verified headless; if verification fails the login window reopens. On Windows the browser keeps that file locked while it runs, so there the cue is the window reaching Figma's file browser after the sign-in, read from a copy of the profile's history (about 10 s behind); the window is asked to close as its close button would, so the browser writes its cookies first, and one that does not close is left for you to close. figma_login with wait_seconds blocks until then. The login persists in the profile.
Tabs the profile would reopen are dropped before each launch (Brave restores the last session by default), so neither the work browser nor the login window comes up with Figma tabs left by earlier runs. The login is untouched: it lives in the cookies, not the session. A profile named by FIGMA_USER_DATA_DIR keeps its tabs, since it may be one you browse with.
Headless needs two workarounds, applied automatically: the user agent's HeadlessChrome is rewritten (CloudFront answers 403 otherwise) and focus is emulated (Figma ignores shortcuts without it).
A managed browser is shared by all servers and CLI calls using the same profile (found via Chromium's DevToolsActivePort) and closed when the last of them exits. A profile can be open in only one browser process: if you have it open normally (without a DevTools port) the server reports it instead of launching.
Env | Default | |
| from | Account: which Figma login and snapshot cache to use |
|
| Dirs scanned (2 levels) for |
| Brave › Chromium › Chrome › Playwright | Browser executable |
|
| Browser profile holding the Figma login (one per browser: cookie keys differ). Without an account set, a custom profile gets its own cache |
|
|
|
| unset | Attach to a running browser instead of launching |
|
| Root of the snapshot cache ( |
|
| Re-export after this age (or pass |
| half of Node's heap limit (about 2 GB with 16 GB of RAM or more) | Memory the decoded files one process keeps between calls (a |
Concurrency
Each server process uses its own editor tab, marked with its pid; tabs of exited servers are reused. Calls within one server run one at a time on that tab; separate agents run in parallel on separate tabs, and concurrent exports share the browser-wide download setting safely (per-frame download matching plus lease files, in a directory named after the profile so that processes given different caches still agree on it). Processes sharing a cache also wait for each other's export of a file rather than each exporting it. What a crashed export left in the cache is swept by the next call that reaches the browser, except a file whose owner's lease is still live: an export being decoded, or a diff previous reading its pair. So is a lock directory a crash left with nobody holding it. Each editor tab costs hundreds of MB to over a GB of RAM. In a visible browser (attached or FIGMA_HEADLESS=0) keep the windows un-minimized: hidden tabs stop rendering and Copy as PNG never fires.
node scripts/concurrency.ts <key> <nodeA> <nodeB> same|multi and node scripts/concurrency.ts x <keyA> <keyB> export exercise the concurrent paths. node scripts/call.ts lists the MCP tools; node scripts/call.ts <tool> '<json>' calls one.
npm test typechecks src/, test/ and scripts/, then runs the unit tests. Tests and scripts run straight from the TypeScript source with Node's built-in type stripping (Node 22.18+), so they need no build; src/ sticks to erasable syntax (no enums or constructor parameter properties) to keep that working. npm run build compiles src/ to dist/ for the published commands.
Unit tests build their scene graphs in code (test/fixtures.ts), since real design files cannot be published, plus two real exports made for this purpose and holding no design work. test/files/real-export.fig (35 KB) pins what the format actually looks like: bindings recorded in parameterConsumptionMap, a property value an enclosing instance sets on a nested one, and an opacity variable of 50 driving a layer at 0.5. test/files/dev-status-export.fig (32 KB, from a Free plan draft) pins what the editor writes for Dev Mode status: four frames marked Ready for dev, Completed, ready then removed, and never. Coded fixtures encode what we believe the format is; these fail when the belief is wrong. To check changes against real files you have, run npm run corpus -- <file.fig | dir>... (or set FIGMA_CORPUS_DIR): it decodes each file and runs it through outline, instance-text, normalize, tokens (variables, their CSS and DTCG, styles and their CSS), component-usage, token-usage and dev-status (with annotations and measurements). It checks that no step throws, and these invariants: no two text items share an id, and no unresolved id repeats for the same reason; every instance layer's text is as long as what Figma last rendered for it, and no layer an instance still renders is left neither answered nor reported as unresolved — derivedSymbolData is Figma's last layout and is never pruned, so entries for layers an instance has since stopped showing are excused; no property definition without a name; no duplicate CSS custom property in :root, no var() reference to a name nothing declares, and none in :root to a name declared only in a mode block; every collection with variables has a mode; no DTCG collections merged into another, every {a.b.c} reference naming a token with a value, no token dropped by a name collision or nested inside another; every component use naming a component the file holds, none recorded on a soft-deleted or superseded instance and none naming a superseded copy, one use per instance of a component, an instance's swaps at least the distinct (path, property) pairs it sets — two properties set to one component are two uses — and at most the swap records it holds, and the per-component totals adding up to the uses; every colour a hex value, every typography entry carrying typography and none reported twice, every count a positive whole number, every text node walked accounted for by a typography count or by textWithoutTypography with that counter holding exactly the text that records none, and no value counted more often with hidden layers skipped than with them included; every Dev Mode status a value this decoder has a name for, no node marked only through the bare sectionStatus field it does not read, no annotation label using markup the markdown conversion does not know, and every measurement naming a target. It prints counts only, never design content, among them keyIdCollisions, the guids one layer uses as an override key and another as a node id, and instancesGone/supersededComponents, which say whether the file has anything for the two skips above to decide about. Add --save base.json before a change and --compare base.json after it to see what moved. Snapshots exported through the browser are under the account's own <cache>/accounts/<account>/ (see Accounts).
For behaviour on real files, keep private tests in test/private/ (gitignored) and run them with npm run test:private, which fails when that directory holds no tests, since a green step that ran nothing proves nothing (FIGMA_PRIVATE_OPTIONAL=1 skips it instead, and also skips the tests whose pinned file is missing). Check expectations against what Figma renders (a figma-reader screenshot of the frame), not against the tool's own output. Pin copies of the files there too rather than pointing at the export cache, which is overwritten on refresh. node:test snapshots (t.assert.snapshot, accepted with npm run test:private:update) can then catch any change in output, for you to review.
Limits
Relies on figma.com internals (Quick actions
data-testid="save-as",_fullscreen_.isReady,/api/recent_files). Breaks if Figma changes them. The Quick actions box itself is recognised by any of three signals — its placeholder or aria-label text, its CSS-module class name, or an ancestor[data-testid*="quick-action"]— none of which has been verified against the live product. If none match,saveLocalCopyfails closed with a diagnostic naming the focused element, rather than typing the query into whatever field happens to have focus.Files whose owner disabled copying/exporting cannot be saved locally.
A collapsed instance's contents are not stored in the
.fig; they are derived from its main component plus overrides.figma_get_textandfigma_searchdo that derivation (text overrides and properties, boolean properties that show or hide layers, instance swaps, and properties set on nested instances), tagging each string withvia(direct/instance), its component, variant and enclosing frame, and counting anything they could not resolve asunresolvedInstances.figma_get_nodeandfigma_get_treestill do not expand instances: they report the main component, variant and property values instead.Layer names inside a collapsed instance are likewise not in the file, so
figma_searchcannot match them; search the main component.Library variables/styles/components appear only when the file uses them (Figma copies them in); they are flagged
remote/fromLibrary.Dev Mode status is read from each node's own record. Each page also keeps an index of the statuses on it, which goes stale (entries for deleted nodes, previous statuses that disagree with the node) and is not used.
BUILDis Ready for dev andCOMPLETEDis Completed, as frames marked in the editor and exported again show;rawis still reported besidestatus, for a value Figma adds later.byis a Figma user id: the export carries no names. Annotation labels are stored as HTML and returned as markdown; a measurement stores its two nodes and sides, not the distance.Token export (
figma_get_variables,figma_get_styles):CSS numbers are
px, except variables scoped to font weight or font axes (unitless) and opacity (Figma's 0-100 written as 0-1).DTCG aliases reference the full token path
{Collection.Mode.path}; an alias into another collection uses that collection's default mode, as Figma does. An alias to a library variable the file has no copy of becomes a CSS comment, or a DTCG node with$extensions["com.figma"].aliasOfand neither$valuenor$type: a token is an object with a$valueand a group is one without, so what has no value is left as the group it is rather than as a token consumers split between dropping and erroring on.Names are unique: collections, modes and styles sharing a name are numbered (
colors-2,Colors 2). Withcollectionorinclude_remote: falsethe names stay those of the full export, and an alias into a collection left out is written as its resolved value.Soft-deleted styles and older copies of an updated library variable or style are left out. Stacked fills are composited (or layered when they cannot be), and gradient angles are approximate on non-square layers.
Selecting a different node for a screenshot reloads the editor tab (a few seconds).
Available Tools
18 toolsfigma_changesARead-only
Top-level layers created or edited since a date or duration, from Figma's edit times per node. A top-level layer is a page's child or a child of its sections, rolled up from everything under it: lastEditedAt is the newest time in it, editedNodes how many of its nodes were created or edited at or after since, created whether the layer itself was; page and path say where it is. Newest first; the editedNodes beside the list counts each such node once. This is edit metadata from one snapshot: it shows nothing deleted (figma_diff lists removals) and never what an edit was, only when. A node that records no time counts only where Figma also moved an ancestor's; undatedNodes counts those, and text layers are among them in every export seen. byPage counts each page's layers and editedNodes, every page counted, excluded ones too; page or exclude_pages (default: the project's excludePages, echoed as excludedPages) narrow the list and its counts before the limit, which is shared between pages so one page cannot crowd out the rest. Where path does not split on ' / ' into its names, pathIds follows it: one id per name, page first. Dated by exportedAt and account, or fileModifiedAt for a file read from disk, as the server's instructions say (figma-reader help on the command line).
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes | A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help) | |
| page | No | Only layers on this page; a name no page has is an error listing the pages | |
| limit | No | Default 50 | |
| since | Yes | An ISO-8601 date (2026-10-01, midnight UTC) or date and time (2026-10-01T09:30:00Z; local time without an offset), or a duration back from now: 30m, 12h, 7d, 2w. The result's since is the instant it was read as | |
| refresh | No | Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help) | |
| exclude_pages | No | Pages to leave out, by name, before the limit: their changes neither fill a list nor count in counts, and byPage still counts them. Default: excludePages in the project's .figma-reader.json, unless page is given; an empty list covers every page |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint/openWorldHint; the description goes well beyond them, disclosing that results are a single-snapshot edit view that shows nothing deleted and never reveals what an edit was, only when. It also explains rolling-up semantics, undated-node handling, shared limit behavior across pages, and count-scoping rules for page/exclude_pages.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded, but the definition is one dense block of unusually long clauses mixing result-field semantics, counting rules, and repeated pointers to 'the server's instructions (figma-reader help)' that appear three times. Almost every sentence carries information, yet the packing makes key constraints hard to extract.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the output burden and largely does so, naming lastEditedAt, editedNodes, created, page, path, pathIds, undatedNodes, byPage, and excludedPages. Residual gaps remain around exact shapes of byPage/pathIds entries, but an agent has enough to call it and interpret results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% so the baseline is 3, but the description adds real meaning: the returned 'since' is the instant the value was read as, exclude_pages defaults to the project's excludePages and is echoed as excludedPages, and the limit is shared across pages so one page cannot crowd out others. It also clarifies page/path/pathIds interplay beyond the schema's text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource+scope: 'Top-level layers created or edited since a date or duration, from Figma's edit times per node.' It then defines what a top-level layer is and explicitly distinguishes itself from the sibling figma_diff ('figma_diff lists removals'). An agent can tell this apart from figma_search or figma_get_tree without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States its operating context clearly (edit metadata from one snapshot, since a date/duration) and routes deletions to figma_diff. It does not, however, state when to prefer it over options like figma_search or figma_diff for non-removal history, so the when-not side is only partially covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
figma_dev_statusARead-only
Dev Mode status: the nodes marked Ready for dev or Completed, and those unmarked since, newest change first. Read off each frame's, section's or component's own status record; each entry has id, type, name, page, path and the fields figma_get_node reports as devStatus: status (ready_for_dev, completed, none, or unknown for a value this decoder has no name for), raw (the value Figma stores: BUILD for Ready for dev, COMPLETED for Completed), previous and previousRaw, changedAt (ISO-8601), and by (a Figma user id) and note when the record has them. status none with a previous status other than none is a mark that came off at changedAt; none with previous none is a record Figma keeps on a node never marked, listed only with status none or any unless a user or note on it says a person left it. With no status given, neverMarked counts those records the listing left out (absent when it left none out); status any lists them. Internal-only pages, soft-deleted nodes and superseded library copies are left out. Where path does not split on ' / ' into its names, pathIds follows it: one id per name, page first. Dated by exportedAt and account, or fileModifiedAt for a file read from disk, as the server's instructions say (figma-reader help on the command line).
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes | A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help) | |
| page | No | Only nodes on this page; a name no page has is an error listing the pages | |
| limit | No | Default 100 | |
| status | No | Only this status: none covers marks that came off as well as records that never said anything else, and any is every record. Default: every node marked now or before (status or previous other than none), and any record with a user or note on it | |
| refresh | No | Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint and openWorldHint, so the description carries real weight and delivers it: ordering (newest change first), exclusions (internal pages, soft-deleted nodes, superseded library copies), default inclusion semantics, neverMarked accounting, and how dating works (exportedAt/account, or fileModifiedAt for a disk read). It adds substantive behavior beyond the safety hints, though the 'see the server's instructions' deferrals are gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded, and the text is information-dense with little filler, but it is a single 130-word paragraph of nested clauses and parentheticals with no structural separation of usage, output fields or constraints, making it hard to scan. Size is large for a 5-parameter tool but mostly load-bearing rather than redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description takes on return-shape disclosure and enumerates the entry fields (id, type, name, page, path, pathIds, status, raw, previous, previousRaw, changedAt, by, note, neverMarked) plus the exception cases. It is largely complete, but key mechanics such as pagination/limit behavior and refresh/caching semantics are outsourced to external docs rather than explained.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description restates status semantics that the schema's own status description already covers ('none' marks that came off, 'any' is every record, default listing rule), adding only marginal clarification of how 'none' interacts with a prior 'previous' value; it does not document limit, page-exclusion or refresh beyond what the schema says.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening clause names a specific resource and scope: nodes marked Ready for dev or Completed plus those unmarked since, ordered newest change first, and it points at each node's own status record (contrasting with figma_get_node's devStatus view). The verb is implicit rather than stated (it never says 'list'), and the dense clause structure blurs the statement, but an agent can still identify the resource and its filter behavior.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Scope rules are given (internal-only pages, soft-deleted nodes and superseded library copies are left out; default listing covers nodes marked now or before), and figma_get_node is referenced as the per-node alternative. However there is no explicit when-to-use-this-instead-of guidance versus figma_changes, figma_diff or figma_get_node, and operational details are deferred to 'figma-reader help' rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
figma_diffARead-only
Compare two snapshots of one file by node id. Figma keeps a node's id through renames and moves, so the id says what is the same layer: pages added, removed or renamed; top-level layers (a page's children, and the children of its sections) added, removed, renamed (same id, other name) or moved (same id, other parent, so a move to another page shows in from.page/to.page; a layer carried inside a moved section keeps its parent and is not listed); and removedNodes, the topmost node of each subtree gone from the visible pages, with the page and path it had and removedCount, how many nodes went with it (itself included); figma_locate on old and new answers for any id under it. Only ids, names and parents are compared: an edit to text, fills, sizes or any other property is reported nowhere. byPage counts each page's added, removed, renamed, moved (moved in; movedOut, moved from it to another page) and removedNodes, every page counted, excluded ones too: read it, then pass page for the one you need. page or exclude_pages (default: the project's excludePages, echoed as excludedPages) narrow the lists before the limit. Every list stops at limit, shared between the pages it covers so a page with many changes cannot crowd out the rest; counts has each total, and truncated says whether any list was cut. A node created and deleted between the two snapshots is in neither. old may be the word previous: the snapshot this account's cache held for new's key before its latest export (one per key, kept by every export that replaces a snapshot). new is then read from that cache, never from a local copy, and refresh exports it again first, which keeps the snapshot it replaces as previous: so 'previous ' with refresh compares the last export with the live file. old and new are each dated, as the server's instructions say: report the changes as between those two times. Where path does not split on ' / ' into its names, pathIds follows it: one id per name, page first.
| Name | Required | Description | Default |
|---|---|---|---|
| new | Yes | The newer file: a .fig path, file key or figma.com URL; a key or URL when old is previous. A node-id in a URL is ignored | |
| old | Yes | The older file: a .fig path, file key or figma.com URL, or the word previous for the snapshot that new's latest export replaced | |
| page | No | Only changes on this page, by its name in either file; a name neither has is an error listing the pages | |
| limit | No | Most entries in each list (default 100) | |
| refresh | No | Export new again through the browser first (old is never refreshed). Has no effect when new is a path to a .fig, and the result's new carries refreshIgnored | |
| exclude_pages | No | Pages to leave out, by name, before the limit: their changes neither fill a list nor count in counts, and byPage still counts them. Default: excludePages in the project's .figma-reader.json, unless page is given; an empty list covers every page |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes far beyond the readOnlyHint/openWorldHint annotations: it discloses exactly which attributes are compared (ids, names, parents) and which are ignored, how moves surface in from.page/to.page, that a node created and deleted between snapshots is in neither, how 'previous' is cached, and that refresh is ignored for .fig paths. This is unusually thorough behavioral disclosure for a read-only tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose, but then collapses into a very long, heavily parenthesized wall of text with no paragraph or list structure, making it hard to scan. Most clauses carry genuine information, but the run-on structure hurts usability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by describing the return shape thoroughly: byPage fields (added, removed, renamed, movedIn/movedOut, removedNodes), counts and truncated, removedNodes with page/path/removedCount, and pathIds. An agent has enough to interpret results and call the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the baseline is 3, but the description adds real meaning beyond the schema: limit is shared across the covered pages so one page cannot crowd out others, exclude_pages applies before the limit, and refresh only affects new. These clarify interactions the parameter descriptions alone don't fully convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Compare two snapshots of one file by node id') and immediately scopes it precisely: pages added/removed/renamed, top-level layers changed, and removedNodes subtrees. It explicitly says property edits (text, fills, sizes) are reported nowhere, so an agent can distinguish this diff tool from siblings like figma_changes and figma_locate.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives rich conditional guidance: when to pass page vs exclude_pages, what default exclude_pages applies, and when old='previous' is meaningful. It points to figma_locate for resolving any id, but never explicitly contrasts this tool with figma_changes, leaving that alternative comparison to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
figma_export_image_fillsA
Write the original image assets (photos, bitmaps) a node or the whole file uses, in a fill or a stroke paint, to a directory. Answers with an array, one entry per distinct image: hash, the path written, its size in bytes, and up to five of the layers using it (with usedByTotal when there are more). An image whose bytes this export does not carry is reported as {hash, missing: true} and nothing is written for it.
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes | A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help) | |
| node_id | No | ||
| out_dir | Yes | Directory to write the images into, created if it is missing. A relative path is resolved against this process's working directory, which for an MCP server is wherever the client started it | |
| refresh | No | Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and openWorldHint=true, and the description goes further by disclosing write behavior (files land in out_dir), partial-failure handling (missing bytes reported as {hash, missing: true} with nothing written), and the per-image result shape including usedByTotal and the five-layer cap. It omits overwrite behavior and auth/rate-limit context, so it is strong but not exhaustive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tightly packed sentences: the action is front-loaded, then the return contract. Every clause (hash, path, size, layer sample, usedByTotal, missing marker) carries information an agent needs absent an output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description fully carries the return-value burden and does so well, and it covers the write/partial-failure semantics. It stops short on overwrite behavior for existing files and any permission or refresh-cost considerations for a tool that re-exports the live file.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 75%, so most parameters are already documented in the schema. The description only adds the node-vs-whole-file distinction for node_id; it does not clarify the effect of refresh or how out_dir interacts with repeated exports. Baseline adequacy, no extra value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource: writing the original image assets used by a node or whole file in fill/stroke paints to a directory. This clearly separates it from rendering-oriented siblings like figma_screenshot and content readers like figma_get_text or figma_get_node.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The scope ('a node or the whole file', 'fill or a stroke paint') implies when the tool is applicable, but there is no explicit when-to-use vs. when-not, no naming of alternatives such as figma_screenshot, and no prerequisite guidance. Usage is inferable rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
figma_get_componentsARead-only
The components this file defines, and the library components it uses. componentSets are the variant sets, with their description, property definitions and one entry per variant carrying that variant's counts; components are the ones outside a set, each with a size and its own counts. A count is instances placed directly, plus swapInstances where the component is swapped into an instance (by an override or an instance-swap property). libraryComponentsUsed is a third list: components defined in other files, by name, with the variants used and the same two counts. Internal-only pages are left out of all three lists but not out of the counts: an instance placed on one still counts for the component it is of, except for a library component, whose uses on such a page are skipped. Dated by exportedAt and account, or fileModifiedAt for a file read from disk, as the server's instructions say (figma-reader help on the command line).
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes | A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help) | |
| query | No | Case-insensitive filter on name; a component set matches when the set or any of its variants does | |
| refresh | No | Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With readOnlyHint=true already covering the safety profile, the description adds genuinely non-obvious behavior: exactly what a 'count' means (direct placements plus swapInstances), how internal-only pages are excluded from the lists but not from the counts, and the exception for library components on those pages. It also discloses how results are dated (exportedAt/account, or fileModifiedAt for disk reads).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is front-loaded with the resource definition, but the middle is dense and hard to parse, packing count semantics, page exclusions and a nested exception into single sprawling sentences. The final dating sentence is convoluted and defers to external docs rather than stating the rule, costing clarity for a paragraph that should be tighter.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of explaining the return shape, and it does so thoroughly for all three lists plus count semantics and exclusions. What is missing is any usage/routing context against the many sibling read tools, and the dating sentence is incompletely specified in-place.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so file, query and refresh are already fully documented in the schema (including query's case-insensitive set/variant matching rule). The description adds nothing parameter-specific, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific resource and scope: the components a file defines plus the library components it uses. It then breaks that resource into three named lists (componentSets, components, libraryComponentsUsed), which unambiguously separates it from siblings like figma_get_styles, figma_get_variables and figma_get_tree.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance, no mention of when to prefer this over figma_get_tree/figma_get_node, and no statement of prerequisites or the effect of the refresh/query parameters on workflow choice. The only routing hints are indirect references to 'the server's instructions', which push guidance out of the description entirely.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
figma_get_nodeARead-only
Detailed design data for a node and its subtree: geometry, fills/strokes/effects (hex), auto-layout, text styling and runs, component/instance info, bound variables and style names. Instances are not expanded (see mainComponentId). Dev Mode's handoff data where a node has it: devStatus as figma_dev_status describes it, annotations (label as markdown, category, the properties pinned) and measurements (from/to node ids and sides; the distance itself is not stored). devStatus is absent on a node never marked: a record that is none and was none, with no user or note on it, is one Figma keeps on components nobody marked, and only figma_dev_status with status none or any lists it. Where path does not split on ' / ' into its names, pathIds follows it: one id per name, page first. Dated by exportedAt and account, or fileModifiedAt for a file read from disk, as the server's instructions say (figma-reader help on the command line).
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes | A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help) | |
| depth | No | Child levels to include (default 3) | |
| node_id | No | ||
| refresh | No | Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With readOnlyHint=true and openWorldHint=true already covering the safety profile, the description still adds substantive behavior: instances are not expanded ('see mainComponentId'), devStatus is absent on unmarked nodes, and path/pathIds handling when the path does not split on ' / '. That is genuine context beyond the annotations, though the devStatus paragraph is so convoluted that its practical value is partly lost.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The content is substantive but the structure is weak: it opens with return data instead of the action, uses tangled clauses ('a record that is none and was none, with no user or note on it...'), and repeats the pointer '(see the server's instructions, or figma-reader help)' three times across description and schema. Dense but not tightly front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must carry return-shape information — and it does, enumerating geometry, fills, text runs, component info, bound variables, dev-mode annotations, measurements, and dating fields. For a 4-parameter reader it is nearly complete, missing only the node_id semantics and any pagination/size caveats.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 75% (file, depth, refresh documented; node_id is not). The description adds no syntax or format detail for any parameter — it discusses output fields (mainComponentId, pathIds, exportedAt) rather than inputs. Baseline 3 is appropriate given the schema carries most parameter meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource and its payload explicitly: 'Detailed design data for a node and its subtree: geometry, fills/strokes/effects (hex), auto-layout, text styling and runs, component/instance info, bound variables and style names.' That is far more specific than a bare 'get node' and lets an agent know it returns deep per-node data. It never names a sibling to distinguish itself (e.g. figma_get_tree, figma_get_text), so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is largely implied by the payload list rather than stated. There is one routing hint — devStatus details are covered by figma_dev_status — but no explicit when-to-use/when-not or comparison against the many sibling readers (figma_get_tree, figma_get_text, figma_get_components). An agent must infer the choice from the return-data description.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
figma_get_stylesB
Local (and imported library) styles with their values: FILL (color), STROKE, TEXT, EFFECT and GRID. Formats: json (default) or css. A file with no styles, or none of the type asked for, answers empty in that format.
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes | A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help) | |
| type | No | Only styles of this type | |
| format | No | ||
| refresh | No | Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help) | |
| out_file | No | Also write the result to this path. The answer then ends with a note, not written to the file: '(written to <path>; exportedAt <time>, account "<name>" (source: <source>))', or '(written to <path>; fileModifiedAt <time>)' for a local .fig | |
| css_prefix | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds real behavioral context beyond the annotations: json is the default format, css is an alternative, and a file with no styles (or none of the requested type) returns an empty result in the chosen format. It does not explain that out_file writes to disk, which is what justifies readOnlyHint=false, but the added format/empty-result semantics are substantive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the resource and its scope, followed by formats and then the empty-result edge case. Only the final empty-result sentence is slightly convoluted, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 6-parameter read tool with no output schema, the description covers style types, output formats and the empty case, but leaves refresh, out_file side effects and css_prefix unexplained and does not describe the shape of the returned values beyond 'with their values'.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 67%. The description restates the type enum values and adds the json default for format, but says nothing about file, refresh, out_file, or css_prefix. With the schema already documenting most parameters, this is a baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: retrieve styles with their values, and enumerates the style kinds (FILL, STROKE, TEXT, EFFECT, GRID). This is distinguishable from siblings like figma_get_variables or figma_get_components by resource type, though it never names them explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clarifies scope ('local and imported library styles') but gives no when-to-use guidance or alternatives. It never tells the agent when to reach for figma_get_styles versus figma_get_variables or figma_get_components.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
figma_get_textARead-only
All text content under a node (or the whole file) in reading order, with node ids. Component instances are expanded, so strings that only exist as instance overrides or component property values are included, each tagged with via (direct/instance) and, where they apply, its component, variant and enclosing frame. A field that does not apply is absent: text on the canvas has no component. Hidden layers are excluded unless include_hidden. The result always reports total/truncated/unresolvedInstances: a non-zero unresolvedInstances means text is missing, at that many places; unresolved lists each missing component once, with its count and some of those places, the most common first, and unresolvedComponentsOmitted counts the components past that listing. Without page, or a node_id other than the document's own (0:0), it reads every page but exclude_pages (never the project's excludePages) and shares limit between them, so one cannot crowd out the rest; byPage gives each page's returned and total: pass page for one cut short. Dated by exportedAt and account, or fileModifiedAt for a file read from disk, as the server's instructions say (figma-reader help on the command line).
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes | A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help) | |
| page | No | Only text on this page, by name | |
| limit | No | Default 500 | |
| fields | No | Keys to keep in each item, of id, name, text, via, component, variant, frame (default all) | |
| node_id | No | Only the text under this node, like 12:34 (or 12-34); the document's own id (0:0) is the whole file | |
| refresh | No | Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help) | |
| exclude_pages | No | Pages to leave out, by name (default none) | |
| include_hidden | No | Include layers hidden in the design (default false) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Far exceeds the readOnlyHint/openWorldHint annotations: it discloses hidden-layer exclusion, component-instance expansion with via/component/variant tagging, truncation and unresolvedInstances semantics (including unresolvedComponentsOmitted), and how limit is shared across pages. This is unusually rich behavioral disclosure with no contradiction of the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded, but the rest is a dense run-on wall of clauses with parenthetical asides and two deferrals to 'the server's instructions / figma-reader help'. Every fact is relevant, yet it is not scannable and would benefit from sentence breaks or bullets.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return-shape burden and does so: total/truncated/unresolvedInstances, byPage returned/total, and per-item tagged fields are all described. Auth/refresh prerequisites are only gestured at via 'the server's instructions', which keeps it from a 5.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description genuinely adds meaning: exclude_pages is explicitly 'never the project's excludePages', limit is shared between pages so 'one cannot crowd out the rest', and the fields keys map to the per-item output. It stops short of explaining refresh/date semantics fully, deferring to 'the server's instructions'.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening clause states a specific verb+resource+scope: 'All text content under a node (or the whole file) in reading order, with node ids.' That is enough to separate it from figma_get_tree or figma_get_node, though it never names a sibling as the alternative, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It spells out how the scoping parameters behave (page vs node_id vs whole file, exclude_pages handling) but never says when to reach for this tool rather than figma_search, figma_locate or figma_get_node for the same question. Usage is implied by the scoping rules rather than stated as guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
figma_get_treeARead-only
Compact outline of the layer tree (id, type, name, size, hints such as ready for dev). Omit node_id for all pages. The first line is a header, '# ' followed by a JSON object holding its date (see below); the outline starts on the second line. max_nodes goes to one level before the next (pages, then top-level layers, then what is under them), so a large first section cannot crowd out later pages. A branch cut short ends in a '- ... N more children' line, a layer whose children were all left out says '(N children)', and the last line says it was truncated; when a level could not give each of its layers one line, it is left out whole and the last line says so instead: 'level 2 not shown: 40 layers have children, 30 of 400 lines left; open one with node_id, or pass max_nodes 450' (levels counted as depth counts them). A layer drawn only with vector shapes, however they are grouped, is one line counting them all, '(27 vectors)': pass its node_id to open it. Dated by exportedAt and account, or fileModifiedAt for a file read from disk, as the server's instructions say (figma-reader help on the command line).
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes | A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help) | |
| depth | No | Levels of children below the start node (default 2). With no node_id the start is the document, whose pages are level 0, so the default shows three: pages, their top-level layers, and one level under those | |
| node_id | No | Start node id like 12:34 (or 12-34) | |
| refresh | No | Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help) | |
| max_nodes | No | Lines to spend (default 400), a level at a time: a level that does not fit is shared evenly between its parents, and the levels under it are not shown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint/openWorldHint, yet the description discloses a great deal more: the header line format and its dating source, the exact truncation markers ('- ... N more children', '(N children)'), the level-dropping message with a worked example, and the vector-collapsing rule. This is unusually rich output-shape disclosure for a read-only tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is front-loaded and information-dense, but the truncation and dating sentences are tangled run-ons, and it defers to external material ('as the server's instructions say (figma-reader help on the command line)') for a core concept. Every sentence carries content, but the packaging could be tighter.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the full burden of explaining the return shape, and it does so thoroughly — header line, per-layer outline format, three distinct truncation signals, and vector grouping. An agent knows what it will receive and how to interpret a cut-off result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds genuine semantics on top: max_nodes is spent a level at a time so 'a large first section cannot crowd out later pages,' and depth is counted with pages at level 0. That clarifies allocation behavior the schema only partially captures.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening clause names a specific verb and resource ('Compact outline of the layer tree') and enumerates the fields it emits (id, type, name, size, hints). An agent can tell it produces a summary view rather than a full node dump, but no sibling (e.g., figma_get_node, figma_locate) is named to sharpen the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives conditional parameter guidance ('Omit node_id for all pages') and hints at escalation ('pass its node_id to open it'), implying figma_get_node for detail. However it never states plainly when to reach for this tool versus figma_get_node, figma_locate, or figma_search, leaving the routing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
figma_get_variablesA
Design variables (tokens) with collections, modes, per-mode values and resolved aliases. Works on any plan (no Enterprise REST API). Formats: json (default), css (custom properties, extra modes as [data-collection=mode]), dtcg (W3C design tokens). A file that defines none answers empty in that format; figma_token_usage derives tokens from the raw values instead, and figma_get_styles reads the styles.
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes | A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help) | |
| format | No | ||
| refresh | No | Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help) | |
| out_file | No | Also write the result to this path. The answer then ends with a note, not written to the file: '(written to <path>; exportedAt <time>, account "<name>" (source: <source>))', or '(written to <path>; fileModifiedAt <time>)' for a local .fig | |
| collection | No | Only this collection name; a name no collection in the file has is an error listing the ones it has | |
| css_prefix | No | ||
| include_remote | No | Include library variables copied into the file (default true) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations are sparse (readOnlyHint=false, openWorldHint=true), so the description must carry behavior, and it does: it discloses empty-file behavior per format, that aliases are resolved, and that the output is format-dependent. It does not address the tension of a read-style tool carrying readOnlyHint=false nor any caching/permission constraints, which is the remaining gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences, front-loaded with the resource and its scope before moving to formats and sibling routing. Every clause carries information; the only cost is slight packing of multiple facts per sentence.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, and the description compensates by naming the three output formats and their conventions plus the written-note behavior on out_file. For a 7-parameter read tool this is close to complete, with only auth/rate-limit and error-shape detail unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 71%, but the description adds genuine meaning the schema lacks: it explains each 'format' enum value (json default, css custom properties with extra modes emitted as [data-collection=mode], dtcg = W3C design tokens) and reinforces the empty-result case. That materially improves an agent's ability to pick and use parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States the exact resource and its shape ('design variables (tokens) with collections, modes, per-mode values and resolved aliases'), which tells an agent precisely what it will receive. It explicitly names the two neighbors it is not—figma_token_usage (derives tokens from raw values) and figma_get_styles (reads styles)—so it is distinguishable without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a real precondition ('Works on any plan (no Enterprise REST API)') and routes away from siblings by stating what each alternative does. It falls short of an explicit 'use this when you want X, use that when you want Y' rule, but the context is clear enough for selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
figma_list_filesARead-only
List Figma files. source=local (default): .fig files under FIGMA_FILES_DIRS, which the result names in searchedDirs. source=web: recently viewed files of the account logged in the browser. With query, totalUnfiltered says how many files there were before it.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Default 30 | |
| query | No | Case-insensitive filter on file name | |
| source | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, and the description adds valuable context about the source-specific behavior (local .fig files vs. recently viewed web files) and the totalUnfiltered field with query. This goes beyond the annotations and enriches the agent's understanding of what the tool does.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no wasted words. It front-loads the core purpose and then efficiently explains the key nuances of source and query. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description should explain what the tool returns. It mentions searchedDirs and totalUnfiltered but does not describe the overall structure of the returned list (e.g., file names, paths, pagination). This leaves some ambiguity about the exact output format, making it only partially complete for a listing tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 67%, and the description adds meaning to the source parameter by explaining the local/web distinction and to the query parameter by mentioning totalUnfiltered. It does not add meaning to limit, but limit is already described in the schema. Overall, it compensates well for the gaps.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action and resource: 'List Figma files.' It further distinguishes between local and web sources, making the tool's scope clear and distinct from siblings like figma_load_file or figma_search. The verb 'list' is precise and the resource is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context on how to use the tool (source selection, query behavior) but does not explicitly mention when to choose this tool over alternatives like figma_search or figma_get_tree. Usage is implied by the purpose, but no exclusions or alternatives are named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
figma_load_fileBRead-only
Export (Save local copy) and decode a Figma file, returning a summary: pages, node counts, variable collections, styles, components. Snapshots are cached; other tools reuse them. Export of large files can take a minute. For a snapshot exported through the browser, snapshotPath is its .fig in the cache, which the next export of the key replaces. Read by that path, it is never exported again, but it is dated fileModifiedAt and names no account like any local file: for a task's calls keep passing the key, and say so if exportedAt changes between them. Dated by exportedAt and account, or fileModifiedAt for a file read from disk, as the server's instructions say (figma-reader help on the command line).
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes | A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help) | |
| refresh | No | Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover readOnlyHint and openWorldHint, yet the description adds real behavioral context: caching and reuse by other tools, a stated latency risk ('can take a minute' for large files), and snapshot replacement semantics. This goes well beyond the annotations, though the later sentences are garbled and hard to act on.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The opening sentence is strong and front-loaded, but the following run-on sentences drift into confusing digressions about snapshotPath, exportedAt, fileModifiedAt and account dating. It is over-long and the trailing clause adds ambiguity rather than information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool whose snapshot/caching semantics are genuinely complex, the description does attempt to cover export vs cache-read and dating, but it repeatedly outsources the authoritative rules to external docs and ends on an unclear note. With no output schema, it should be self-sufficient, and it is only partly so.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3. The description elaborates on caching/replacement behavior but also introduces 'snapshotPath', which is not a parameter in the schema, creating mild confusion, and it never names the actual 'refresh' parameter or explains its default.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence gives a specific verb+resource ('Export and decode a Figma file') and even enumerates the returned summary (pages, node counts, variable collections, styles, components), which is more specific than most siblings. It implies its role as the file-level entry point that other tools draw from, but never explicitly contrasts itself with figma_get_tree or figma_get_node.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Snapshots are cached; other tools reuse them' hints that this is the load-first step and the refresh parameter controls re-export, so usage is implied. However, there is no explicit when-to-use / when-not / alternative guidance, and the reader is repeatedly deferred to 'the server's instructions' or 'figma-reader help' rather than given the rule inline.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
figma_locateARead-only
Look up a list of node ids in one call, such as the ids a document or an earlier answer cites. One entry per id, in the order given, with the id written 12:34 whichever spelling was passed: {id, found: true, type, name, page, path} for a node the file has (path from the page down, as figma_get_node gives it), {id, found: false} for one it has not, and {id, error} for a string that is not a node id. found, missing and invalid count the entries. found: false is said only of a file that was read: one that cannot be read fails the whole call. Where path does not split on ' / ' into its names, pathIds follows it: one id per name, page first. Dated by exportedAt and account, or fileModifiedAt for a file read from disk, as the server's instructions say (figma-reader help on the command line).
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes | A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help) | |
| refresh | No | Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help) | |
| node_ids | Yes | The node ids to look up, like 12:34 (or 12-34) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnlyHint and openWorldHint, but the description adds substantial behavioral detail beyond them: the per-entry result shapes ({id, found: true, ...} vs {id, found: false} vs {id, error}), the fact that missing and invalid entries are counted rather than thrown, and the crucial failure mode that an unreadable file fails the whole call. This is genuinely useful context the annotations do not convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded, but the body is dense, run-on and awkwardly phrased ('found, missing and invalid count the entries', 'is said only of a file that was read'), forcing re-reads to extract the semantics. The information is valuable but not economically expressed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of explaining return values and does so in detail, including found/missing/invalid shapes, pathIds fallback behavior, and timestamp provenance. Remaining gaps are minor, mostly around the refresh parameter's caching implications.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents file, refresh and node_ids; baseline is 3. The description adds only the id spelling variants ('12:34 or 12-34') and timestamp semantics, which is marginal beyond what the schema provides for the two primary parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence states a specific verb+resource ('Look up a list of node ids in one call') and the batch nature separates it from the single-node figma_get_node, which it references by name. It is clear what the tool does, though the sibling differentiation is incidental rather than an explicit routing statement.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'such as the ids a document or an earlier answer cites' gives a concrete usage context, so the agent can infer when this applies. However, there is no explicit guidance on when to prefer this over figma_get_node or figma_search, and no stated prerequisites beyond the passing reference to the server's instructions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
figma_loginA
Ensure this project's account is logged into figma.com. If not, opens a normal (not remote-controlled) browser window on the login page; after the user logs in the window closes by itself and work continues headless. wait_seconds blocks until then.
| Name | Required | Description | Default |
|---|---|---|---|
| wait_seconds | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes well beyond the annotations (readOnlyHint=false, openWorldHint=true) by disclosing that it opens a non-remote-controlled browser, that the window self-closes, that headless work resumes afterward, and that wait_seconds blocks until login completes.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no filler. Purpose, trigger condition, user interaction, and headless continuation are front-loaded in a compact, readable form.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-optional-parameter tool with no output schema, the description covers the essential behavior, UI side effect, and blocking semantics. The only noticeable gap is timeout/failure behavior, which is minor given the tool's simplicity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must carry the parameter meaning. It states that wait_seconds blocks until login completes, which adds semantic value beyond the schema's min/max, but it does not explain the default behavior when omitted or what happens if the timeout is reached.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific operation and resource ('ensure ... logged into figma.com') and explains the trigger condition ('if not') and action. It is clearly distinct from all sibling tools, none of which handle authentication or login.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It communicates the use case (before headless work that requires an authenticated account) and behavior ('if not, opens a normal browser window'). It does not name alternatives, but no sibling tool provides this function, so no exclusions are needed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
figma_screenshotA
Render a node to PNG using Figma's own 'Copy as PNG' in the browser (the system clipboard is not touched). Uses the live file, not the snapshot. Returns the image, downscaled to max_dimension, and a note that ends with the Figma account it was rendered through.
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes | A Figma file key or figma.com/design/... URL (a node-id in the URL is used when node_id is omitted). The image always comes from the live file in the browser, so a local .fig path works only if its name carries the key ('<name> [<key>].fig'), and is read only to tell whether node_id is a page. | |
| node_id | No | ||
| save_path | No | Also save the PNG (at returned size) to this path | |
| max_dimension | No | Longest side in px of the returned image (default 1568) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint=false, openWorldHint=true), the description discloses that rendering happens via the browser's Copy-as-PNG, that the system clipboard is untouched, that the live file is used, and that the return includes a note naming the Figma account. It doesn't cover auth requirements or failure modes, but the added context is substantial.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the core action and mechanism; the parenthetical about the clipboard preempts an obvious false assumption, and every clause carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully describes the return (image downscaled to max_dimension plus an account-identifying note). Combined with annotations covering the safety profile, it is nearly complete, though auth/login expectations go unmentioned.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 75%, so the schema already documents most parameters. The description adds the downscaling semantics for max_dimension and the shape of the returned note, but says nothing about save_path or node_id beyond what the schema states. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (render a node to PNG) and immediately scopes it: browser-based 'Copy as PNG' on the live file, not the snapshot. This distinguishes it from snapshot-based siblings like figma_load_file and from figma_export_image_fills without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'Uses the live file, not the snapshot' tells the agent when this tool is the right choice versus snapshot-reading siblings, and the clipboard note clarifies the mechanism. It stops short of explicitly naming an alternative tool or an exclusion, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
figma_searchARead-only
Find nodes by name (and optionally text content). The query is a literal substring, case-insensitive unless case_sensitive: a name like Icons/Arrow/Left or /Card [v2]/ matches itself. Only regex=true reads it as a pattern, bare or /pattern/flags, and an invalid pattern is an error. With include_text, component instances are expanded, so strings that only exist as instance overrides or component property values are matched too, each tagged with via (direct/instance) and, where they apply, component, variant and frame. Name matching sees only real layers: layer names inside a collapsed instance live in its main component, so search that component instead. A hit's characters is a preview: longer text is cut to its first 120 characters followed by ... and flagged charactersTruncated (truncated, next to it, is about the number of results); figma_get_text returns the strings whole. When the text pass runs, unresolvedInstances counts the instances whose text could not be resolved and so was not searched (figma_get_text names the components); it is absent when the pass did not run. Pages in exclude_pages, or by default in the project's excludePages, are skipped before the limit is counted; excludedPages names the ones this search left out. Dated by exportedAt and account, or fileModifiedAt for a file read from disk, as the server's instructions say (figma-reader help on the command line).
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes | A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help) | |
| page | No | Restrict to page name | |
| limit | No | Default 50 | |
| query | Yes | Name or text to find. A literal substring unless regex is set, so slashes and characters like [ ] ( ) . * match themselves | |
| regex | No | Read the query as a regex, bare or /pattern/flags, and report an invalid one. Default false: the query is a literal substring however it is written | |
| types | No | Node types to match, e.g. FRAME, COMPONENT, INSTANCE, TEXT. A list without TEXT also turns include_text off, since every text hit is a TEXT node; an empty list is no filter at all | |
| node_id | No | Search only this node and everything under it, like 12:34 (or 12-34); a node-id in the file URL is used when it is omitted, and the document's own id (0:0) is the whole file | |
| refresh | No | Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help) | |
| include_text | No | Also match text content, including text rendered inside instances | |
| exclude_pages | No | Pages to skip, by name as page takes it. They are left out while walking, so their hits neither fill the limit nor count in total. Default: excludePages in the project's .figma-reader.json, unless page or a node_id other than the document's own (0:0) is given; an empty list searches every page | |
| case_sensitive | No | Match case (default false, for a regex too) | |
| include_hidden | No | Include text on layers hidden in the design (default false) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already settle the safety profile (readOnlyHint=true, openWorldHint=true), and the description goes well beyond them: truncation at 120 characters with charactersTruncated, unresolvedInstances for text that could not be resolved, via/component/variant/frame tagging, and the ordering rule that excluded pages are skipped before the limit is counted. It stops short of stating auth requirements, rate limits, or per-call cost, so it is strong but not exhaustive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded, but the body is one undivided block of run-on sentences covering matching, instance expansion, truncation, exclusion, and timestamps. Every clause is arguably informative, yet nested asides such as '(truncated, next to it, is about the number of results)' make it hard to scan; splitting into matching/behaviour/return sections would preserve the content at lower reading cost.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 12 parameters, no output schema, and a subtle matching model, this description supplies exactly the missing context: what the returned fields mean (via, characters, charactersTruncated, unresolvedInstances, excludedPages) and where output is elided. An agent has enough to call the tool and interpret the result without further documentation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description earns an increment by giving concrete, illustrative query forms ('Icons/Arrow/Left or /Card [v2]/ matches itself') and by clarifying cross-parameter interactions such as an invalid regex being an error and regex quoting behavior. Much of the remaining parameter detail duplicates the schema, which caps it below 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening clause gives a specific verb and resource ('Find nodes by name (and optionally text content)') and immediately scopes the matching semantics. It also distinguishes itself from the sibling figma_get_text by stating that search returns a truncated preview while 'figma_get_text returns the strings whole', so an agent can route between the two without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage context is clearly established: when to set include_text, when the text pass does not run, and the important workaround that 'layer names inside a collapsed instance live in its main component, so search that component instead'. What is missing is an explicit statement of when NOT to use this tool versus figma_locate, figma_get_tree, or figma_get_text beyond the single truncation contrast.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
figma_statusA
Account, browser and login state. Does not launch anything: local .fig paths never need the browser.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations are sparse (readOnlyHint=false, openWorldHint=true) and do not explain side effects. The description adds a valuable behavioral guarantee: it does not launch anything, which is safety-relevant for an agent deciding whether to call it. This goes beyond the annotations, though it does not disclose return format or network behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with no redundancy. The core state information is front-loaded, and the clarifying no-launch note is placed immediately after.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter status tool with no output schema, the description is largely complete: it names what is reported and clarifies a key side-effect constraint. It could briefly mention what the agent will receive in the response, but the low complexity keeps this from being a major gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and the schema is an empty object with 100% coverage, so there is nothing the description needs to add. The 0-parameter baseline of 4 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description identifies the resource as 'account, browser and login state', which clearly signals a status-checking tool. It lacks an explicit verb like 'reports' or 'checks', but the follow-up 'Does not launch anything' differentiates it from file-loading and login siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use guidance or mention of alternatives. The note about local .fig paths never needing the browser implies a use context, but the description never says 'use this to verify login state before...' or contrasts it with figma_login or figma_load_file.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
figma_token_usageARead-only
Scan a subtree (or whole file) and aggregate the raw design values actually used: colors, typography combos, corner radii, auto-layout gaps/paddings, stroke widths, effects, each with counts and the variable/style bound where present. Useful to derive a token set from files that do not define variables or styles. A typography entry carries only the properties the file records, and always at least one: text that records none of them is counted in textWithoutTypography instead, so it is accounted for without standing in the list as an entry naming no value. Dated by exportedAt and account, or fileModifiedAt for a file read from disk, as the server's instructions say (figma-reader help on the command line).
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes | A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help) | |
| node_id | No | ||
| refresh | No | Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help) | |
| min_count | No | Drop values used fewer times (default 1) | |
| include_hidden | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover readOnly/openWorld, and the description goes well beyond them: it explains the aggregate shape (counts + bound variable/style), the typography edge case (entries carry only recorded properties; text with none is counted in textWithoutTypography), and the dating rules (exportedAt/account vs fileModifiedAt). These are genuine behavioral details, though it leans heavily on pointing to external 'server instructions' rather than stating rules inline.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first sentence, but the description is bloated: the typography-exclusion explanation is a long clause, and 'as the server's instructions say (figma-reader help on the command line)' is repeated, deferring to external docs twice.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return-value burden and does so well -- it enumerates the aggregated categories, mentions counts and bindings, and handles the typography edge case. Remaining gaps are minor (include_hidden, exact grouping of output).
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 60%, so the schema documents file, refresh, and min_count while node_id and include_hidden are bare. The description only indirectly signals node_id ('scan a subtree') and refresh ('a file read from disk'); include_hidden is never addressed. It adds marginal value, aligning with the 3 baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource -- scan a subtree/whole file and aggregate raw design values (colors, typography, radii, gaps, stroke widths, effects) with counts. It also distinguishes itself from the sibling style/variable tools by noting it is for 'files that do not define variables or styles'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a use condition ('to derive a token set from files that do not define variables or styles'), which implicitly excludes files that do have variables/styles. But it never names figma_get_variables or figma_get_styles as the alternatives to reach for in that case, so routing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
14 tool updates
v0.4.2- Added
figma_changes - Added
figma_dev_status - Added
figma_diff - Changed
figma_export_image_fills2 fields changed- changed
Input schema / properties / file / descriptionPrevious value: -"Path to a local .fig file, or a Figma file key / figma.com/design/... URL. A node-id in the URL is used when this tool takes node_id and it is omitted; a tool that answers about the whole file ignores it. A key or URL uses a local '<name> [<key>].fig' from FIGMA_FILES_DIRS when one exists, otherwise exports through the browser."New value: +"A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help)" - changed
Input schema / properties / refresh / descriptionPrevious value: -"Skip local/cached copies and export the live file through the browser. Has no effect when file is a path to a .fig: that file is read as it is on disk and the result carries refreshIgnored; pass the key or URL to export the live file instead."New value: +"Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help)"
- Changed
figma_get_components2 fields changed- changed
Input schema / properties / file / descriptionPrevious value: -"Path to a local .fig file, or a Figma file key / figma.com/design/... URL. A node-id in the URL is used when this tool takes node_id and it is omitted; a tool that answers about the whole file ignores it. A key or URL uses a local '<name> [<key>].fig' from FIGMA_FILES_DIRS when one exists, otherwise exports through the browser."New value: +"A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help)" - changed
Input schema / properties / refresh / descriptionPrevious value: -"Skip local/cached copies and export the live file through the browser. Has no effect when file is a path to a .fig: that file is read as it is on disk and the result carries refreshIgnored; pass the key or URL to export the live file instead."New value: +"Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help)"
- Changed
figma_get_node2 fields changed- changed
Input schema / properties / file / descriptionPrevious value: -"Path to a local .fig file, or a Figma file key / figma.com/design/... URL. A node-id in the URL is used when this tool takes node_id and it is omitted; a tool that answers about the whole file ignores it. A key or URL uses a local '<name> [<key>].fig' from FIGMA_FILES_DIRS when one exists, otherwise exports through the browser."New value: +"A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help)" - changed
Input schema / properties / refresh / descriptionPrevious value: -"Skip local/cached copies and export the live file through the browser. Has no effect when file is a path to a .fig: that file is read as it is on disk and the result carries refreshIgnored; pass the key or URL to export the live file instead."New value: +"Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help)"
- Changed
figma_get_styles3 fields changed- changed
Input schema / properties / file / descriptionPrevious value: -"Path to a local .fig file, or a Figma file key / figma.com/design/... URL. A node-id in the URL is used when this tool takes node_id and it is omitted; a tool that answers about the whole file ignores it. A key or URL uses a local '<name> [<key>].fig' from FIGMA_FILES_DIRS when one exists, otherwise exports through the browser."New value: +"A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help)" - changed
Input schema / properties / out_file / descriptionPrevious value: -"Also write the result to this path"New value: +"Also write the result to this path. The answer then ends with a note, not written to the file: '(written to <path>; exportedAt <time>, account \"<name>\" (source: <source>))', or '(written to <path>; fileModifiedAt <time>)' for a local .fig" - changed
Input schema / properties / refresh / descriptionPrevious value: -"Skip local/cached copies and export the live file through the browser. Has no effect when file is a path to a .fig: that file is read as it is on disk and the result carries refreshIgnored; pass the key or URL to export the live file instead."New value: +"Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help)"
- Changed
figma_get_text6 fields changed- added
Input schema / properties / exclude_pagesAdded value: +{ + "description": "Pages to leave out, by name (default none)", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / fieldsAdded value: +{ + "description": "Keys to keep in each item, of id, name, text, via, component, variant, frame (default all)", + "items": { + "enum": [ + "id", + "name", + "text", + "via", + "component", + "variant", + "frame" + ], + "type": "string" + }, + "minItems": 1, + "type": "array" +} - changed
Input schema / properties / file / descriptionPrevious value: -"Path to a local .fig file, or a Figma file key / figma.com/design/... URL. A node-id in the URL is used when this tool takes node_id and it is omitted; a tool that answers about the whole file ignores it. A key or URL uses a local '<name> [<key>].fig' from FIGMA_FILES_DIRS when one exists, otherwise exports through the browser."New value: +"A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help)" - added
Input schema / properties / node_id / descriptionAdded value: +"Only the text under this node, like 12:34 (or 12-34); the document's own id (0:0) is the whole file" - added
Input schema / properties / pageAdded value: +{ + "description": "Only text on this page, by name", + "type": "string" +} - changed
Input schema / properties / refresh / descriptionPrevious value: -"Skip local/cached copies and export the live file through the browser. Has no effect when file is a path to a .fig: that file is read as it is on disk and the result carries refreshIgnored; pass the key or URL to export the live file instead."New value: +"Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help)"
- Changed
figma_get_tree3 fields changed- changed
Input schema / properties / file / descriptionPrevious value: -"Path to a local .fig file, or a Figma file key / figma.com/design/... URL. A node-id in the URL is used when this tool takes node_id and it is omitted; a tool that answers about the whole file ignores it. A key or URL uses a local '<name> [<key>].fig' from FIGMA_FILES_DIRS when one exists, otherwise exports through the browser."New value: +"A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help)" - changed
Input schema / properties / max_nodes / descriptionPrevious value: -"Default 400"New value: +"Lines to spend (default 400), a level at a time: a level that does not fit is shared evenly between its parents, and the levels under it are not shown" - changed
Input schema / properties / refresh / descriptionPrevious value: -"Skip local/cached copies and export the live file through the browser. Has no effect when file is a path to a .fig: that file is read as it is on disk and the result carries refreshIgnored; pass the key or URL to export the live file instead."New value: +"Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help)"
- Changed
figma_get_variables3 fields changed- changed
Input schema / properties / file / descriptionPrevious value: -"Path to a local .fig file, or a Figma file key / figma.com/design/... URL. A node-id in the URL is used when this tool takes node_id and it is omitted; a tool that answers about the whole file ignores it. A key or URL uses a local '<name> [<key>].fig' from FIGMA_FILES_DIRS when one exists, otherwise exports through the browser."New value: +"A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help)" - changed
Input schema / properties / out_file / descriptionPrevious value: -"Also write the result to this path"New value: +"Also write the result to this path. The answer then ends with a note, not written to the file: '(written to <path>; exportedAt <time>, account \"<name>\" (source: <source>))', or '(written to <path>; fileModifiedAt <time>)' for a local .fig" - changed
Input schema / properties / refresh / descriptionPrevious value: -"Skip local/cached copies and export the live file through the browser. Has no effect when file is a path to a .fig: that file is read as it is on disk and the result carries refreshIgnored; pass the key or URL to export the live file instead."New value: +"Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help)"
- Changed
figma_load_file2 fields changed- changed
Input schema / properties / file / descriptionPrevious value: -"Path to a local .fig file, or a Figma file key / figma.com/design/... URL. A node-id in the URL is used when this tool takes node_id and it is omitted; a tool that answers about the whole file ignores it. A key or URL uses a local '<name> [<key>].fig' from FIGMA_FILES_DIRS when one exists, otherwise exports through the browser."New value: +"A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help)" - changed
Input schema / properties / refresh / descriptionPrevious value: -"Skip local/cached copies and export the live file through the browser. Has no effect when file is a path to a .fig: that file is read as it is on disk and the result carries refreshIgnored; pass the key or URL to export the live file instead."New value: +"Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help)"
- Added
figma_locate - Changed
figma_search4 fields changed- added
Input schema / properties / exclude_pagesAdded value: +{ + "description": "Pages to skip, by name as page takes it. They are left out while walking, so their hits neither fill the limit nor count in total. Default: excludePages in the project's .figma-reader.json, unless page or a node_id other than the document's own (0:0) is given; an empty list searches every page", + "items": { + "type": "string" + }, + "type": "array" +} - changed
Input schema / properties / file / descriptionPrevious value: -"Path to a local .fig file, or a Figma file key / figma.com/design/... URL. A node-id in the URL is used when this tool takes node_id and it is omitted; a tool that answers about the whole file ignores it. A key or URL uses a local '<name> [<key>].fig' from FIGMA_FILES_DIRS when one exists, otherwise exports through the browser."New value: +"A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help)" - changed
Input schema / properties / node_id / descriptionPrevious value: -"Search only this node and everything under it, like 12:34 (or 12-34); a node-id in the file URL is used when it is omitted"New value: +"Search only this node and everything under it, like 12:34 (or 12-34); a node-id in the file URL is used when it is omitted, and the document's own id (0:0) is the whole file" - changed
Input schema / properties / refresh / descriptionPrevious value: -"Skip local/cached copies and export the live file through the browser. Has no effect when file is a path to a .fig: that file is read as it is on disk and the result carries refreshIgnored; pass the key or URL to export the live file instead."New value: +"Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help)"
- Changed
figma_token_usage2 fields changed- changed
Input schema / properties / file / descriptionPrevious value: -"Path to a local .fig file, or a Figma file key / figma.com/design/... URL. A node-id in the URL is used when this tool takes node_id and it is omitted; a tool that answers about the whole file ignores it. A key or URL uses a local '<name> [<key>].fig' from FIGMA_FILES_DIRS when one exists, otherwise exports through the browser."New value: +"A local .fig path, a Figma file key or a figma.com/design/... URL (see the server's instructions, or figma-reader help)" - changed
Input schema / properties / refresh / descriptionPrevious value: -"Skip local/cached copies and export the live file through the browser. Has no effect when file is a path to a .fig: that file is read as it is on disk and the result carries refreshIgnored; pass the key or URL to export the live file instead."New value: +"Export the live file again rather than read a local or cached copy (see the server's instructions, or figma-reader help)"
14 tool updates
v0.1.0- First observed
figma_export_image_fills - First observed
figma_get_components - First observed
figma_get_node - First observed
figma_get_styles - First observed
figma_get_text - First observed
figma_get_tree - First observed
figma_get_variables - First observed
figma_list_files - First observed
figma_load_file - First observed
figma_login - First observed
figma_screenshot - First observed
figma_search - First observed
figma_status - First observed
figma_token_usage
TDQS
Scored across 18 tools
Most tools target clearly distinct resources or actions (get_text, get_styles, get_variables, search, screenshot, diff, changes). Some overlap exists among node-inspection tools (get_node, get_tree, locate) and token-related tools (get_styles, get_variables, token_usage), but the descriptions carefully distinguish their scopes and output formats.
All names share a consistent figma_ prefix and snake_case formatting with mostly verb_noun patterns. A few are noun phrases (figma_screenshot, figma_status, figma_changes) or noun-based (figma_dev_status, figma_token_usage), which is a minor deviation from a strict verb_noun convention.
Eighteen tools is slightly heavy for a read-only Figma reader, but each covers a genuinely distinct part of the domain (loading, tree/node inspection, text, styles, variables, components, search, screenshots, image exports, diffs, change history, account state). The breadth justifies the count more than it bloats the surface.
The surface covers the core read lifecycle very well: export/load, inspect nodes and text, extract styles/variables/components, search, screenshot, export image fills, diff snapshots, and track changes. Minor gaps exist, such as reading Figma comments or version metadata, but agents can work around them for typical read-only tasks.
Maintenance
Related MCP Connectors
The Figma MCP server brings Figma design context directly into your AI workflow.
OCR, transcription, file extraction, and image generation for AI agents via MCP.
Read-only MCP tools for AI agent discovery, structured resources, and NIULAI information.
Web scraping, browser automation, screenshots and AI data extraction for AI agents via MCP.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceMCP server for the Figma API. Lets AI agents fetch designs, nodes, and rendered images from Figma.3,295 npm-
- FlicenseNot gradedqualityDmaintenanceRead-only MCP server that wraps the Figma REST API, providing tools like get file metadata, list frames, and export node image URLs for AI SDLC agents.-

Figma MCP Serverofficial
FlicenseNot gradedqualityBmaintenanceProvides Figma design context to AI agents, enabling code generation, design system integration, and canvas manipulation through MCP.2,129-- FlicenseNot gradedqualityBmaintenanceEnables AI agents to access Figma design context, generate code from frames, extract variables, components, and layout data, and create or modify Figma files directly from MCP clients.-