figjam-context-mcp
Turn FigJam boards into source-cited context for LLMs via a local MCP server.
Ingest a FigJam/Figma board from a URL and save a local snapshot, with optional vision LLM interpretation, custom phases, and incremental re-ingest.
Retrieve paginated, source-linked board context by section, page, frame, group, exact node IDs, or topic for overviews, summaries, and documentation.
Ask one specific question about a board and get an answer with validated node-level citations or an insufficient-evidence result.
Compare two retained snapshots of the same board to see new, removed, or changed clusters, nodes, table cells, and connector arrows.
Diagnose the configured text and vision models with small synthetic JSON checks after changing model/provider settings.
Read Figma boards without modifying them; snapshots stay in a private local cache, and some modes avoid sending anything to an LLM provider.
Provides tools to ingest FigJam boards, retrieve context summaries and clusters, and answer questions about board content.
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., "@figjam-context-mcpWhat are the main action items from the FigJam board?"
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.
figjam-context-mcp
A local MCP server that turns FigJam boards into source-cited context for LLMs. It reads a board through the Figma REST API, groups stickies, tables, images and arrows into clusters, and answers questions with links back to the original nodes.

Why
Workshop boards hold research notes, decisions and open questions, but an LLM cannot read a canvas. Screenshots and PDF exports lose tables, arrow direction and the link to the source. This server keeps the board's structure and cites every answer to the nodes it came from.
Related MCP server: Miro MCP Server
Tools
Tool | What it does | LLM call |
| Reads a board, clusters it and saves a local snapshot. Re-ingests reuse unchanged clusters. | In |
| Returns paginated, source-linked context, optionally for a topic or exact node IDs. Use it for overviews, summaries and documentation. | No |
| Answers one specific question (a number, status or decision) from the most relevant excerpts, with node-level citations or an insufficient-evidence result. Not meant for whole-board summaries. | Yes |
| Compares two snapshots: new, removed and changed clusters, nodes, table cells and arrows. | No |
| Tests the configured models with small text and image JSON checks. | Yes |
Quick start
Requires Node.js 22.12 or later.
Create a Figma personal access token under Settings → Security → Personal access tokens with the scope
file_content:read. Addfile_metadata:readso re-ingests of an unchanged board skip the download. The token's account needs access to the board.Optional: create an OpenRouter key at openrouter.ai/keys. It enables image interpretation,
answer_from_boardanddiagnose_llm_config. Without it, useingestMode: "max_speed"withget_board_contextanddiff_board.Add the server to your MCP client.
@latestmakes npx check for a new release on every start instead of reusing a cached older version:
{
"mcpServers": {
"figjam-context": {
"command": "npx",
"args": ["-y", "figjam-context-mcp@latest"],
"env": {
"FIGMA_ACCESS_TOKEN": "your-figma-token",
"LLM_BASE_URL": "https://openrouter.ai/api/v1",
"LLM_API_KEY": "your-openrouter-key"
}
}
}
}For Claude Code:
claude mcp add figjam-context -e FIGMA_ACCESS_TOKEN=your-figma-token -e LLM_BASE_URL=https://openrouter.ai/api/v1 -e LLM_API_KEY=your-openrouter-key -- npx -y figjam-context-mcp@latestThen ask your assistant to ingest a board URL, for example "Ingest
https://www.figma.com/board/FILE_KEY/Name and list the open questions."
The boardId of every later call is the file key from that URL. To summarize
a board, the assistant calls ingest_board, then get_board_context without
parameters, whose first page names the largest sections and lists all sections
with IDs, and then reads the largest sections by passing their IDs as nodeIds.
Everything that lies in no section, such as loose notes and tables, comes with
outsideSections: true.
All settings: configuration. Problems: troubleshooting.
How it works
Read.
ingest_boarddownloads the board through the Figma REST API. If Figma reports the same version as the last ingest, the download is skipped.Normalize. Nodes become text, table cells, images and connectors, with their pages and sections. Tables are read row by row: row and column come from the cell IDs, and each row becomes one excerpt.
Cluster. Nearby nodes are grouped by rotation-aware distance. Arrows between groups become directed relations.
Interpret. In
balancedmode, clusters with an image, or drawings without any text, get a vision-model summary within a 40-second budget; text clusters, however short, keep their extracted text. A cluster starts only when the time left fits it; unfinished clusters continue on the next ingest.Serve. The snapshot is saved to a private local cache.
get_board_contextsearches it (BM25 over original text, table rows and names),answer_from_boardanswers with citations anddiff_boardcompares snapshots. Its first page lists the board's sections with IDs; pass a page, section, frame or group ID asnodeIdsto read everything inside it; several IDs in one call take turns, so each of them appears on every page. Its textcontentis the readable page;structuredContentholds the same data without repeating it, with excerpts inevidenceand location per cluster inclusters.
Models and cost
The default preset student-free uses free OpenRouter models: text goes to
nvidia/nemotron-3-super-120b-a12b:free and then openrouter/free; images go to
openrouter/free, which picks a free model that accepts images and structured
outputs. The free default is best effort: free models change, hit rate limits
and time out.
OpenRouter allows free models 20 requests per minute and 50 requests per day, or 1,000 per day once you have bought at least 10 credits (limits).
Figma limits requests by seat and plan (rate limits). File downloads and image renders are Tier 1: Dev and Full seats on paid plans get 10–20 requests per minute, View and Collab seats and files in Starter plans at most 20 per month. Images come from the image fills instead, Tier 2 with at least 5 requests per minute, in one request per ingest. Renders are left for drawings without an image and as a fallback for single images; one render request covers up to 18 nodes.
max_speedneeds neither.For a team, configure your own model:
LLM_BASE_URLtakes any OpenAI-compatible endpoint, andLLM_TEXT_MODELS/LLM_VISION_MODELSset the model lists.Run
diagnose_llm_configafter every model change. It checks JSON replies and image understanding with synthetic inputs.
Privacy
The server reads from Figma and never changes a board.
balancedandmax_qualityingests send board text and images (originals or renders) to the configured LLM provider.answer_from_boardsends the question and selected excerpts.max_speedwithget_board_contextanddiff_boardsends nothing to an LLM provider.Snapshots stay in a private per-user cache on your machine. Delete the cache directory to remove them.
Explicit credentials such as
Passwort: …or API keys are redacted before they reach the cache, tool output or an LLM provider (FIGJAM_MCP_REDACT_CREDENTIALS). This is a safety net, not a guarantee: images are not redacted, so keep credentials off the board.Keep tokens in the client's environment. A token passed as a tool argument can appear in client logs.
Limitations
Image interpretation gets 40 seconds per ingest by default; large boards need several ingests to interpret every image cluster.
A client that cancels an ingest, for example after a 60-second timeout, gets no partial result.
Free models are best effort. Citations show where an answer comes from, not that its conclusion is right.
Search is lexical; synonyms without shared words do not match.
Local stdio only; no hosted or multi-user mode.
Measured results: evaluation.
Development
git clone https://github.com/ecestnrkl/figjam-mcp.git
cd figjam-mcp
npm ci
cp .env.example .env # add your tokens
npm run check # typecheck, tests, build, package validation
npm run package:smoke # install the packed package and exercise all tools
npm run eval:retrieval # offline retrieval and diff evaluation
npx @modelcontextprotocol/inspector --config inspector.config.jsonSee CONTRIBUTING.md and the changelog.
License
MIT © 2026 ecestnrkl
Available Tools
5 toolsanswer_from_boardAnswer From BoardARead-only
Answer one specific question, such as a number, a status or a decision, from the most relevant excerpts of an ingested board, with validated source citations or an insufficient-evidence result. It reads only a handful of excerpts: not for summaries, lists, risks or next steps across several sections; read those with get_board_context. Sends the question and the selected excerpts to the configured LLM provider; calls may incur charges.
| Name | Required | Description | Default |
|---|---|---|---|
| boardId | Yes | The Figma file key returned by ingest_board | |
| question | Yes | ||
| snapshotId | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| answer | Yes | |
| citations | Yes | |
| snapshotId | Yes | |
| citedClusters | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, non-destructive, open-world, non-idempotent), so the bar is lower. The description adds genuinely useful non-structured context: it reads only a handful of excerpts, sends the question plus excerpts to the configured LLM provider, and that calls may incur charges. It stops short of latency, rate limits, or what happens on provider misconfiguration, but the cost disclosure is real added value.
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 sentences, all front-loaded and each earning its place: what it answers, the negative scope with the alternative tool, then the LLM/cost caveat. No filler and the most decision-relevant content comes first.
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 an output schema present, the description needn't explain return values, and it still notes the insufficient-evidence outcome and validated citations. Annotations carry the safety profile and the description carries the cost/LLM behavior; the only meaningful hole is the unexplained optional snapshotId parameter.
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 only 33% — boardId is documented as a Figma file key, but 'question' and 'snapshotId' carry no schema descriptions, and the description never mentions parameters at all. snapshotId in particular is an optional parameter whose meaning (which point-in-time snapshot to answer from) is left entirely unexplained in both places.
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 ('answer one specific question... from the most relevant excerpts of an ingested board') and scopes the question types it handles. It also explicitly distinguishes itself from the sibling get_board_context by naming what it is not for, so an agent can route between the two without opening either 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 an explicit when-not ('not for summaries, lists, risks or next steps across several sections') and names the alternative tool to use instead (get_board_context). The usage condition is unambiguous and the alternative is named, not merely implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
diagnose_llm_configDiagnose LLM ConfigARead-only
Test the configured text and vision models with three small synthetic JSON challenges. Sends synthetic text and an image to the configured provider, may incur charges, and reports semantic/schema failures. Does not read board contents. Use after changing model/provider settings.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| checks | Yes | |
| preset | Yes | |
| summary | Yes | |
| textModels | Yes | |
| visionModels | Yes | |
| fastTextModels | Yes | |
| providerRequireParameters | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, non-destructive, openWorld) and the description adds real value beyond them: potential charges, that synthetic data is sent to the external provider, that board contents are not read, and that semantic/schema failures are reported. It does not contradict the annotations — outbound provider calls are consistent with openWorldHint and the non-idempotent hint aligns with per-call charges.
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?
Four short sentences, front-loaded with what it does, followed by side effects, scope boundary, and timing. Dense but every sentence carries information; minor compression possible in the failure-reporting clause.
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 diagnostic with an output schema (so return values need no explanation), the description covers purpose, cost side effects, external data transmission, scope exclusion, and when to invoke it. Nothing material is missing.
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 takes zero parameters, so per the rubric the baseline is 4; there is nothing for the description to disambiguate.
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 (diagnose/test) and resource (configured text and vision models) plus the exact scope: three small synthetic JSON challenges. It is unmistakably distinct from the board-oriented siblings like ingest_board and get_board_context.
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?
Explicitly names the trigger condition: 'Use after changing model/provider settings.' No alternative tool is named and no when-not-to-use is given, but the diagnostic framing makes the context clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
diff_boardDiff Board SnapshotsARead-onlyIdempotent
Compare retained local snapshots of the same board, reporting cluster, node and connector changes. Requires at least two distinct ingests. compareTo=1 selects the previous snapshot, 2 selects two states back. No network or LLM calls; ingest_board must capture the current Figma state first.
| Name | Required | Description | Default |
|---|---|---|---|
| boardId | Yes | The Figma file key, as returned by ingest_board | |
| compareTo | No | How many snapshots back to use as the baseline (1 = the ingest before the latest) |
Output Schema
| Name | Required | Description |
|---|---|---|
| stats | Yes | |
| boardId | Yes | |
| newClusters | Yes | |
| summaryText | Yes | Paste-ready human/LLM-readable change report |
| removedClusters | Yes | |
| addedConnections | Yes | |
| currentCreatedAt | Yes | ISO timestamp of the latest ingest |
| modifiedClusters | Yes | |
| tableCellChanges | No | |
| baselineCreatedAt | Yes | ISO timestamp of the baseline ingest |
| currentSnapshotId | No | |
| baselineSnapshotId | No | |
| removedConnections | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive, non-open-world, so the safety profile is covered. The description adds genuine context beyond that: the two-ingest precondition and that no network or LLM calls are made, which is useful cost/latency information.
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 with no filler; the scope statement comes first, then the precondition, then the parameter shortcut and the ingest dependency. 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?
With an output schema present, return values need no explanation, and the description covers the key prerequisites and behavioral constraints. It omits the snapshot-history bound (max 19 back) and any note on what happens when fewer than two snapshots exist, but is otherwise sufficient.
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 both parameters are already documented. The description restates compareTo=1 as 'previous snapshot' and adds '2 selects two states back', which is slightly more intuitive but largely duplicates the schema's own wording. Baseline 3 applies.
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 retained local board snapshots) and names the output (cluster, node and connector changes). An agent can tell it apart from ingest_board and get_board_context immediately.
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 hard prerequisite (at least two distinct ingests) and explicitly routes the agent to ingest_board before calling this. It does not say when to prefer this over get_board_context or answer_from_board, so it stops short of full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_board_contextGet Board ContextARead-onlyIdempotent
Read source-cited context from an ingested board snapshot: original text, table rows, cluster summaries and arrows, each with a Figma link. Start here for overviews, summaries and documentation with one call without topic, nodeIds, limit and maxChars: its first page names the largest sections and lists all sections with IDs. Then read sections, pages, frames or groups by passing their IDs as nodeIds (several IDs in one call share every page), read everything outside sections with outsideSections: true, search words with topic, or continue with cursor, and synthesize the answer yourself. Large pages can exceed client output limits. No network or LLM calls; does not refresh Figma content (use ingest_board).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum evidence excerpts per page (default 20) | |
| topic | No | Optional topic to focus the context on | |
| cursor | No | Continue a page using the same query, snapshot, limit and maxChars | |
| boardId | Yes | The Figma file key returned by ingest_board | |
| nodeIds | No | Read exact source nodes, all rows of a table or the row of a table cell, or every excerpt inside a page, section, frame or group by its ID (nested sections included, in reading order); several IDs in one call share every page in request order; cannot be combined with topic | |
| maxChars | No | Character budget for each representation: the readable text content and the JSON of structuredContent (default 12000) | |
| snapshotId | No | Read a specific retained snapshot instead of the latest board | |
| outsideSections | No | Read every excerpt that lies in no section, cluster by cluster in reading order, tables row by row; on a board without sections, all excerpts. Cannot be combined with topic or nodeIds |
Output Schema
| Name | Required | Description |
|---|---|---|
| clusters | Yes | |
| evidence | Yes | |
| relations | No | Cluster-to-cluster relations derived from connector arrows |
| truncated | Yes | |
| nextCursor | No | |
| snapshotId | Yes | |
| truncation | Yes | Explicit omissions from structured results and the readable text |
| connections | Yes | |
| contextText | Yes | Orientation: board header, page position, board overview or subsections. The excerpts are in evidence; the text content carries the readable version |
| totalMatched | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive and closed-world, so safety is covered. The description usefully adds that there are no network or LLM calls, that it does not refresh Figma content, and that large pages can exceed client output limits, but it does not cover pagination failure modes or error behavior in depth.
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?
One dense but well-ordered paragraph: purpose first, entry-point strategy second, follow-on invocation patterns third, caveats last. Every clause carries routing or constraint information rather than restating the name.
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 an 8-parameter read tool with an output schema and full annotation coverage, the description supplies everything an agent needs: how to start, how to drill into specific nodes, mutual-exclusion rules, pagination, freshness limits, and the sibling to call instead when refreshing is required.
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; the description goes beyond it by explaining that omitting topic/nodeIds/limit/maxChars yields a first page that names the largest sections, that multiple nodeIds share every page in request order, and that cursor resumes the same query. That is genuine added meaning on top of the schema.
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 ('read source-cited context from an ingested board snapshot') and enumerates the content types returned (original text, table rows, cluster summaries, arrows). It also differentiates from siblings by naming ingest_board for refreshes and implying answer_from_board with 'synthesize the answer yourself.'
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 an explicit entry strategy ('Start here... without topic, nodeIds, limit, maxChars'), then a follow-up path for sections/pages/frames by nodeIds, outsideSections, topic, and cursor. Exclusion rules (cannot combine topic with nodeIds) and the alternative for refreshing (use ingest_board) are stated directly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ingest_boardIngest FigJam BoardA
Read a FigJam/Figma URL with the configured Figma token and persist a local snapshot for get_board_context, answer_from_board and diff_board; the summary names the largest sections to read next and how many excerpts lie outside sections. Leaves the Figma file unchanged. Balanced/quality modes may send board text and images to the configured LLM provider and incur charges; max_speed skips vision. Re-ingest to refresh stale content; local history is bounded. Supports framework phases or customPhases.
| Name | Required | Description | Default |
|---|---|---|---|
| ingestMode | No | How aggressively to use vision LLM calls during ingest | balanced |
| customPhases | No | Free-form phase names to map clusters onto (e.g. ["Ideen", "Feedback", "Offene Fragen"]); overrides docStructureHint | |
| figmaFileUrl | Yes | URL of the FigJam/Figma file to ingest | |
| forceFullIngest | No | Download and extract the board again, skipping the unchanged-board check and cache, and redo the image interpretation of the chosen ingestMode. Interpretations this mode does not redo (all in max_speed; in balanced those of clusters without image or drawing) are kept while a cluster's content is unchanged. The vision time budget still applies, so balanced and max_quality may need several ingests until every image is interpreted again. An unchanged board gives no new snapshot for diff_board, even with forceFullIngest. Model/configuration changes are detected automatically. Default: false | |
| docStructureHint | No | Built-in framework used to map clusters to phases | freeform |
| figmaAccessToken | No | Figma personal access token; falls back to FIGMA_ACCESS_TOKEN env var if omitted |
Output Schema
| Name | Required | Description |
|---|---|---|
| boardId | Yes | |
| summary | Yes | |
| ingestMode | No | |
| snapshotId | No | |
| clusterCount | Yes | |
| figmaVersion | No | |
| qualityReport | No | |
| relationCount | No | Directed cluster-to-cluster relations derived from connector arrows |
| freshnessCheckedAt | No | |
| persistenceWarning | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing cost implications (board text and images sent to the configured LLM provider, charges may be incurred), the vision behavior of max_speed, that the remote Figma file is left unchanged, that local history is bounded, and that stale content requires re-ingest. These are exactly the non-obvious side effects an agent needs, and they are consistent with readOnlyHint=false and idempotentHint=false (each ingest writes a new local snapshot).
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-loads the core action and its persistence target in the first clause, then layers cost, freshness, and phase-configuration caveats. It is dense and semicolon-heavy, but each clause carries distinct operational information, so it is appropriately sized for a six-parameter tool with side effects.
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 of this complexity it covers the essentials: auth fallback (FIGMA_ACCESS_TOKEN env var), external-cost exposure, the shape of the summary it produces (largest sections, excerpts outside sections), staleness/refresh behavior, and bounded local history. An output schema exists, so it correctly avoids restating full return 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 description coverage is 100%, so the schema already documents all six parameters and the baseline would be 3. The description adds genuine meaning on top by tying ingestMode to external cost and vision behavior and by noting the framework-phases vs customPhases choice, which helps an agent pick a mode rather than just read an enum label.
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 pair (read a FigJam/Figma URL) plus the concrete effect (persist a local snapshot), and explicitly names the three sibling tools that consume that snapshot (get_board_context, answer_from_board, diff_board). An agent can distinguish this from its siblings 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 clear conditional guidance: 'Re-ingest to refresh stale content' establishes when to call it again, and the mode sentence tells the agent when cost/vision tradeoffs apply (max_speed skips vision). It stops short of naming an explicit alternative or a when-not-to-use condition, so it is strong context rather than full routing guidance.
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.
2 tool updates
v0.8.0- Changed
get_board_context2 fields changed- changed
Input schema / properties / nodeIds / descriptionPrevious value: -"Read exact source nodes, all rows of a table or the row of a table cell, or every excerpt inside a page, section, frame or group by its ID (nested sections included, in reading order); cannot be combined with topic"New value: +"Read exact source nodes, all rows of a table or the row of a table cell, or every excerpt inside a page, section, frame or group by its ID (nested sections included, in reading order); several IDs in one call share every page in request order; cannot be combined with topic" - added
Input schema / properties / outsideSectionsAdded value: +{ + "description": "Read every excerpt that lies in no section, cluster by cluster in reading order, tables row by row; on a board without sections, all excerpts. Cannot be combined with topic or nodeIds", + "type": "boolean" +}
- Changed
ingest_board2 fields changed- changed
Input schema / properties / forceFullIngest / descriptionPrevious value: -"Deliberately skip all caching and incremental reuse, including successful interpretations. The vision time budget still applies. Model/configuration changes are detected automatically. Default: false"New value: +"Download and extract the board again, skipping the unchanged-board check and cache, and redo the image interpretation of the chosen ingestMode. Interpretations this mode does not redo (all in max_speed; in balanced those of clusters without image or drawing) are kept while a cluster's content is unchanged. The vision time budget still applies, so balanced and max_quality may need several ingests until every image is interpreted again. An unchanged board gives no new snapshot for diff_board, even with forceFullIngest. Model/configuration changes are detected automatically. Default: false" - added
Output schema / properties / qualityReport / properties / figmaRequestsAdded value: +{ + "additionalProperties": false, + "description": "Figma requests of this ingest for images: image fills (Tier 2) and renders (Tier 1)", + "properties": { + "imageFills": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "renders": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "imageFills", + "renders" + ], + "type": "object" +}
2 tool updates
v0.7.0- Changed
answer_from_board1 field changed- changed
Output schema / properties / citations / items / properties / sourceType / enumPrevious value: -[ - "board_text", - "table_cell", - "board_metadata", - "model_interpretation", - "cluster_summary" -]New value: +[ + "board_text", + "table_cell", + "table_row", + "board_metadata", + "model_interpretation", + "cluster_summary" +]
- Changed
get_board_context9 fields changed- changed
Input schema / properties / maxChars / descriptionPrevious value: -"Character budget for the whole structured result (JSON of structuredContent, including contextText; default 12000)"New value: +"Character budget for each representation: the readable text content and the JSON of structuredContent (default 12000)" - changed
Input schema / properties / nodeIds / descriptionPrevious value: -"Read exact source nodes or table cells; cannot be combined with topic"New value: +"Read exact source nodes, all rows of a table or the row of a table cell, or every excerpt inside a page, section, frame or group by its ID (nested sections included, in reading order); cannot be combined with topic" - added
Output schema / properties / clusters / items / properties / pageNameAdded value: +{ + "description": "Page of this cluster's excerpts on this page of results; excerpts repeat it only where they differ", + "maxLength": 160, + "type": "string" +} - added
Output schema / properties / clusters / items / properties / sectionNamesAdded value: +{ + "description": "Enclosing sections, outermost first, of this cluster's excerpts; excerpts repeat them only where they differ", + "items": { + "maxLength": 80, + "type": "string" + }, + "maxItems": 16, + "type": "array" +} - added
Output schema / properties / clusters / items / properties / summary / descriptionAdded value: +"Model summary of the cluster; empty for deterministic clusters, whose excerpts carry the text" - added
Output schema / properties / contextText / descriptionAdded value: +"Orientation: board header, page position, board overview or subsections. The excerpts are in evidence; the text content carries the readable version" - added
Output schema / properties / evidence / items / properties / pageName / descriptionAdded value: +"Only for an excerpt outside the listed clusters or whose location differs from its cluster's" - added
Output schema / properties / evidence / items / properties / sectionNames / descriptionAdded value: +"Same rule as pageName; an empty list means outside sections" - changed
Output schema / properties / evidence / items / properties / sourceType / enumPrevious value: -[ - "board_text", - "table_cell", - "board_metadata", - "model_interpretation", - "cluster_summary" -]New value: +[ + "board_text", + "table_cell", + "table_row", + "board_metadata", + "model_interpretation", + "cluster_summary" +]
1 tool update
v0.6.0- Changed
get_board_context1 field changed- changed
Input schema / properties / maxChars / descriptionPrevious value: -"Character budget for the readable context (default 12000)"New value: +"Character budget for the whole structured result (JSON of structuredContent, including contextText; default 12000)"
5 tool updates
v0.4.0- Changed
answer_from_board13 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / boardId / descriptionAdded value: +"The Figma file key returned by ingest_board" - added
Input schema / properties / boardId / maxLengthAdded value: +128 - added
Input schema / properties / boardId / minLengthAdded value: +6 - added
Input schema / properties / boardId / patternAdded value: +"^[A-Za-z0-9]+$" - added
Input schema / properties / question / maxLengthAdded value: +2000 - added
Input schema / properties / question / minLengthAdded value: +1 - added
Input schema / properties / snapshotIdAdded value: +{ + "maxLength": 128, + "minLength": 1, + "pattern": "^[A-Za-z0-9_-]+$", + "type": "string" +} - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / properties / citationsAdded value: +{ + "items": { + "additionalProperties": false, + "properties": { + "clusterId": { + "type": "string" + }, + "clusterLabel": { + "type": "string" + }, + "column": { + "type": "number" + }, + "evidenceId": { + "type": "string" + }, + "modelDerived": { + "type": "boolean" + }, + "nodeId": { + "type": "string" + }, + "nodeName": { + "maxLength": 160, + "type": "string" + }, + "pageId": { + "type": "string" + }, + "pageName": { + "maxLength": 160, + "type": "string" + }, + "quote": { + "type": "string" + }, + "row": { + "type": "number" + }, + "sectionIds": { + "items": { + "type": "string" + }, + "type": "array" + }, + "sectionNames": { + "items": { + "maxLength": 80, + "type": "string" + }, + "maxItems": 16, + "type": "array" + }, + "snapshotId": { + "type": "string" + }, + "sourceType": { + "enum": [ + "board_text", + "table_cell", + "board_metadata", + "model_interpretation", + "cluster_summary" + ], + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "evidenceId", + "snapshotId", + "nodeId", + "quote", + "url", + "sourceType", + "modelDerived" + ], + "type": "object" + }, + "type": "array" +} - added
Output schema / properties / snapshotIdAdded value: +{ + "type": "string" +} - changed
Output schema / requiredPrevious value: -[ - "answer", - "citedClusters" -]New value: +[ + "answer", + "citedClusters", + "snapshotId", + "citations" +]
- Added
diagnose_llm_config - Added
diff_board - Changed
get_board_context27 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / boardId / descriptionAdded value: +"The Figma file key returned by ingest_board" - added
Input schema / properties / boardId / maxLengthAdded value: +128 - added
Input schema / properties / boardId / minLengthAdded value: +6 - added
Input schema / properties / boardId / patternAdded value: +"^[A-Za-z0-9]+$" - added
Input schema / properties / cursorAdded value: +{ + "description": "Continue a page using the same query, snapshot, limit and maxChars", + "maxLength": 2048, + "minLength": 1, + "type": "string" +} - added
Input schema / properties / limitAdded value: +{ + "default": 20, + "description": "Maximum evidence excerpts per page (default 20)", + "maximum": 100, + "minimum": 1, + "type": "integer" +} - added
Input schema / properties / maxCharsAdded value: +{ + "default": 12000, + "description": "Character budget for the readable context (default 12000)", + "maximum": 24000, + "minimum": 512, + "type": "integer" +} - added
Input schema / properties / nodeIdsAdded value: +{ + "description": "Read exact source nodes or table cells; cannot be combined with topic", + "items": { + "maxLength": 200, + "minLength": 1, + "type": "string" + }, + "maxItems": 50, + "minItems": 1, + "type": "array" +} - added
Input schema / properties / snapshotIdAdded value: +{ + "description": "Read a specific retained snapshot instead of the latest board", + "maxLength": 128, + "minLength": 1, + "pattern": "^[A-Za-z0-9_-]+$", + "type": "string" +} - added
Input schema / properties / topic / maxLengthAdded value: +200 - added
Input schema / properties / topic / minLengthAdded value: +1 - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / properties / clusters / items / properties / modelDerivedAdded value: +{ + "description": "True for model summaries and summaries whose non-model origin cannot be established", + "type": "boolean" +} - added
Output schema / properties / clusters / items / properties / sourceNodeIds / descriptionAdded value: +"Source nodes displayed on this page, not citations validating the cluster summary" - added
Output schema / properties / clusters / items / properties / summarySourceAdded value: +{ + "description": "Origin of the derived cluster summary; the summary is not verbatim source evidence", + "enum": [ + "vision_llm", + "text_llm", + "deterministic", + "cache", + "unknown" + ], + "type": "string" +} - changed
Output schema / properties / clusters / items / requiredPrevious value: -[ - "label", - "summary", - "sourceNodeIds" -]New value: +[ + "label", + "summary", + "summarySource", + "modelDerived", + "sourceNodeIds" +] - added
Output schema / properties / connectionsAdded value: +{ + "items": { + "additionalProperties": false, + "properties": { + "connectorId": { + "type": "string" + }, + "direction": { + "enum": [ + "forward", + "reverse", + "bidirectional", + "undirected" + ], + "type": "string" + }, + "fromNodeId": { + "type": "string" + }, + "label": { + "type": "string" + }, + "toNodeId": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "connectorId", + "fromNodeId", + "toNodeId", + "direction", + "url" + ], + "type": "object" + }, + "type": "array" +} - added
Output schema / properties / evidenceAdded value: +{ + "items": { + "additionalProperties": false, + "properties": { + "chunkIndex": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "clusterId": { + "type": "string" + }, + "clusterLabel": { + "type": "string" + }, + "column": { + "type": "number" + }, + "evidenceId": { + "type": "string" + }, + "modelDerived": { + "type": "boolean" + }, + "nodeId": { + "type": "string" + }, + "nodeName": { + "maxLength": 160, + "type": "string" + }, + "pageId": { + "type": "string" + }, + "pageName": { + "maxLength": 160, + "type": "string" + }, + "renderNodeId": { + "type": "string" + }, + "row": { + "type": "number" + }, + "sectionIds": { + "items": { + "type": "string" + }, + "type": "array" + }, + "sectionNames": { + "items": { + "maxLength": 80, + "type": "string" + }, + "maxItems": 16, + "type": "array" + }, + "snapshotId": { + "type": "string" + }, + "sourceType": { + "enum": [ + "board_text", + "table_cell", + "board_metadata", + "model_interpretation", + "cluster_summary" + ], + "type": "string" + }, + "text": { + "type": "string" + }, + "truncated": { + "type": "boolean" + }, + "url": { + "type": "string" + } + }, + "required": [ + "evidenceId", + "snapshotId", + "nodeId", + "text", + "sourceType", + "modelDerived", + "chunkIndex", + "url", + "truncated" + ], + "type": "object" + }, + "type": "array" +} - added
Output schema / properties / nextCursorAdded value: +{ + "type": "string" +} - added
Output schema / properties / relationsAdded value: +{ + "description": "Cluster-to-cluster relations derived from connector arrows", + "items": { + "additionalProperties": false, + "properties": { + "edgeCount": { + "exclusiveMinimum": 0, + "maximum": 9007199254740991, + "type": "integer" + }, + "from": { + "description": "Label of the source cluster", + "type": "string" + }, + "label": { + "description": "Connector label(s), when the arrows are annotated", + "type": "string" + }, + "to": { + "description": "Label of the target cluster", + "type": "string" + } + }, + "required": [ + "from", + "to", + "edgeCount" + ], + "type": "object" + }, + "type": "array" +} - added
Output schema / properties / snapshotIdAdded value: +{ + "type": "string" +} - added
Output schema / properties / totalMatchedAdded value: +{ + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" +} - added
Output schema / properties / truncatedAdded value: +{ + "type": "boolean" +} - added
Output schema / properties / truncationAdded value: +{ + "additionalProperties": false, + "description": "Explicit omissions from structured results and the readable text", + "properties": { + "omittedConnections": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "omittedRelations": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "omittedTextConnections": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "omittedTextRelations": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "remainingEvidence": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "remainingEvidence", + "omittedConnections", + "omittedRelations", + "omittedTextConnections", + "omittedTextRelations" + ], + "type": "object" +} - changed
Output schema / requiredPrevious value: -[ - "contextText", - "clusters" -]New value: +[ + "contextText", + "clusters", + "snapshotId", + "evidence", + "connections", + "totalMatched", + "truncated", + "truncation" +]
- Changed
ingest_board22 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / customPhasesAdded value: +{ + "description": "Free-form phase names to map clusters onto (e.g. [\"Ideen\", \"Feedback\", \"Offene Fragen\"]); overrides docStructureHint", + "items": { + "maxLength": 80, + "minLength": 1, + "type": "string" + }, + "maxItems": 12, + "minItems": 1, + "type": "array" +} - changed
Input schema / properties / docStructureHint / descriptionPrevious value: -"How to interpret the board's structure when mapping clusters to phases"New value: +"Built-in framework used to map clusters to phases" - changed
Input schema / properties / docStructureHint / enumPrevious value: -[ - "double_diamond", - "freeform" -]New value: +[ + "freeform", + "double_diamond", + "lean_canvas", + "retro", + "user_journey" +] - added
Input schema / properties / figmaAccessToken / maxLengthAdded value: +512 - added
Input schema / properties / figmaAccessToken / minLengthAdded value: +1 - added
Input schema / properties / figmaFileUrl / maxLengthAdded value: +2048 - added
Input schema / properties / forceFullIngestAdded value: +{ + "description": "Deliberately skip all caching and incremental reuse, including successful interpretations. The vision time budget still applies. Model/configuration changes are detected automatically. Default: false", + "type": "boolean" +} - added
Input schema / properties / ingestModeAdded value: +{ + "default": "balanced", + "description": "How aggressively to use vision LLM calls during ingest", + "enum": [ + "balanced", + "max_quality", + "max_speed" + ], + "type": "string" +} - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / properties / boardId / maxLengthAdded value: +128 - added
Output schema / properties / boardId / minLengthAdded value: +6 - added
Output schema / properties / boardId / patternAdded value: +"^[A-Za-z0-9]+$" - added
Output schema / properties / clusterCount / maximumAdded value: +9007199254740991 - added
Output schema / properties / figmaVersionAdded value: +{ + "type": "string" +} - added
Output schema / properties / freshnessCheckedAtAdded value: +{ + "type": "string" +} - added
Output schema / properties / ingestModeAdded value: +{ + "enum": [ + "balanced", + "max_quality", + "max_speed" + ], + "type": "string" +} - added
Output schema / properties / persistenceWarningAdded value: +{ + "type": "string" +} - added
Output schema / properties / qualityReportAdded value: +{ + "additionalProperties": false, + "properties": { + "cachedClusters": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "deterministicClusters": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "fallbackCount": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "fallbackReasons": { + "additionalProperties": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "propertyNames": { + "type": "string" + }, + "type": "object" + }, + "incompleteClusters": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "modelsUsed": { + "items": { + "type": "string" + }, + "type": "array" + }, + "nextRetryAt": { + "type": "number" + }, + "reusedClusters": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "visionClusters": { + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "modelsUsed", + "cachedClusters", + "deterministicClusters", + "visionClusters", + "fallbackCount" + ], + "type": "object" +} - added
Output schema / properties / relationCountAdded value: +{ + "description": "Directed cluster-to-cluster relations derived from connector arrows", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" +} - added
Output schema / properties / snapshotIdAdded value: +{ + "type": "string" +}
3 tool updates
v0.1.0- First observed
answer_from_board - First observed
get_board_context - First observed
ingest_board
TDQS
Scored across 5 tools
Each tool has a distinct role: ingest_board persists a snapshot, get_board_context reads structured context, answer_from_board handles single-question LLM Q&A, diff_board compares snapshots, and diagnose_llm_config tests configuration. Descriptions explicitly delineate boundaries (e.g., answer_from_board is not for summaries; get_board_context is not for single questions), eliminating overlap.
All names use snake_case with a verb-first pattern (ingest_board, get_board_context, answer_from_board, diff_board, diagnose_llm_config). The convention is consistent and predictable throughout.
Five tools are well-scoped for the workflow: ingest, read, answer, diff, and config check. No redundant or trivial tools are present, and the count sits comfortably within the typical 3-15 range.
The toolset covers ingestion, context retrieval, Q&A, diffing, and LLM diagnostics, forming a coherent lifecycle. Minor gaps exist, such as no explicit tool to list or delete stored snapshots, but agents can work around this by re-ingesting since local history is bounded.
Maintenance
Related MCP Connectors
Access Pollinations models and API capabilities through agent tools.
Bounded tools for rendering, extraction, RAG, enrichment, local discovery and review analysis.
Astra DB tools for agents: schema, find, vector search, guarded writes, and interactive views.
Enterprise memory, search, and context for frontier AI. 38 tools for business intelligence.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables MCP-compatible LLMs to interact with Miro whiteboards to manage boards, create and manipulate shapes, and organize content through grouping tools.-
- FlicenseNot gradedqualityDmaintenanceEnables AI agents to programmatically interact with a Miro board through the Miro API, supporting operations like creating items, updating positions, and managing connectors.16-
- FlicenseBqualityDmaintenanceEnables AI agents to read, inspect, and export Figma designs programmatically. Provides tools for listing components, styles, and exporting assets in various formats.51-
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to visualize tasks on a collaborative Sketchbord whiteboard by composing content into diagrams, editing them incrementally, and reading back the board including user-drawn additions.MIT