figjam-context-mcp 0.0.0-stage → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/.env.example +70 -0
  2. package/CHANGELOG.md +58 -0
  3. package/LICENSE +21 -0
  4. package/README.md +150 -2
  5. package/SECURITY.md +26 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.js +20 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/lib/boardDiff.d.ts +55 -0
  10. package/dist/lib/boardDiff.js +285 -0
  11. package/dist/lib/boardDiff.js.map +1 -0
  12. package/dist/lib/cache.d.ts +9 -0
  13. package/dist/lib/cache.js +63 -0
  14. package/dist/lib/cache.js.map +1 -0
  15. package/dist/lib/connectorGraph.d.ts +32 -0
  16. package/dist/lib/connectorGraph.js +121 -0
  17. package/dist/lib/connectorGraph.js.map +1 -0
  18. package/dist/lib/docStructureMapper.d.ts +24 -0
  19. package/dist/lib/docStructureMapper.js +121 -0
  20. package/dist/lib/docStructureMapper.js.map +1 -0
  21. package/dist/lib/env.d.ts +2 -0
  22. package/dist/lib/env.js +25 -0
  23. package/dist/lib/env.js.map +1 -0
  24. package/dist/lib/evidence.d.ts +63 -0
  25. package/dist/lib/evidence.js +474 -0
  26. package/dist/lib/evidence.js.map +1 -0
  27. package/dist/lib/figmaApi.d.ts +28 -0
  28. package/dist/lib/figmaApi.js +180 -0
  29. package/dist/lib/figmaApi.js.map +1 -0
  30. package/dist/lib/llmClient.d.ts +65 -0
  31. package/dist/lib/llmClient.js +459 -0
  32. package/dist/lib/llmClient.js.map +1 -0
  33. package/dist/lib/llmOutputBudgets.d.ts +6 -0
  34. package/dist/lib/llmOutputBudgets.js +13 -0
  35. package/dist/lib/llmOutputBudgets.js.map +1 -0
  36. package/dist/lib/llmTimeouts.d.ts +12 -0
  37. package/dist/lib/llmTimeouts.js +22 -0
  38. package/dist/lib/llmTimeouts.js.map +1 -0
  39. package/dist/lib/modelRegistry.d.ts +12 -0
  40. package/dist/lib/modelRegistry.js +91 -0
  41. package/dist/lib/modelRegistry.js.map +1 -0
  42. package/dist/lib/nodeTree.d.ts +9 -0
  43. package/dist/lib/nodeTree.js +174 -0
  44. package/dist/lib/nodeTree.js.map +1 -0
  45. package/dist/lib/persistentCache.d.ts +32 -0
  46. package/dist/lib/persistentCache.js +301 -0
  47. package/dist/lib/persistentCache.js.map +1 -0
  48. package/dist/lib/spatialCluster.d.ts +58 -0
  49. package/dist/lib/spatialCluster.js +340 -0
  50. package/dist/lib/spatialCluster.js.map +1 -0
  51. package/dist/lib/visionInterpreter.d.ts +14 -0
  52. package/dist/lib/visionInterpreter.js +207 -0
  53. package/dist/lib/visionInterpreter.js.map +1 -0
  54. package/dist/schemas/answerFromBoard.d.ts +75 -0
  55. package/dist/schemas/answerFromBoard.js +28 -0
  56. package/dist/schemas/answerFromBoard.js.map +1 -0
  57. package/dist/schemas/common.d.ts +14 -0
  58. package/dist/schemas/common.js +59 -0
  59. package/dist/schemas/common.js.map +1 -0
  60. package/dist/schemas/diagnoseLlmConfig.d.ts +35 -0
  61. package/dist/schemas/diagnoseLlmConfig.js +20 -0
  62. package/dist/schemas/diagnoseLlmConfig.js.map +1 -0
  63. package/dist/schemas/diffBoard.d.ts +118 -0
  64. package/dist/schemas/diffBoard.js +61 -0
  65. package/dist/schemas/diffBoard.js.map +1 -0
  66. package/dist/schemas/getBoardContext.d.ts +255 -0
  67. package/dist/schemas/getBoardContext.js +77 -0
  68. package/dist/schemas/getBoardContext.js.map +1 -0
  69. package/dist/schemas/ingestBoard.d.ts +96 -0
  70. package/dist/schemas/ingestBoard.js +88 -0
  71. package/dist/schemas/ingestBoard.js.map +1 -0
  72. package/dist/server.d.ts +16 -0
  73. package/dist/server.js +131 -0
  74. package/dist/server.js.map +1 -0
  75. package/dist/tools/answerFromBoard.d.ts +9 -0
  76. package/dist/tools/answerFromBoard.js +243 -0
  77. package/dist/tools/answerFromBoard.js.map +1 -0
  78. package/dist/tools/diagnoseLlmConfig.d.ts +4 -0
  79. package/dist/tools/diagnoseLlmConfig.js +169 -0
  80. package/dist/tools/diagnoseLlmConfig.js.map +1 -0
  81. package/dist/tools/diffBoard.d.ts +11 -0
  82. package/dist/tools/diffBoard.js +49 -0
  83. package/dist/tools/diffBoard.js.map +1 -0
  84. package/dist/tools/getBoardContext.d.ts +3 -0
  85. package/dist/tools/getBoardContext.js +157 -0
  86. package/dist/tools/getBoardContext.js.map +1 -0
  87. package/dist/tools/ingestBoard.d.ts +8 -0
  88. package/dist/tools/ingestBoard.js +667 -0
  89. package/dist/tools/ingestBoard.js.map +1 -0
  90. package/dist/types.d.ts +145 -0
  91. package/dist/types.js +6 -0
  92. package/dist/types.js.map +1 -0
  93. package/docs/pipeline.gif +0 -0
  94. package/package.json +73 -4
  95. package/server.json +48 -0
package/.env.example ADDED
@@ -0,0 +1,70 @@
1
+ # Figma personal access token
2
+ # figma.com → Settings → Security → Personal access tokens
3
+ # Scope: file_content:read. The token must have access to the requested board.
4
+ # Prefer environment credentials; tool arguments can appear in client logs.
5
+ FIGMA_ACCESS_TOKEN=
6
+
7
+ # --- LLM (vision interpretation + answer synthesis) ---------------------
8
+ # OpenAI-compatible chat completions endpoint. Model quotas/prices can change.
9
+ # Board text/images are sent to this provider for vision and Q&A; use max_speed
10
+ # and get_board_context for deterministic context without model calls.
11
+ #
12
+ # 1) OpenRouter (default): create a key at https://openrouter.ai/keys.
13
+ # The student-free preset uses nvidia/nemotron-3-super-120b-a12b:free for
14
+ # text, then the openrouter/free router, and the router alone for vision.
15
+ # Free models and their limits change; run diagnose_llm_config to check.
16
+ #
17
+ # 2) GitHub Models: free with any GitHub account
18
+ # (https://github.com/marketplace/models) — set
19
+ # LLM_BASE_URL=https://models.github.ai/inference and use a GitHub PAT
20
+ # as LLM_API_KEY, with a vision-capable model id.
21
+ LLM_BASE_URL=https://openrouter.ai/api/v1
22
+ LLM_API_KEY=
23
+ # Supported presets: student-free
24
+ LLM_MODEL_PRESET=student-free
25
+ # Optional role-specific overrides. Legacy LLM_VISION_MODEL / LLM_TEXT_MODEL
26
+ # still work and become the first candidate in each list.
27
+ # LLM_VISION_MODELS=openrouter/free
28
+ # LLM_TEXT_MODELS=nvidia/nemotron-3-super-120b-a12b:free,openrouter/free
29
+ # LLM_FAST_TEXT_MODELS=nvidia/nemotron-3-super-120b-a12b:free,openrouter/free
30
+ # LLM_PROVIDER_REQUIRE_PARAMETERS=true
31
+ # Optional answer-only reasoning effort: none, low, medium or high.
32
+ # Omit to retain provider defaults; support depends on the configured model.
33
+ # LLM_ANSWER_REASONING_EFFORT=none
34
+
35
+ # --- Timeout controls ----------------------------------------------------
36
+ # Defaults are tuned so MCP UI clients do not wait forever on slow providers.
37
+ # Increase these only if your MCP client/request timeout is also higher.
38
+ # FIGMA_REQUEST_TIMEOUT_MS=15000
39
+ # FIGMA_FILE_REQUEST_TIMEOUT_MS=60000
40
+ # Global LLM request timeout; when set, it applies to roles without their own value.
41
+ # LLM_REQUEST_TIMEOUT_MS=20000
42
+ # Answers and text diagnostics: explicit role value > explicit global value > 40000 ms.
43
+ # answer_from_board stops after 50000 ms across all model candidates (or this value, if larger).
44
+ # LLM_ANSWER_REQUEST_TIMEOUT_MS=40000
45
+ # Vision: explicit role value > explicit global value > 60000 ms.
46
+ # LLM_VISION_REQUEST_TIMEOUT_MS=60000
47
+ # LLM_SDK_MAX_RETRIES=0
48
+ # LLM_RATE_LIMIT_RETRIES=1
49
+ # LLM_RATE_LIMIT_MAX_BACKOFF_MS=5000
50
+ # LLM_ANSWER_MAX_OUTPUT_TOKENS=2048
51
+ # LLM_VISION_MAX_OUTPUT_TOKENS=4096
52
+ # LLM_ANSWER_TOP_K=6
53
+ # LLM_ANSWER_PROMPT_MAX_CHARS=24000
54
+ # INGEST_BOARD_VISION_BUDGET_MS=40000
55
+ # INGEST_BOARD_MIN_VISION_SLOT_MS=10000
56
+ # INGEST_BOARD_VISION_CONCURRENCY=3
57
+ # FIGMA_SCREENSHOT_DOWNLOAD_CONCURRENCY=3
58
+
59
+ # --- Cache controls ------------------------------------------------------
60
+ # Maximum full boards retained in process memory. Older entries remain on
61
+ # disk and are restored on demand.
62
+ # FIGJAM_MCP_MEMORY_CACHE_MAX_BOARDS=10
63
+
64
+ # Private cache root (v4/ is created beneath it). Omit for the per-user OS default.
65
+ # macOS: ~/Library/Caches/figjam-context-mcp
66
+ # Windows: %LOCALAPPDATA%/figjam-context-mcp
67
+ # Linux: $XDG_CACHE_HOME/figjam-context-mcp or ~/.cache/figjam-context-mcp
68
+ # Use an absolute dedicated directory, not a shared project directory.
69
+ # FIGJAM_MCP_CACHE_DIR=/absolute/private/path/figjam-context-mcp
70
+ # Legacy v3 data is preserved; re-ingest boards to populate v4.
package/CHANGELOG.md ADDED
@@ -0,0 +1,58 @@
1
+ # Changelog
2
+
3
+ ## 0.4.1 — 2026-10-19
4
+
5
+ - `answer_from_board` waits up to 40 s per model request (`LLM_ANSWER_REQUEST_TIMEOUT_MS`)
6
+ instead of 20 s and stops after 50 s across all model candidates, so large prompts
7
+ on free reasoning models finish inside a 60-second client timeout. The text checks of
8
+ `diagnose_llm_config` use the same timeout, and timeout errors name the setting to change.
9
+ - Tool descriptions point overviews and whole-board summaries to `get_board_context`;
10
+ `answer_from_board` is for one specific question.
11
+ - `ingest_board` renders screenshots of several clusters per Figma request (up to
12
+ 18 nodes) instead of one request per cluster, saving Tier 1 Figma requests.
13
+ - Vision summaries keep table values and statistical notation literally and name
14
+ a statistic such as a confidence interval only when a legend identifies it.
15
+ - Releases are published from CI with npm provenance.
16
+ - Dependency updates: `openai` 7.34, `dotenv` 18.0.8.
17
+
18
+ ## 0.4.0 — 2026-10-18
19
+
20
+ - New `student-free` defaults: text uses `nvidia/nemotron-3-super-120b-a12b:free`,
21
+ then `openrouter/free`; vision uses `openrouter/free`. OpenRouter's
22
+ `provider.require_parameters` is no longer sent to other providers.
23
+ - `ingest_board` fits a 60-second client timeout: the vision phase defaults to
24
+ 40 s (`INGEST_BOARD_VISION_BUDGET_MS`). Unfinished clusters continue on the
25
+ next ingest, and the summary says so.
26
+ - `diagnose_llm_config` runs its checks in parallel with the same output budgets
27
+ as the real calls and answers within 45 s.
28
+ - Stable MCP TypeScript SDK v2 and Zod 4 with unchanged tool names and required
29
+ fields; cancellation, ingest progress and tool annotations. Requires Node.js 22.12+.
30
+ - Answers cite source nodes with exact quotes and Figma links, and report
31
+ insufficient evidence instead of guessing.
32
+ - Answers keep confirmed statuses, explicit negatives, open tasks, proposals and
33
+ conflicting sources apart. Optional `LLM_ANSWER_REASONING_EFFORT` for answers.
34
+ - `get_board_context` adds pagination, character budgets, exact node lookups and
35
+ local BM25 search over original text, table cells and names. Topics without
36
+ matches return empty results.
37
+ - Tables, pages, sections and arrow direction are preserved. Arrows anchored to
38
+ the page canvas no longer create connections.
39
+ - `diff_board` compares the latest snapshot with an earlier one (20 are kept),
40
+ including table-cell, visual and connector changes.
41
+ - Re-ingests reuse unchanged clusters and skip the download when Figma reports
42
+ the same version. Model or prompt changes invalidate interpretations automatically.
43
+ - Ingest results report why vision is incomplete (time budget, timeout, rate
44
+ limit, configuration, access) and when to retry; Retry-After is respected.
45
+ - Private v4 cache with atomic writes and a write lock. Legacy v3 caches are kept;
46
+ re-ingest once after upgrading.
47
+ - Bounded work: 64 MiB per file, 100,000 nodes, 8 MiB per image, 64 MiB of
48
+ screenshots per ingest, and per-request timeouts for Figma and the LLM.
49
+ - Vision summaries keep visible facts and diagram direction and are marked as
50
+ model-derived.
51
+ - Offline retrieval and diff evaluation with 20 synthetic cases
52
+ (`npm run eval:retrieval`); MIT license and CI on Linux, macOS and Windows.
53
+
54
+ ## 0.3.0 — Development history
55
+
56
+ Added board snapshot diffs, incremental interpretation, bounded concurrent vision,
57
+ connector relations and an npm tarball startup smoke test. No published release
58
+ date is asserted for this development version.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ecestnrkl
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,151 @@
1
- # Temporary Holding Version
1
+ # figjam-context-mcp
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A local MCP server that turns FigJam boards into source-cited context for LLMs.
4
+ It reads a board through the Figma REST API, groups stickies, tables, images and
5
+ arrows into clusters, and answers questions with links back to the original nodes.
6
+
7
+ ![Pipeline: a FigJam board is read through the Figma API, clustered by geometry, refined with vision and turned into LLM-ready context](https://raw.githubusercontent.com/ecestnrkl/figjam-mcp/main/docs/pipeline.gif)
8
+
9
+ ## Why
10
+
11
+ Workshop boards hold research notes, decisions and open questions, but an LLM
12
+ cannot read a canvas. Screenshots and PDF exports lose tables, arrow direction
13
+ and the link to the source. This server keeps the board's structure and cites
14
+ every answer to the nodes it came from.
15
+
16
+ ## Tools
17
+
18
+ | Tool | What it does | LLM call |
19
+ | --- | --- | --- |
20
+ | `ingest_board` | Reads a board, clusters it and saves a local snapshot. Re-ingests reuse unchanged clusters. | In `balanced` (default) and `max_quality` mode |
21
+ | `get_board_context` | Returns paginated, source-linked context, optionally for a topic or exact node IDs. Use it for overviews, summaries and documentation. | No |
22
+ | `answer_from_board` | 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 |
23
+ | `diff_board` | Compares two snapshots: new, removed and changed clusters, nodes, table cells and arrows. | No |
24
+ | `diagnose_llm_config` | Tests the configured models with small text and image JSON checks. | Yes |
25
+
26
+ ## Quick start
27
+
28
+ Requires Node.js 22.12 or later.
29
+
30
+ 1. Create a Figma personal access token under **Settings → Security → Personal
31
+ access tokens** with the scope `file_content:read`. Add `file_metadata:read`
32
+ so re-ingests of an unchanged board skip the download. The token's account
33
+ needs access to the board.
34
+ 2. Optional: create an OpenRouter key at
35
+ [openrouter.ai/keys](https://openrouter.ai/keys). It enables image
36
+ interpretation, `answer_from_board` and `diagnose_llm_config`. Without it, use
37
+ `ingestMode: "max_speed"` with `get_board_context` and `diff_board`.
38
+ 3. Add the server to your MCP client:
39
+
40
+ ```json
41
+ {
42
+ "mcpServers": {
43
+ "figjam-context": {
44
+ "command": "npx",
45
+ "args": ["-y", "figjam-context-mcp"],
46
+ "env": {
47
+ "FIGMA_ACCESS_TOKEN": "your-figma-token",
48
+ "LLM_BASE_URL": "https://openrouter.ai/api/v1",
49
+ "LLM_API_KEY": "your-openrouter-key"
50
+ }
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ For Claude Code:
57
+
58
+ ```bash
59
+ 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
60
+ ```
61
+
62
+ Then ask your assistant to ingest a board URL, for example *"Ingest
63
+ https://www.figma.com/board/FILE_KEY/Name and list the open questions."*
64
+ The `boardId` of every later call is the file key from that URL.
65
+
66
+ All settings: [configuration](https://github.com/ecestnrkl/figjam-mcp/blob/main/docs/configuration.md).
67
+ Problems: [troubleshooting](https://github.com/ecestnrkl/figjam-mcp/blob/main/docs/troubleshooting.md).
68
+
69
+ ## How it works
70
+
71
+ 1. **Read.** `ingest_board` downloads the board through the Figma REST API. If
72
+ Figma reports the same version as the last ingest, the download is skipped.
73
+ 2. **Normalize.** Nodes become text, table cells, images and connectors, with
74
+ their pages and sections.
75
+ 3. **Cluster.** Nearby nodes are grouped by rotation-aware distance. Arrows
76
+ between groups become directed relations.
77
+ 4. **Interpret.** In `balanced` mode, clusters with images or little text get a
78
+ vision-model summary within a 40-second budget; the rest keep their extracted
79
+ text. Unfinished clusters continue on the next ingest.
80
+ 5. **Serve.** The snapshot is saved to a private local cache.
81
+ `get_board_context` searches it (BM25 over original text, table cells and
82
+ names), `answer_from_board` answers with citations and `diff_board` compares
83
+ snapshots.
84
+
85
+ ## Models and cost
86
+
87
+ The default preset `student-free` uses free OpenRouter models: text goes to
88
+ `nvidia/nemotron-3-super-120b-a12b:free` and then `openrouter/free`; images go to
89
+ `openrouter/free`, which picks a free model that accepts images and structured
90
+ outputs. The free default is best effort: free models change, hit rate limits
91
+ and time out.
92
+
93
+ - OpenRouter allows free models 20 requests per minute and 50 requests per day,
94
+ or 1,000 per day once you have bought at least 10 credits
95
+ ([limits](https://openrouter.ai/docs/api-reference/limits)).
96
+ - Figma limits file downloads and image renders by seat and plan: Dev and Full
97
+ seats on paid plans get 10–20 requests per minute, View and Collab seats and
98
+ files in Starter plans at most 20 per month
99
+ ([rate limits](https://developers.figma.com/docs/rest-api/rate-limits/)).
100
+ One render request covers up to 18 screenshots (about three clusters), so a
101
+ default ingest usually needs at most four; `max_speed` needs none.
102
+ - For a team, configure your own model: `LLM_BASE_URL` takes any
103
+ OpenAI-compatible endpoint, and `LLM_TEXT_MODELS` / `LLM_VISION_MODELS` set
104
+ the model lists.
105
+ - Run `diagnose_llm_config` after every model change. It checks JSON replies
106
+ and image understanding with synthetic inputs.
107
+
108
+ ## Privacy
109
+
110
+ - The server reads from Figma and never changes a board.
111
+ - `balanced` and `max_quality` ingests send board text and screenshots to the
112
+ configured LLM provider. `answer_from_board` sends the question and selected
113
+ excerpts. `max_speed` with `get_board_context` and `diff_board` sends nothing
114
+ to an LLM provider.
115
+ - Snapshots stay in a private per-user cache on your machine. Delete the cache
116
+ directory to remove them.
117
+ - Keep tokens in the client's environment. A token passed as a tool argument can
118
+ appear in client logs.
119
+
120
+ ## Limitations
121
+
122
+ - Image interpretation gets 40 seconds per ingest by default; large boards need
123
+ several ingests to interpret every image cluster.
124
+ - A client that cancels an ingest, for example after a 60-second timeout, gets
125
+ no partial result.
126
+ - Free models are best effort. Citations show where an answer comes from, not
127
+ that its conclusion is right.
128
+ - Search is lexical; synonyms without shared words do not match.
129
+ - Local stdio only; no hosted or multi-user mode.
130
+
131
+ Measured results: [evaluation](https://github.com/ecestnrkl/figjam-mcp/blob/main/docs/evaluation.md).
132
+
133
+ ## Development
134
+
135
+ ```bash
136
+ git clone https://github.com/ecestnrkl/figjam-mcp.git
137
+ cd figjam-mcp
138
+ npm ci
139
+ cp .env.example .env # add your tokens
140
+ npm run check # typecheck, tests, build, package validation
141
+ npm run package:smoke # install the packed package and exercise all tools
142
+ npm run eval:retrieval # offline retrieval and diff evaluation
143
+ npx @modelcontextprotocol/inspector --config inspector.config.json
144
+ ```
145
+
146
+ See [CONTRIBUTING.md](https://github.com/ecestnrkl/figjam-mcp/blob/main/CONTRIBUTING.md)
147
+ and the [changelog](https://github.com/ecestnrkl/figjam-mcp/blob/main/CHANGELOG.md).
148
+
149
+ ## License
150
+
151
+ [MIT](https://github.com/ecestnrkl/figjam-mcp/blob/main/LICENSE) © 2026 ecestnrkl
package/SECURITY.md ADDED
@@ -0,0 +1,26 @@
1
+ # Security policy
2
+
3
+ Security fixes target the latest release on the current development line.
4
+ Use supported Node.js LTS versions and apply dependency updates promptly.
5
+
6
+ ## Reporting
7
+
8
+ Use GitHub's **Report a vulnerability** option on the repository Security tab
9
+ when private reporting is enabled. If that option is unavailable, open an issue
10
+ requesting a private reporting channel without including exploit details or
11
+ secrets. Do not attach Figma tokens, provider keys, private board content or cache
12
+ files to public issues. There is no guaranteed response-time SLA.
13
+
14
+ ## Data boundary
15
+
16
+ This is a local stdio server intended for one user's trusted MCP client. It does
17
+ not expose an HTTP endpoint or implement multi-user access control. Figma tokens
18
+ belong in the environment. Board text/screenshots and questions can be sent to the
19
+ configured LLM provider; provider retention and costs depend on that provider.
20
+ Use max_speed ingest and get_board_context to avoid model calls.
21
+
22
+ Local snapshots contain board content and are stored in a private per-user cache.
23
+ Only connect clients trusted to read that data. Re-ingest after upgrading from
24
+ legacy cache formats. Stop the server before removing its cache directory.
25
+ Board content is untrusted input; source citations and prompt boundaries reduce
26
+ risk but do not make model output authoritative. Review cited source nodes.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "dotenv/config";
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ import "dotenv/config";
3
+ import { serveStdio } from "@modelcontextprotocol/server/stdio";
4
+ import { createServer, packageMetadata } from "./server.js";
5
+ async function main() {
6
+ if (process.argv.includes("--version") || process.argv.includes("-v")) {
7
+ process.stdout.write(`${packageMetadata.version}\n`);
8
+ return;
9
+ }
10
+ const handle = serveStdio(() => createServer());
11
+ const shutdown = () => { void handle.close(); };
12
+ process.once("SIGINT", shutdown);
13
+ process.once("SIGTERM", shutdown);
14
+ console.error(`${packageMetadata.name} running on stdio`);
15
+ }
16
+ main().catch((error) => {
17
+ console.error(`Fatal error starting ${packageMetadata.name}:`, error);
18
+ process.exit(1);
19
+ });
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE5D,KAAK,UAAU,IAAI;IACjB,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,eAAe,CAAC,OAAO,IAAI,CAAC,CAAC;QACrD,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IAChD,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACjC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAClC,OAAO,CAAC,KAAK,CAAC,GAAG,eAAe,CAAC,IAAI,mBAAmB,CAAC,CAAC;AAC5D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,OAAO,CAAC,KAAK,CAAC,wBAAwB,eAAe,CAAC,IAAI,GAAG,EAAE,KAAK,CAAC,CAAC;IACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,55 @@
1
+ import type { BoardData } from "../types.js";
2
+ /**
3
+ * Compares two ingest snapshots of the same board — "what changed since the
4
+ * last workshop?". Works on three levels:
5
+ * - nodes: added / removed / edited content nodes (structural containers
6
+ * and connectors excluded — connectors are diffed separately),
7
+ * - clusters: matched across snapshots by member overlap, then classified
8
+ * as unchanged (same content hash), modified, new, or removed,
9
+ * - connections: connector arrows diffed as (from, to, label) edges and
10
+ * rendered with the owning clusters' labels.
11
+ */
12
+ export interface ClusterSummaryRef {
13
+ label: string;
14
+ summary: string;
15
+ }
16
+ export interface ModifiedClusterDiff {
17
+ label: string;
18
+ previousLabel: string;
19
+ addedNodeCount: number;
20
+ removedNodeCount: number;
21
+ editedNodeCount: number;
22
+ }
23
+ export interface BoardDiffStats {
24
+ addedNodes: number;
25
+ removedNodes: number;
26
+ editedNodes: number;
27
+ newClusters: number;
28
+ removedClusters: number;
29
+ modifiedClusters: number;
30
+ unchangedClusters: number;
31
+ addedConnections: number;
32
+ removedConnections: number;
33
+ }
34
+ export interface BoardDiffResult {
35
+ stats: BoardDiffStats;
36
+ newClusters: ClusterSummaryRef[];
37
+ removedClusters: ClusterSummaryRef[];
38
+ modifiedClusters: ModifiedClusterDiff[];
39
+ addedConnections: string[];
40
+ removedConnections: string[];
41
+ summaryText: string;
42
+ tableCellChanges: TableCellChange[];
43
+ }
44
+ export interface TableCellChange {
45
+ tableNodeId: string;
46
+ cellId: string;
47
+ changeType: "added" | "removed" | "modified";
48
+ previousText?: string;
49
+ currentText?: string;
50
+ previousRow?: number;
51
+ previousColumn?: number;
52
+ currentRow?: number;
53
+ currentColumn?: number;
54
+ }
55
+ export declare function diffBoards(baseline: BoardData, current: BoardData): BoardDiffResult;