@autobest-ui/agent 1.0.0 → 1.0.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.
package/README.md CHANGED
@@ -20,30 +20,63 @@ npx --yes --package=@autobest-ui/agent@latest autobest-agent-sync react
20
20
 
21
21
  ## MCP
22
22
 
23
- 安装 Node.js 20 或更高版本后,无需在业务项目中安装依赖,可以直接通过 `npx` 启动 MCP:
23
+ 安装 Node.js 20 或更高版本后,无需在业务项目中安装依赖。直接在终端验证 MCP 时,必须同时提供对应的环境变量。
24
+
25
+ 先启动 PRD Knowledge HTTP API,再验证 RAG MCP:
26
+
27
+ ```bash
28
+ RAG_API_BASE_URL="http://127.0.0.1:3000/api/knowledge" \
29
+ npx --yes \
30
+ --package=@autobest-ui/agent@latest \
31
+ autobest-rag-mcp
32
+ ```
33
+
34
+ 验证 Azure PR MCP:
24
35
 
25
36
  ```bash
26
- npx --yes --package=@autobest-ui/agent@latest autobest-rag-mcp
27
- npx --yes --package=@autobest-ui/agent@latest autobest-azurepr-mcp
37
+ AZURE_DEVOPS_PAT="your-personal-access-token" \
38
+ npx --yes \
39
+ --package=@autobest-ui/agent@latest \
40
+ autobest-azurepr-mcp
28
41
  ```
29
42
 
30
- 同一个 npm 包暴露两个独立命令:
43
+ 启动成功后,MCP 会通过 stdio 持续等待客户端请求,终端没有输出属于正常状态,可按 `Ctrl+C` 停止。供 Codex 长期使用时,不要只执行上述临时命令,应将完整配置加入 `~/.codex/config.toml` 后重启 Codex。
44
+
45
+ 同一个 npm 包暴露三个独立命令:
31
46
 
32
47
  | 命令 | 用途 | 必需配置 |
33
48
  | ---------------------- | ------------------------------ | ------------------ |
34
49
  | `autobest-rag-mcp` | 连接 PRD Knowledge RAG API | `RAG_API_BASE_URL` |
35
50
  | `autobest-azurepr-mcp` | 读取 Azure DevOps Pull Request | `AZURE_DEVOPS_PAT` |
51
+ | `figma-mcp-bridge` | 连接本机 Figma Plugin | 无 |
36
52
 
37
53
  Codex 配置示例分别位于:
38
54
 
39
55
  - [RAG MCP 配置](mcp/rag-mcp-bridge/config.toml.example)
40
56
  - [Azure PR MCP 配置](mcp/azurepr-mcp-bridge/config.toml.example)
57
+ - [Figma MCP 配置](mcp/figma-mcp-bridge/config.toml.example)
41
58
 
42
59
  生产环境可将 `@latest` 替换为明确版本,以固定 MCP 行为。
43
60
 
44
61
  如果 `@autobest-ui` 发布在私有 npm registry,使用前需要在 npm 的 `.npmrc` 中配置该 scope 对应的 registry 和认证信息。
45
62
 
46
- ## Plugin
63
+ ## Figma Plugin
64
+
65
+ Figma Plugin 与 `figma-mcp-bridge` 分目录维护,并通过同一个 npm 包提供两个独立命令。安装或更新到稳定目录:
66
+
67
+ ```bash
68
+ npx --yes --package=@autobest-ui/agent@latest figma-plugin
69
+ ```
70
+
71
+ 命令会输出 `manifest.json` 的稳定路径。首次安装后,在 Figma 中通过 **Plugins -> Development -> Import plugin from manifest** 导入该文件。详细说明见 [Figma Plugin 使用说明](plugins/figma-plugin/README.md)。
72
+
73
+ 卸载本地文件:
74
+
75
+ ```bash
76
+ npx --yes --package=@autobest-ui/agent@latest figma-plugin uninstall
77
+ ```
78
+
79
+ ## Codex Plugin
47
80
 
48
81
  Autobest Delivery 将交付闭环 Skills 和隔离的 Playwright MCP 运行器作为一个 Codex Plugin 安装。需要 Node.js 20 或更高版本,以及支持 `codex plugin` 命令的 Codex CLI。
49
82
 
@@ -126,7 +159,7 @@ Common Skills 会写入 `~/.agents/skills`,React Skills 会写入目标项目
126
159
  RAG MCP:
127
160
 
128
161
  ```bash
129
- RAG_API_BASE_URL=http://127.0.0.1:3000 \
162
+ RAG_API_BASE_URL="http://127.0.0.1:3000/api/knowledge" \
130
163
  npx --yes \
131
164
  --package="$AGENT_TARBALL_PATH" \
132
165
  autobest-rag-mcp
@@ -141,6 +174,22 @@ npx --yes \
141
174
  autobest-azurepr-mcp
142
175
  ```
143
176
 
177
+ Figma MCP:
178
+
179
+ ```bash
180
+ npx --yes \
181
+ --package="$AGENT_TARBALL_PATH" \
182
+ figma-mcp-bridge
183
+ ```
184
+
185
+ Figma Plugin:
186
+
187
+ ```bash
188
+ npx --yes \
189
+ --package="$AGENT_TARBALL_PATH" \
190
+ figma-plugin
191
+ ```
192
+
144
193
  MCP 使用 stdio 协议,启动后持续等待客户端请求属于正常行为,可按 `Ctrl+C` 停止。
145
194
 
146
195
  ### 5. 在 Codex 中联调 MCP
@@ -157,7 +206,7 @@ args = [
157
206
  ]
158
207
 
159
208
  [mcp_servers.rag-mcp-bridge.env]
160
- RAG_API_BASE_URL = "http://127.0.0.1:3000"
209
+ RAG_API_BASE_URL = "http://127.0.0.1:3000/api/knowledge"
161
210
 
162
211
  [mcp_servers.azurepr-mcp-bridge]
163
212
  command = "npx"
@@ -167,11 +216,21 @@ args = [
167
216
  "autobest-azurepr-mcp"
168
217
  ]
169
218
 
170
- [mcp_servers.azurepr-mcp-bridge.env]
171
- AZURE_DEVOPS_PAT = "your-token"
219
+ env_vars = ["AZURE_DEVOPS_PAT"]
220
+
221
+ [mcp_servers.figma-mcp-bridge]
222
+ command = "npx"
223
+ args = [
224
+ "--yes",
225
+ "--package=/absolute/path/to/autobest-ui-agent-x.y.z.tgz",
226
+ "figma-mcp-bridge"
227
+ ]
228
+ startup_timeout_sec = 30
229
+ tool_timeout_sec = 120
230
+ enabled = true
172
231
  ```
173
232
 
174
- 修改 `config.toml` 后重启 Codex,再从新会话调用对应 MCP 工具。重新打包后如果 tarball 文件名或路径发生变化,需要同步更新 `config.toml`。
233
+ 配置 Azure PR MCP 前,还需要在启动 Codex 的环境中设置 `AZURE_DEVOPS_PAT`。修改 `config.toml` 后重启 Codex,再从新会话调用对应 MCP 工具。重新打包后如果 tarball 文件名或路径发生变化,需要同步更新 `config.toml`。
175
234
 
176
235
  ## 本地验证
177
236
 
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Magic Spells
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.
@@ -0,0 +1,25 @@
1
+ # figma-mcp-bridge
2
+
3
+ `figma-mcp-bridge` 是本地 STDIO MCP 服务。它在 Codex 与 Figma Plugin 之间建立 WebSocket 桥接,使 Agent 可以读取和修改当前打开的 Figma Design 或 FigJam 文档。
4
+
5
+ ## 安装与配置
6
+
7
+ 先安装 Figma Plugin:
8
+
9
+ ```bash
10
+ npx --yes --package=@autobest-ui/agent@latest figma-plugin
11
+ ```
12
+
13
+ 然后将 [config.toml.example](config.toml.example) 中的配置加入 `~/.codex/config.toml`,重启 Codex。Codex 会通过 npm 安装并启动 MCP:
14
+
15
+ ```bash
16
+ npx --yes --package=@autobest-ui/agent@latest figma-mcp-bridge
17
+ ```
18
+
19
+ MCP 使用 stdio 通信,启动后持续等待客户端请求属于正常状态。WebSocket 默认从 `3055` 端口开始;如果端口已被占用,会依次尝试到 `3070`。
20
+
21
+ ## 连接 Figma
22
+
23
+ 在 Figma 中通过 **Plugins -> Development -> Import plugin from manifest** 导入安装器输出的 `manifest.json`。打开目标文件并运行插件,将插件显示的端口设置为 MCP 实际监听端口。状态显示 `Connected` 后即可使用。
24
+
25
+ 生产环境可将 `@latest` 替换为明确版本,以固定 MCP 行为。
@@ -0,0 +1,10 @@
1
+ [mcp_servers.figma-mcp-bridge]
2
+ command = "npx"
3
+ args = ["--yes", "--package=@autobest-ui/agent@latest", "figma-mcp-bridge"]
4
+ startup_timeout_sec = 30
5
+ tool_timeout_sec = 120
6
+ enabled = true
7
+
8
+ [mcp_servers.figma-mcp-bridge.env]
9
+ # 可选。默认从 3055 开始;端口占用时服务会依次尝试到 3070。
10
+ FIGMA_BRIDGE_PORT = "3055"
@@ -0,0 +1,47 @@
1
+ import assert from 'node:assert/strict';
2
+ import { readFile } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import test from 'node:test';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
7
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
8
+
9
+ const directory = path.dirname(fileURLToPath(import.meta.url));
10
+
11
+ test('ships a valid skill frontmatter', async () => {
12
+ const skill = await readFile(path.join(directory, 'skills', 'figma-bridge', 'SKILL.md'), 'utf8');
13
+ assert.match(skill, /^---\nname: figma-bridge\ndescription: [^\n]+\n---\n/);
14
+ });
15
+
16
+ test('initializes and exposes Figma tools and skill resources over stdio', async () => {
17
+ const client = new Client({
18
+ name: 'figma-mcp-bridge-test',
19
+ version: '1.0.0'
20
+ });
21
+ const transport = new StdioClientTransport({
22
+ command: process.execPath,
23
+ args: [path.join(directory, 'src', 'index.js')],
24
+ cwd: directory,
25
+ env: {
26
+ ...process.env,
27
+ FIGMA_BRIDGE_PORT: '0'
28
+ },
29
+ stderr: 'pipe'
30
+ });
31
+
32
+ try {
33
+ await client.connect(transport);
34
+ assert.equal(client.getServerVersion()?.name, 'figma-mcp-bridge');
35
+ assert.match(client.getInstructions() ?? '', /Figma MCP Bridge v0\.4\.0/);
36
+
37
+ const { tools } = await client.listTools();
38
+ assert.ok(tools.length >= 90);
39
+ assert.ok(tools.some(({ name }) => name === 'figma_get_context'));
40
+ assert.ok(tools.some(({ name }) => name === 'figma_create_frame'));
41
+
42
+ const { resources } = await client.listResources();
43
+ assert.ok(resources.some(({ uri }) => uri === 'skill://figma-bridge/SKILL.md'));
44
+ } finally {
45
+ await client.close();
46
+ }
47
+ });
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "@autobest/figma-mcp-bridge",
3
+ "version": "0.4.0",
4
+ "private": true,
5
+ "description": "STDIO MCP server bridging Codex to the Autobest Figma plugin",
6
+ "type": "module",
7
+ "main": "src/index.js",
8
+ "engines": {
9
+ "node": ">=20"
10
+ },
11
+ "dependencies": {
12
+ "@modelcontextprotocol/sdk": "1.30.0",
13
+ "ws": "8.18.3",
14
+ "zod": "4.4.3"
15
+ }
16
+ }
@@ -0,0 +1,98 @@
1
+ ---
2
+ name: figma-bridge
3
+ description: Operate figma-mcp-bridge for reliable Figma Design and FigJam reads, edits, verification, and export review.
4
+ ---
5
+
6
+ # Figma MCP Bridge — Operation Skill
7
+
8
+ How to work through the figma-mcp-bridge effectively and honestly. Read this
9
+ before any write-heavy design session. Applies to bridge **v0.4.0+**.
10
+
11
+ ## Verification discipline — the core of this skill
12
+
13
+ **1. Verify bindings by readback, not by assumption.**
14
+ `figma_get_nodes` (full depth) returns `boundVariables` (node-level variable
15
+ bindings), `explicitVariableModes` (pinned modes), `layoutWrap`,
16
+ `counterAxisSpacing`, and `clipsContent`. After binding, pinning, or layout
17
+ work, read the node back and confirm the field says what you intended. Mutating
18
+ tools echo readbacks in their responses (`verified: true`, resulting
19
+ `explicitVariableModes`, per-side stroke weights, etc.) — check them.
20
+
21
+ **2. Export the render and look at it before reporting done.**
22
+ `figma_export_node` writes the image to disk and returns the path — Read the
23
+ file and actually look at it. Property readback cannot see composition: real
24
+ sessions passed every numeric check while renders showed a portrait video well
25
+ where a 16:9 one belonged, a heading breaking mid-word, and a button hugging at
26
+ 140px instead of spanning its form. Looking catches what measuring cannot.
27
+
28
+ **3. Report honestly.**
29
+ - If a tool errors, report the failure — never record the work as done.
30
+ - If a readback disagrees with a success response, report that too.
31
+ - Never paper over a missing capability by hardcoding a value.
32
+ - The bridge errors instead of silently no-oping (see error codes below);
33
+ treat those errors as information about Figma's real constraints, not as
34
+ obstacles to retry around.
35
+
36
+ ## Errors that mean "Figma forbids this" (don't retry — change approach)
37
+
38
+ - `INSTANCE_SUBLAYER_RESTRICTED` — size binds, resizes, and reorders inside an
39
+ instance are not allowed. Make the change on the component master; it flows
40
+ to every instance.
41
+ - `MODE_NOT_FOUND` / `COLLECTION_NOT_FOUND` — the modeId/collectionId is wrong;
42
+ the error lists valid modes.
43
+ - `WRONG_EDITOR` / `FIGMA_DESIGN_ONLY` — the tool is gated to FigJam or Figma
44
+ Design; the error names the current editor type (there are five: figma,
45
+ figjam, dev, slides, buzz).
46
+ - `BIND_NOT_APPLIED` / `STYLE_NOT_APPLIED` / `RESIZE_NO_OP` /
47
+ `REORDER_FAILED` / `LIMIT_NOT_APPLIED` — the write did not land and the
48
+ bridge is telling you instead of pretending. Report it.
49
+
50
+ ## Tool guidance
51
+
52
+ - **Sizing a child to its parent:** use `figma_set_layout_align: STRETCH`, not
53
+ `figma_resize_nodes`. STRETCH preserves width/height variable binds; resize
54
+ may destroy them (the bridge re-applies and warns, but STRETCH avoids the
55
+ problem entirely).
56
+ - **Pinning variable modes:** `figma_set_variable_mode` sets or clears
57
+ (`clear: true`) an explicit mode per collection on nodes *and pages*. Pins
58
+ belong on preview/page frames. Never pin a component master — every instance
59
+ inherits it, per-collection, and the partial correctness hides the fault.
60
+ - **Text styles:** create with `figma_create_text_style`, bind `fontSize` (and
61
+ other text fields) to variables via `figma_set_variable` with `styleId`,
62
+ apply with `figma_apply_style`, delete with `figma_delete_style`.
63
+ - **Borders on one side:** `figma_set_strokes` per-side weights
64
+ (`strokeTopWeight` etc.); `strokes` may be omitted to change weights only.
65
+ A mixed weight reads back as the string `'MIXED'` plus the four per-side
66
+ values.
67
+ - **Min/max sizes:** `figma_set_size_limits`; pass explicit `null` to clear.
68
+ `figma_unbind_variable` on a min/max field also clears the residual literal.
69
+ - **Reordering:** `figma_reorder_node` `position` is the final index among
70
+ siblings (0 = back, `childCount-1` = front), verified by readback.
71
+ - **Hiding:** `figma_set_visible` — don't fake it with opacity 0.
72
+ - **Exports:** the returned `path` is the deliverable; Read it. No need to
73
+ inflate `scale` to force anything.
74
+ - **Constraints:** set `figma_set_constraints` BEFORE converting the parent to
75
+ auto-layout; inside auto-layout parents it's rejected, and it can't be
76
+ overridden on instance sublayers at all.
77
+
78
+ ## Auto-layout facts that bite
79
+
80
+ - `SPACE_BETWEEN` is inert when any child has `layoutGrow: 1` (no free space
81
+ to distribute) — `itemSpacing` is ignored then too.
82
+ - `figma_set_layout_align: CENTER` is a no-op on a stretched child — use
83
+ `INHERIT` plus the parent's `counterAxisAlignItems: CENTER`.
84
+ - Reading wrap: `layoutWrap` and `counterAxisSpacing` come back in full node
85
+ reads; compact children include x/y for geometry checks.
86
+ - `figma_set_text` does not decode HTML entities — send literal characters
87
+ (`&`, not `&`).
88
+
89
+ ## Concurrency (multi-agent sessions)
90
+
91
+ - One WebSocket to one open document. More than ~2 write-heavy agents produces
92
+ transient `Unable to establish connection` errors — retry them; if an agent
93
+ stalls completely, kill and restart it.
94
+ - **Never call `figma_set_current_page` or `figma_set_selection` from a
95
+ sub-agent** — it yanks the shared view out from under every other client.
96
+ - The plugin must be connected to THIS server's port: check
97
+ `figma_server_info` / `figma_get_context` first and surface the port to the
98
+ user if disconnected.
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Figma MCP Bridge - Entry Point
5
+ *
6
+ * Starts the WebSocket server for Figma plugin communication
7
+ * and the MCP server for Agent communication.
8
+ */
9
+
10
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
11
+ import { FigmaBridge } from './websocket.js';
12
+ import { createServer } from './server.js';
13
+
14
+ const PORT = parseInt(process.env.FIGMA_BRIDGE_PORT || '3055', 10);
15
+
16
+ async function main() {
17
+ // eslint-disable-next-line no-console
18
+ console.error('[FigmaMCP] Starting Figma MCP Bridge...');
19
+
20
+ // Create and start WebSocket bridge
21
+ const bridge = new FigmaBridge(PORT);
22
+ await bridge.start();
23
+
24
+ // Log connection events
25
+ bridge.on('connected', info => {
26
+ // eslint-disable-next-line no-console
27
+ console.error(`[FigmaMCP] Figma connected: ${info.fileName}`);
28
+ });
29
+
30
+ bridge.on('disconnected', () => {
31
+ // eslint-disable-next-line no-console
32
+ console.error('[FigmaMCP] Figma disconnected');
33
+ });
34
+
35
+ // Create MCP server
36
+ const server = createServer(bridge);
37
+
38
+ // Connect to stdio transport (Agent communication)
39
+ const transport = new StdioServerTransport();
40
+ await server.connect(transport);
41
+
42
+ // eslint-disable-next-line no-console
43
+ console.error(
44
+ `[FigmaMCP] MCP server running, WebSocket bound to port ${bridge.port}. Waiting for Figma plugin connection...`
45
+ );
46
+
47
+ // Graceful shutdown helper
48
+ const shutdown = async reason => {
49
+ // eslint-disable-next-line no-console
50
+ console.error(`[FigmaMCP] Shutting down (${reason})...`);
51
+ await bridge.stop();
52
+ process.exit(0);
53
+ };
54
+
55
+ // Handle graceful shutdown
56
+ process.on('SIGINT', () => shutdown('SIGINT'));
57
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
58
+
59
+ // Handle stdio close (when the Agent closes the connection)
60
+ process.stdin.on('close', () => shutdown('stdin closed'));
61
+ transport.onclose = () => shutdown('transport closed');
62
+ }
63
+
64
+ main().catch(error => {
65
+ // eslint-disable-next-line no-console
66
+ console.error('[FigmaMCP] Fatal error:', error);
67
+ process.exit(1);
68
+ });
@@ -0,0 +1,159 @@
1
+ /**
2
+ * MCP Server setup
3
+ */
4
+
5
+ import { readFileSync, readdirSync, existsSync } from 'fs';
6
+ import { fileURLToPath } from 'url';
7
+ import { dirname, join } from 'path';
8
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
9
+ import { registerTools } from './tools/index.js';
10
+
11
+ // Read package.json once at module load so version stays in sync with the published artifact
12
+ const __dirname = dirname(fileURLToPath(import.meta.url));
13
+ let pkgVersion = '0.0.0';
14
+ try {
15
+ const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
16
+ pkgVersion = pkg.version;
17
+ } catch (_) {
18
+ // Fall back to placeholder if package.json can't be read
19
+ }
20
+
21
+ /**
22
+ * Create and configure the MCP server
23
+ * @param {FigmaBridge} bridge - Figma bridge instance (must be started — bridge.port must reflect the bound port)
24
+ * @returns {McpServer} Configured MCP server
25
+ */
26
+ export function createServer(bridge) {
27
+ const port = bridge.port;
28
+ const instructions = `# Figma MCP Bridge v${pkgVersion}
29
+
30
+ ## CONNECTION INFO — CHECK FIRST
31
+
32
+ This MCP server is bridging an Agent to Figma via a WebSocket on **port ${port}**.
33
+
34
+ Multiple Agent sessions can run concurrently and the bridge falls back through ports 3055–3070, so the port may differ from the default. **At the start of any new Figma-related conversation, call \`figma_get_context\` to check connection state. If it returns \`connected: false\`, proactively tell the user:**
35
+
36
+ > "The Figma MCP bridge is running on port **${port}**. Open the Figma plugin and set its port input to **${port}**, then re-run the plugin if it was already open."
37
+
38
+ Don't make the user discover the port themselves — surface it the first time you notice they aren't connected.
39
+
40
+ ## SKILLS — READ BEFORE WRITE-HEAVY WORK
41
+
42
+ This server ships its own skills as MCP resources. **Before any session that creates or edits design content (not just single reads), read \`skill://figma-bridge/SKILL.md\`** — it covers verification discipline (readback + export-and-look), the error codes that mean "Figma forbids this", bind-preserving sizing, mode pinning, concurrency rules, and auto-layout traps. List resources to discover any additional skills shipped with this server version.
43
+
44
+ ## FigJam Support
45
+
46
+ This server supports both Figma design files AND FigJam files. FigJam-specific tools (sticky notes, flowchart shapes, connectors, tables, code blocks, link previews) are gated to FigJam files and return a \`WRONG_EDITOR\` error if called against a Figma design file.
47
+
48
+ **Editor-restricted tools:**
49
+ - FigJam-only (return \`WRONG_EDITOR\` in design files): all sticky / shape-with-text / connector / table / code-block / link-preview tools
50
+ - Figma Design only (return \`FIGMA_DESIGN_ONLY\` in FigJam): \`figma_create_page\`, \`figma_duplicate_page\`. FigJam files have pages but the plugin API does not expose page creation; pages must be created via the FigJam UI by the user.
51
+
52
+ For flowcharts in FigJam:
53
+ - \`figma_create_shape_with_text\` with \`shapeType\` (ROUNDED_RECTANGLE for processes, DIAMOND for decisions, ENG_DATABASE for data stores, etc.)
54
+ - \`figma_create_connector\` with \`{ start: { nodeId, magnet: 'AUTO' }, end: { nodeId, magnet: 'AUTO' } }\` — \`endCap\` defaults to \`ARROW_EQUILATERAL\` so connectors look like arrows
55
+ - Wrap the diagram in a \`figma_create_section\` for grouping
56
+
57
+ ## IMPORTANT: Always Use Search Tools First
58
+
59
+ When working with Figma documents, ALWAYS prefer search tools over bulk retrieval:
60
+
61
+ ### For Variables
62
+ - **USE**: \`figma_search_variables\` (~500 tokens) - Filter by name pattern, type, collection
63
+ - **AVOID**: \`figma_get_local_variables\` (25k+ tokens, may truncate)
64
+
65
+ Example:
66
+ \`\`\`
67
+ figma_search_variables({ namePattern: "colors/*", type: "COLOR", compact: true })
68
+ \`\`\`
69
+
70
+ ### For Nodes
71
+ - **USE**: \`figma_search_nodes\` - Find frames/elements by name within a scope
72
+ - **USE**: \`figma_get_children\` - Browse hierarchy one level at a time
73
+ - **AVOID**: Repeated \`figma_get_nodes\` calls to traverse the tree
74
+
75
+ Example:
76
+ \`\`\`
77
+ figma_search_nodes({ parentId: "0:1", nameContains: "Button", types: ["FRAME", "COMPONENT"] })
78
+ \`\`\`
79
+
80
+ ### For Components
81
+ - **USE**: \`figma_search_components\` - Find by name pattern
82
+ - Returns compact results with component metadata
83
+
84
+ ### For Styles
85
+ - **USE**: \`figma_search_styles\` - Find by name and type
86
+ - **AVOID**: \`figma_get_local_styles\` for large documents
87
+
88
+ ## Workflow
89
+
90
+ 1. **Start with context**: Call \`figma_get_context\` to understand the current document and selection
91
+ 2. **Search first**: Use search tools to find specific elements by name
92
+ 3. **Get details only when needed**: Use \`figma_get_nodes\` with \`depth: "minimal"\` or \`"compact"\` for efficiency
93
+ 4. **Use full depth sparingly**: Only use \`depth: "full"\` when you need all node properties
94
+
95
+ ## Token Optimization
96
+
97
+ | Tool | Tokens | Use Case |
98
+ |------|--------|----------|
99
+ | \`figma_search_*\` | ~50/result | Finding specific elements |
100
+ | \`figma_get_children\` | ~50/node | Browsing hierarchy |
101
+ | \`figma_get_nodes\` (minimal) | ~100/node | Tree traversal |
102
+ | \`figma_get_nodes\` (full) | ~500/node | Detailed inspection |
103
+ | \`figma_get_local_variables\` | 25k+ | AVOID - use search instead
104
+ `;
105
+ const server = new McpServer(
106
+ {
107
+ name: 'figma-mcp-bridge',
108
+ version: pkgVersion
109
+ },
110
+ { instructions }
111
+ );
112
+
113
+ // Register all Figma tools
114
+ registerTools(server, bridge);
115
+
116
+ // Serve every skills/<name>/SKILL.md as an MCP resource (skill://<name>/SKILL.md)
117
+ // so agents get the bridge's operating knowledge without installing anything.
118
+ registerSkillResources(server);
119
+
120
+ return server;
121
+ }
122
+
123
+ /**
124
+ * Register the markdown skills shipped in skills/ as MCP resources.
125
+ * Files are read lazily per request so a dev checkout picks up edits
126
+ * without a server restart. Missing dir (or a race on a deleted file)
127
+ * degrades to no/absent resources rather than a crash.
128
+ * @param {McpServer} server
129
+ */
130
+ function registerSkillResources(server) {
131
+ const skillsDir = join(__dirname, '..', 'skills');
132
+ if (!existsSync(skillsDir)) return;
133
+
134
+ for (const entry of readdirSync(skillsDir, { withFileTypes: true })) {
135
+ if (!entry.isDirectory()) continue;
136
+ const skillPath = join(skillsDir, entry.name, 'SKILL.md');
137
+ if (!existsSync(skillPath)) continue;
138
+
139
+ const uri = `skill://${entry.name}/SKILL.md`;
140
+ server.registerResource(
141
+ entry.name,
142
+ uri,
143
+ {
144
+ title: `Skill: ${entry.name}`,
145
+ description: `Operating skill shipped with figma-mcp-bridge. Read before write-heavy ${entry.name} work.`,
146
+ mimeType: 'text/markdown'
147
+ },
148
+ async () => ({
149
+ contents: [
150
+ {
151
+ uri,
152
+ mimeType: 'text/markdown',
153
+ text: readFileSync(skillPath, 'utf8')
154
+ }
155
+ ]
156
+ })
157
+ );
158
+ }
159
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * figma_get_context tool
3
+ * Returns current document context including connection status, file info, and selection
4
+ */
5
+
6
+ export const contextTool = {
7
+ name: 'figma_get_context',
8
+ description:
9
+ 'Get the current Figma document context including file info, current page, and selection. Use this to understand what document is open and what the user has selected.',
10
+ inputSchema: {
11
+ type: 'object',
12
+ properties: {},
13
+ required: []
14
+ }
15
+ };
16
+
17
+ export async function handleGetContext(bridge) {
18
+ if (!bridge.isConnected()) {
19
+ return {
20
+ content: [
21
+ {
22
+ type: 'text',
23
+ text: JSON.stringify(
24
+ {
25
+ connected: false,
26
+ message: 'Figma plugin is not connected. Please open Figma and run the Autobest Figma Plugin.'
27
+ },
28
+ null,
29
+ 2
30
+ )
31
+ }
32
+ ]
33
+ };
34
+ }
35
+
36
+ try {
37
+ const result = await bridge.sendCommand('get_context', {});
38
+
39
+ return {
40
+ content: [
41
+ {
42
+ type: 'text',
43
+ text: JSON.stringify(
44
+ {
45
+ connected: true,
46
+ ...result
47
+ },
48
+ null,
49
+ 2
50
+ )
51
+ }
52
+ ]
53
+ };
54
+ } catch (error) {
55
+ return {
56
+ content: [
57
+ {
58
+ type: 'text',
59
+ text: JSON.stringify(
60
+ {
61
+ connected: true,
62
+ error: {
63
+ code: error.code || 'UNKNOWN_ERROR',
64
+ message: error.message
65
+ }
66
+ },
67
+ null,
68
+ 2
69
+ )
70
+ }
71
+ ],
72
+ isError: true
73
+ };
74
+ }
75
+ }