figma-console-mcp 1.13.1 β†’ 1.15.0

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
@@ -8,7 +8,7 @@
8
8
 
9
9
  > **Your design system as an API.** Model Context Protocol server that bridges design and developmentβ€”giving AI assistants complete access to Figma for **extraction**, **creation**, and **debugging**.
10
10
 
11
- > **πŸ†• Cloud Write Relay β€” Web AI Clients Can Now Design in Figma:** Claude.ai, v0, Replit, and Lovable can now create and modify Figma designs through a cloud relay. No Node.js required β€” just pair your Desktop Bridge plugin with a 6-character code and get 43 tools including full write access. [See changelog β†’](CHANGELOG.md)
11
+ > **πŸ†• Import Once, Update Never β€” Plugin Bootloader Architecture:** The Desktop Bridge plugin now dynamically loads its UI from the MCP server on every launch. Import the manifest once from `~/.figma-console-mcp/plugin/manifest.json` and you're done forever β€” server updates, new tools, and bug fixes are delivered automatically. Plus: orphaned process cleanup, cross-file library components, and built-in housekeeping. [See changelog β†’](CHANGELOG.md)
12
12
 
13
13
  ## What is this?
14
14
 
@@ -49,9 +49,9 @@ Figma Console MCP connects AI assistants (like Claude) to Figma, enabling:
49
49
  | Real-time monitoring (console, selection) | βœ… | ❌ | ❌ |
50
50
  | Desktop Bridge plugin | βœ… | βœ… | ❌ |
51
51
  | Requires Node.js | Yes | **No** | No |
52
- | **Total tools available** | **59+** | **43** | **22** |
52
+ | **Total tools available** | **63+** | **43** | **22** |
53
53
 
54
- > **Bottom line:** Remote SSE is **read-only** with ~38% of the tools. **Cloud Mode** unlocks write access from web AI clients without Node.js. NPX/Local Git gives the full 59+ tools with real-time monitoring.
54
+ > **Bottom line:** Remote SSE is **read-only** with ~38% of the tools. **Cloud Mode** unlocks write access from web AI clients without Node.js. NPX/Local Git gives the full 63+ tools with real-time monitoring.
55
55
 
56
56
  ---
57
57
 
@@ -59,7 +59,7 @@ Figma Console MCP connects AI assistants (like Claude) to Figma, enabling:
59
59
 
60
60
  **Best for:** Designers who want full AI-assisted design capabilities.
61
61
 
62
- **What you get:** All 59+ tools including design creation, variable management, and component instantiation.
62
+ **What you get:** All 63+ tools including design creation, variable management, and component instantiation.
63
63
 
64
64
  #### Prerequisites
65
65
 
@@ -122,11 +122,10 @@ If you're not sure where to put the JSON configuration above, here's where each
122
122
  **Desktop Bridge Plugin:**
123
123
  1. Open Figma Desktop normally (no special flags needed)
124
124
  2. Go to **Plugins β†’ Development β†’ Import plugin from manifest...**
125
- 3. Select `figma-desktop-bridge/manifest.json` from the figma-console-mcp directory
126
- - **NPX users:** Run `npx figma-console-mcp@latest --print-path` to find the directory
127
- 4. Run the plugin in your Figma file β€” it auto-connects via WebSocket (scans ports 9223–9232)
125
+ 3. Select `~/.figma-console-mcp/plugin/manifest.json` (stable path, auto-created by the MCP server)
126
+ 4. Run the plugin in your Figma file β€” the bootloader finds the MCP server and loads the latest UI automatically
128
127
 
129
- > One-time setup. The plugin persists in your Development plugins list across sessions.
128
+ > One-time setup. The plugin uses a bootloader that dynamically loads fresh code from the MCP server β€” no need to re-import when the server updates.
130
129
 
131
130
  #### Step 4: Restart Your MCP Client
132
131
 
@@ -152,7 +151,7 @@ Create a simple frame with a blue background
152
151
 
153
152
  **Best for:** Developers who want to modify source code or contribute to the project.
154
153
 
155
- **What you get:** Same 59+ tools as NPX, plus full source code access.
154
+ **What you get:** Same 63+ tools as NPX, plus full source code access.
156
155
 
157
156
  #### Quick Setup
158
157
 
@@ -193,7 +192,7 @@ Then follow [NPX Steps 3-5](#step-3-connect-to-figma-desktop) above.
193
192
 
194
193
  **Best for:** Quickly evaluating the tool or read-only design data extraction.
195
194
 
196
- **What you get:** 22 read-only tools β€” view data, take screenshots, read logs, design-code parity. **Cannot create or modify designs.**
195
+ **What you get:** 9 read-only tools β€” view data, take screenshots, read logs, design-code parity. **Cannot create or modify designs.**
197
196
 
198
197
  #### Claude Desktop (UI Method)
199
198
 
@@ -241,24 +240,34 @@ Ready for design creation? Follow the [NPX Setup](#-npx-setup-recommended) guide
241
240
 
242
241
  **Best for:** Using Claude.ai, v0, Replit, or Lovable to create and modify Figma designs β€” no Node.js required.
243
242
 
244
- **What you get:** 43 tools including full write access β€” design creation, variable management, component instantiation, and all REST API tools. Only real-time monitoring (console logs, selection tracking, document changes) requires Local Mode.
243
+ **What you get:** 52 tools including full write access β€” design creation, variable management, component instantiation, and all REST API tools. Only real-time monitoring (console logs, selection tracking, document changes) requires Local Mode.
245
244
 
246
245
  #### Prerequisites
247
246
 
247
+ - [ ] **Figma Personal Access Token** β€” [Create one here](https://help.figma.com/hc/en-us/articles/8085703771159-Manage-personal-access-tokens) (starts with `figd_`)
248
248
  - [ ] **Figma Desktop** with the Desktop Bridge plugin installed (see [Desktop Bridge setup](#step-3-connect-to-figma-desktop))
249
- - [ ] **A web AI client** connected to the remote MCP endpoint (see [Remote SSE setup](#-remote-sse-read-only-exploration))
249
+ - [ ] **A web AI client** that supports MCP (Claude.ai, Lovable, v0, Replit, etc.)
250
+
251
+ #### Step 1: Add the MCP Connector
252
+
253
+ Add this endpoint to your AI platform's MCP settings:
250
254
 
251
- #### How to Connect
255
+ **URL:** `https://figma-console-mcp.southleft.com/mcp`
256
+ **Auth:** Your Figma PAT as Bearer token
252
257
 
253
- 1. **Set up Remote SSE** if you haven't already β€” follow the [Remote SSE](#-remote-sse-read-only-exploration) steps above
254
- 2. **Open the Desktop Bridge plugin** in Figma Desktop (Plugins β†’ Development β†’ Figma Desktop Bridge)
255
- 3. **Tell your AI assistant:**
258
+ In **Claude.ai**: Settings β†’ Connectors β†’ Add Custom Connector β†’ paste the URL above.
259
+ In **Lovable/v0/Replit**: Look for "Add MCP Server" or "Integrations" in settings β†’ paste the URL and add your token.
260
+
261
+ #### Step 2: Pair the Plugin
262
+
263
+ 1. **Open the Desktop Bridge plugin** in Figma Desktop (Plugins β†’ Development β†’ Figma Desktop Bridge)
264
+ 2. **Tell your AI assistant:**
256
265
  ```
257
266
  Connect to my Figma plugin
258
267
  ```
259
- 4. **The AI gives you a 6-character pairing code** (expires in 5 minutes)
260
- 5. **In the plugin:** Toggle "Cloud Mode" β†’ enter the code β†’ click Connect
261
- 6. **You're paired!** Full write access is now available
268
+ 3. **The AI gives you a 6-character pairing code** (expires in 5 minutes)
269
+ 4. **In the plugin:** Toggle "Cloud Mode" β†’ enter the code β†’ click Connect
270
+ 5. **You're paired!** Full write access is now available
262
271
 
263
272
  #### What You Can Do
264
273
 
@@ -288,7 +297,7 @@ AI Client β†’ Cloud MCP Server β†’ Durable Object Relay β†’ Desktop Bridge Plugi
288
297
  | Feature | NPX (Recommended) | Cloud Mode | Local Git | Remote SSE |
289
298
  |---------|-------------------|------------|-----------|------------|
290
299
  | **Setup time** | ~10 minutes | ~5 minutes | ~15 minutes | ~2 minutes |
291
- | **Total tools** | **59+** | **43** | **59+** | **22** (read-only) |
300
+ | **Total tools** | **63+** | **43** | **63+** | **22** (read-only) |
292
301
  | **Design creation** | βœ… | βœ… | βœ… | ❌ |
293
302
  | **Variable management** | βœ… | βœ… | βœ… | ❌ |
294
303
  | **Component instantiation** | βœ… | βœ… | βœ… | ❌ |
@@ -302,7 +311,7 @@ AI Client β†’ Cloud MCP Server β†’ Durable Object Relay β†’ Desktop Bridge Plugi
302
311
  | **Automatic updates** | βœ… (`@latest`) | βœ… | Manual (`git pull`) | βœ… |
303
312
  | **Source code access** | ❌ | ❌ | βœ… | ❌ |
304
313
 
305
- > **Key insight:** Remote SSE is read-only. Cloud Mode adds write access for web AI clients without Node.js. NPX/Local Git give the full 59+ tools.
314
+ > **Key insight:** Remote SSE is read-only. Cloud Mode adds write access for web AI clients without Node.js. NPX/Local Git give the full 63+ tools.
306
315
 
307
316
  **πŸ“– [Complete Feature Comparison](docs/mode-comparison.md)**
308
317
 
@@ -587,7 +596,7 @@ The **Figma Desktop Bridge** plugin is the recommended way to connect Figma to t
587
596
  - The MCP server communicates via **WebSocket** through the Desktop Bridge plugin
588
597
  - The server tries port 9223 first, then automatically falls back through ports 9224–9232 if needed
589
598
  - The plugin scans all ports in the range and connects to every active server it finds
590
- - All 59+ tools work through the WebSocket transport
599
+ - All 63+ tools work through the WebSocket transport
591
600
 
592
601
  **Multiple files:** The WebSocket server supports multiple simultaneous plugin connections β€” one per open Figma file. Each connection is tracked by file key with independent state (selection, document changes, console logs).
593
602
 
@@ -627,11 +636,11 @@ When two processes tried to start the MCP server (e.g., Claude Desktop's Chat ta
627
636
 
628
637
  ### Do I Need to Do Anything?
629
638
 
630
- **If you're running a single instance:** Nothing changes. You'll still use port 9223 as before.
631
-
632
- **If you want multi-instance:** Re-import the Desktop Bridge plugin in Figma (Plugins β†’ Development β†’ Import plugin from manifest). This updates the plugin to scan all ports and connect to every active server.
633
-
634
- > **Note:** The server-side update happens automatically when you update the npm package. Only the plugin needs a one-time re-import to enable multi-connection support.
639
+ **Nothing.** Multi-instance support is fully automatic:
640
+ - Each MCP server claims the next available port in the range
641
+ - The bootloader plugin scans all ports and connects to every active server
642
+ - Orphaned processes from closed tabs are automatically cleaned up on startup
643
+ - No re-importing, no manual port management
635
644
 
636
645
  ---
637
646
 
@@ -723,7 +732,7 @@ The architecture supports adding new apps with minimal boilerplate β€” each app
723
732
 
724
733
  ## πŸ›€οΈ Roadmap
725
734
 
726
- **Current Status:** v1.12.0 (Stable) - Production-ready with Cloud Write Relay, Design System Kit, WebSocket-only connectivity, smart multi-file tracking, 59+ tools, Comments API, and MCP Apps
735
+ **Current Status:** v1.12.0 (Stable) - Production-ready with Cloud Write Relay, Design System Kit, WebSocket-only connectivity, smart multi-file tracking, 63+ tools, Comments API, and MCP Apps
727
736
 
728
737
  **Recent Releases:**
729
738
  - [x] **v1.12.0** - Cloud Write Relay: web AI clients (Claude.ai, v0, Replit, Lovable) can create and modify Figma designs via cloud relay pairing β€” no Node.js required
@@ -223,6 +223,27 @@ export class CloudWebSocketConnector {
223
223
  return this.sendCommand('SET_INSTANCE_PROPERTIES', { nodeId, properties });
224
224
  }
225
225
  // ============================================================================
226
+ // Image fill
227
+ // ============================================================================
228
+ async setImageFill(nodeIds, imageData, scaleMode = 'FILL') {
229
+ return this.sendCommand('SET_IMAGE_FILL', { nodeIds, imageData, scaleMode }, 60000);
230
+ }
231
+ // ============================================================================
232
+ // Design lint
233
+ // ============================================================================
234
+ async lintDesign(nodeId, rules, maxDepth, maxFindings) {
235
+ const params = {};
236
+ if (nodeId)
237
+ params.nodeId = nodeId;
238
+ if (rules)
239
+ params.rules = rules;
240
+ if (maxDepth !== undefined)
241
+ params.maxDepth = maxDepth;
242
+ if (maxFindings !== undefined)
243
+ params.maxFindings = maxFindings;
244
+ return this.sendCommand('LINT_DESIGN', params, 120000);
245
+ }
246
+ // ============================================================================
226
247
  // Cache management (no-op for cloud relay)
227
248
  // ============================================================================
228
249
  clearFrameCache() {
@@ -1148,5 +1148,37 @@ export class FigmaDesktopConnector {
1148
1148
  throw error;
1149
1149
  }
1150
1150
  }
1151
+ /**
1152
+ * Set image fill on one or more nodes (decodes base64 in browser bridge, sends bytes to plugin)
1153
+ */
1154
+ async setImageFill(nodeIds, imageData, scaleMode = 'FILL') {
1155
+ logger.info({ nodeIds, scaleMode, dataLength: imageData.length }, 'Setting image fill via plugin UI');
1156
+ const frame = await this.findPluginUIFrame();
1157
+ try {
1158
+ const result = await frame.evaluate(`window.setImageFill(${JSON.stringify(nodeIds)}, ${JSON.stringify(imageData)}, ${JSON.stringify(scaleMode)})`);
1159
+ logger.info({ success: result.success, imageHash: result.imageHash }, 'Image fill set');
1160
+ return result;
1161
+ }
1162
+ catch (error) {
1163
+ logger.error({ error, nodeIds }, 'Set image fill failed');
1164
+ throw error;
1165
+ }
1166
+ }
1167
+ /**
1168
+ * Lint design for accessibility and quality issues via plugin UI
1169
+ */
1170
+ async lintDesign(nodeId, rules, maxDepth, maxFindings) {
1171
+ logger.info({ nodeId, rules }, 'Linting design via plugin UI');
1172
+ const frame = await this.findPluginUIFrame();
1173
+ try {
1174
+ const result = await frame.evaluate(`window.lintDesign(${JSON.stringify(nodeId || null)}, ${JSON.stringify(rules || null)}, ${JSON.stringify(maxDepth ?? null)}, ${JSON.stringify(maxFindings ?? null)})`);
1175
+ logger.info({ success: result.success }, 'Design lint complete');
1176
+ return result;
1177
+ }
1178
+ catch (error) {
1179
+ logger.error({ error, nodeId }, 'Design lint failed');
1180
+ throw error;
1181
+ }
1182
+ }
1151
1183
  }
1152
1184
  FigmaDesktopConnector.DEBUG = process.env.DEBUG === '1' || process.env.DEBUG === 'true';
@@ -227,6 +227,27 @@ export class WebSocketConnector {
227
227
  return this.wsServer.sendCommand('SET_INSTANCE_PROPERTIES', { nodeId, properties });
228
228
  }
229
229
  // ============================================================================
230
+ // Image fill
231
+ // ============================================================================
232
+ async setImageFill(nodeIds, imageData, scaleMode = 'FILL') {
233
+ return this.wsServer.sendCommand('SET_IMAGE_FILL', { nodeIds, imageData, scaleMode }, 60000);
234
+ }
235
+ // ============================================================================
236
+ // Design lint
237
+ // ============================================================================
238
+ async lintDesign(nodeId, rules, maxDepth, maxFindings) {
239
+ const params = {};
240
+ if (nodeId)
241
+ params.nodeId = nodeId;
242
+ if (rules)
243
+ params.rules = rules;
244
+ if (maxDepth !== undefined)
245
+ params.maxDepth = maxDepth;
246
+ if (maxFindings !== undefined)
247
+ params.maxFindings = maxFindings;
248
+ return this.wsServer.sendCommand('LINT_DESIGN', params, 120000);
249
+ }
250
+ // ============================================================================
230
251
  // Cache management (no-op for WebSocket β€” no frame cache)
231
252
  // ============================================================================
232
253
  clearFrameCache() {
@@ -1227,6 +1227,49 @@ After instantiating components, use figma_take_screenshot to verify the result l
1227
1227
  };
1228
1228
  }
1229
1229
  });
1230
+ // Tool: Set Image Fill on nodes
1231
+ server.tool("figma_set_image_fill", "Set an image fill on one or more Figma nodes. The imageData parameter accepts a base64-encoded " +
1232
+ "image string (JPEG/PNG). The image is decoded in the browser bridge and passed " +
1233
+ "as raw bytes to the Figma plugin. Requires Desktop Bridge plugin.", {
1234
+ nodeIds: z.array(z.string()).describe("Array of node IDs to apply the image fill to"),
1235
+ imageData: z.string().describe("Base64-encoded image data (JPEG/PNG)"),
1236
+ scaleMode: z.enum(["FILL", "FIT", "CROP", "TILE"]).optional().describe("How the image fills the node (default: FILL)"),
1237
+ }, async ({ nodeIds, imageData, scaleMode }) => {
1238
+ try {
1239
+ const connector = await getDesktopConnector();
1240
+ const result = await connector.setImageFill(nodeIds, imageData, scaleMode || "FILL");
1241
+ if (!result.success) {
1242
+ throw new Error(result.error || "Failed to set image fill");
1243
+ }
1244
+ return {
1245
+ content: [
1246
+ {
1247
+ type: "text",
1248
+ text: JSON.stringify({
1249
+ success: true,
1250
+ message: `Image fill applied to ${result.updatedCount || 0} node(s)`,
1251
+ imageHash: result.imageHash,
1252
+ nodes: result.nodes,
1253
+ }),
1254
+ },
1255
+ ],
1256
+ };
1257
+ }
1258
+ catch (error) {
1259
+ logger.error({ error }, "Failed to set image fill");
1260
+ return {
1261
+ content: [
1262
+ {
1263
+ type: "text",
1264
+ text: JSON.stringify({
1265
+ error: error instanceof Error ? error.message : String(error),
1266
+ }),
1267
+ },
1268
+ ],
1269
+ isError: true,
1270
+ };
1271
+ }
1272
+ });
1230
1273
  // Tool: Set Node Strokes
1231
1274
  server.tool("figma_set_strokes", "Set the stroke (border) on a node. Accepts hex color strings and optional stroke weight.", {
1232
1275
  nodeId: z.string().describe("The node ID to modify"),
@@ -2003,4 +2046,46 @@ return {
2003
2046
  };
2004
2047
  }
2005
2048
  });
2049
+ // Tool: Lint Design for accessibility and quality issues
2050
+ server.tool("figma_lint_design", "Run accessibility (WCAG) and design quality checks on the current page or a specific node tree. " +
2051
+ "Checks color contrast ratios, text sizing, touch targets, hardcoded values, detached components, " +
2052
+ "naming conventions, and layout quality. Returns categorized findings with severity levels. " +
2053
+ "Use natural language like 'check my design for accessibility issues' or 'lint this page'. " +
2054
+ "Requires Desktop Bridge plugin.", {
2055
+ nodeId: z.string().optional().describe("Node ID to lint (defaults to current page)"),
2056
+ rules: z.array(z.string()).optional().describe("Rule filter: ['all'] (default), ['wcag'], ['design-system'], ['layout'], or specific rule IDs like ['wcag-contrast', 'detached-component']"),
2057
+ maxDepth: z.number().optional().describe("Maximum tree depth to traverse (default: 10)"),
2058
+ maxFindings: z.number().optional().describe("Maximum findings before stopping (default: 100)"),
2059
+ }, async ({ nodeId, rules, maxDepth, maxFindings }) => {
2060
+ try {
2061
+ const connector = await getDesktopConnector();
2062
+ const result = await connector.lintDesign(nodeId, rules || ['all'], maxDepth || 10, maxFindings || 100);
2063
+ if (!result.success) {
2064
+ throw new Error(result.error || "Lint failed");
2065
+ }
2066
+ return {
2067
+ content: [
2068
+ {
2069
+ type: "text",
2070
+ text: JSON.stringify(result.data || result, null, 2),
2071
+ },
2072
+ ],
2073
+ };
2074
+ }
2075
+ catch (error) {
2076
+ logger.error({ error }, "Failed to lint design");
2077
+ return {
2078
+ content: [
2079
+ {
2080
+ type: "text",
2081
+ text: JSON.stringify({
2082
+ error: error instanceof Error ? error.message : String(error),
2083
+ hint: "Make sure the Desktop Bridge plugin is running in your Figma file.",
2084
+ }),
2085
+ },
2086
+ ],
2087
+ isError: true,
2088
+ };
2089
+ }
2090
+ });
2006
2091
  }
@@ -38,7 +38,7 @@ export class FigmaConsoleMCPv3 extends McpAgent {
38
38
  super(...arguments);
39
39
  this.server = new McpServer({
40
40
  name: "Figma Console MCP",
41
- version: "1.12.0",
41
+ version: "1.13.0",
42
42
  });
43
43
  this.browserManager = null;
44
44
  this.consoleMonitor = null;
@@ -950,7 +950,7 @@ export default {
950
950
  });
951
951
  const statelessServer = new McpServer({
952
952
  name: "Figma Console MCP",
953
- version: "1.12.0",
953
+ version: "1.13.0",
954
954
  });
955
955
  // ================================================================
956
956
  // Cloud Write Relay β€” Pairing Tool (stateless /mcp path)
@@ -1005,19 +1005,40 @@ export default {
1005
1005
  await connector.initialize();
1006
1006
  return connector;
1007
1007
  };
1008
+ // Build a getCurrentUrl that resolves from the relay DO's file info
1009
+ const getCloudFileUrl = () => {
1010
+ // This is synchronous β€” we cache the file URL after first relay status check
1011
+ return cloudFileUrlCache;
1012
+ };
1013
+ let cloudFileUrlCache = null;
1014
+ // Pre-fetch file info from relay if paired
1015
+ try {
1016
+ const relayDoId = await env.OAUTH_TOKENS.get(`relay:${bearerToken}`);
1017
+ if (relayDoId) {
1018
+ const doId = env.PLUGIN_RELAY.idFromString(relayDoId);
1019
+ const stub = env.PLUGIN_RELAY.get(doId);
1020
+ const statusRes = await stub.fetch('https://relay/relay/status');
1021
+ const status = await statusRes.json();
1022
+ if (status.connected && status.fileInfo?.fileKey) {
1023
+ cloudFileUrlCache = `https://www.figma.com/design/${status.fileInfo.fileKey}`;
1024
+ }
1025
+ }
1026
+ }
1027
+ catch {
1028
+ // No relay session or not paired β€” cloudFileUrlCache stays null
1029
+ }
1008
1030
  // Register all write/manipulation tools via shared function
1009
1031
  registerWriteTools(statelessServer, getCloudDesktopConnector);
1010
1032
  // Register REST API tools with the authenticated Figma API
1011
- registerFigmaAPITools(statelessServer, async () => statelessApi, () => null, // No browser URL in stateless mode
1012
- () => null, // No console monitor
1033
+ registerFigmaAPITools(statelessServer, async () => statelessApi, getCloudFileUrl, () => null, // No console monitor
1013
1034
  () => null, // No browser manager
1014
1035
  undefined, // No ensureInitialized
1015
1036
  new Map(), // Fresh variables cache per request
1016
1037
  { isRemoteMode: true }, getCloudDesktopConnector);
1017
- registerDesignCodeTools(statelessServer, async () => statelessApi, () => null, new Map(), // Fresh variables cache per request
1038
+ registerDesignCodeTools(statelessServer, async () => statelessApi, getCloudFileUrl, new Map(), // Fresh variables cache per request
1018
1039
  { isRemoteMode: true }, getCloudDesktopConnector);
1019
- registerCommentTools(statelessServer, async () => statelessApi, () => null);
1020
- registerDesignSystemTools(statelessServer, async () => statelessApi, () => null, new Map(), // Fresh variables cache per request
1040
+ registerCommentTools(statelessServer, async () => statelessApi, getCloudFileUrl);
1041
+ registerDesignSystemTools(statelessServer, async () => statelessApi, getCloudFileUrl, new Map(), // Fresh variables cache per request
1021
1042
  { isRemoteMode: true });
1022
1043
  await statelessServer.connect(transport);
1023
1044
  const response = await transport.handleRequest(request);
@@ -1038,7 +1059,7 @@ export default {
1038
1059
  const metadata = {
1039
1060
  resource: url.origin,
1040
1061
  authorization_servers: [`${url.origin}/`],
1041
- scopes_supported: ["file_content:read", "library_content:read", "file_variables:read"],
1062
+ scopes_supported: ["file_content:read", "file_variables:read", "library_content:read"],
1042
1063
  bearer_methods_supported: ["header"],
1043
1064
  resource_signing_alg_values_supported: ["RS256"]
1044
1065
  };
@@ -1057,7 +1078,7 @@ export default {
1057
1078
  authorization_endpoint: `${url.origin}/authorize`,
1058
1079
  token_endpoint: `${url.origin}/token`,
1059
1080
  registration_endpoint: `${url.origin}/oauth/register`,
1060
- scopes_supported: ["file_content:read", "library_content:read", "file_variables:read"],
1081
+ scopes_supported: ["file_content:read", "file_variables:read", "library_content:read"],
1061
1082
  response_types_supported: ["code"],
1062
1083
  grant_types_supported: ["authorization_code", "refresh_token"],
1063
1084
  token_endpoint_auth_methods_supported: ["client_secret_basic", "client_secret_post"],
@@ -1120,7 +1141,7 @@ export default {
1120
1141
  const figmaAuthUrl = new URL("https://www.figma.com/oauth");
1121
1142
  figmaAuthUrl.searchParams.set("client_id", env.FIGMA_OAUTH_CLIENT_ID);
1122
1143
  figmaAuthUrl.searchParams.set("redirect_uri", `${oauthOrigin}/oauth/callback`);
1123
- figmaAuthUrl.searchParams.set("scope", "file_content:read,library_content:read,file_variables:read");
1144
+ figmaAuthUrl.searchParams.set("scope", "file_content:read,file_variables:read,library_content:read");
1124
1145
  figmaAuthUrl.searchParams.set("state", stateToken);
1125
1146
  figmaAuthUrl.searchParams.set("response_type", "code");
1126
1147
  return Response.redirect(figmaAuthUrl.toString(), 302);
@@ -1161,7 +1182,7 @@ export default {
1161
1182
  token_type: "Bearer",
1162
1183
  expires_in: Math.max(0, Math.floor((tokenData.expiresAt - Date.now()) / 1000)),
1163
1184
  refresh_token: tokenData.refreshToken,
1164
- scope: "file_content:read library_content:read file_variables:read"
1185
+ scope: "file_content:read file_variables:read library_content:read"
1165
1186
  }), {
1166
1187
  headers: {
1167
1188
  "Content-Type": "application/json",
@@ -1238,7 +1259,7 @@ export default {
1238
1259
  token_type: "Bearer",
1239
1260
  expires_in: tokenData.expires_in,
1240
1261
  refresh_token: tokenData.refresh_token || refreshToken,
1241
- scope: "file_content:read library_content:read file_variables:read"
1262
+ scope: "file_content:read file_variables:read library_content:read"
1242
1263
  }), {
1243
1264
  headers: {
1244
1265
  "Content-Type": "application/json",
@@ -1310,7 +1331,7 @@ export default {
1310
1331
  const figmaAuthUrl = new URL("https://www.figma.com/oauth");
1311
1332
  figmaAuthUrl.searchParams.set("client_id", env.FIGMA_OAUTH_CLIENT_ID);
1312
1333
  figmaAuthUrl.searchParams.set("redirect_uri", redirectUri);
1313
- figmaAuthUrl.searchParams.set("scope", "file_content:read,library_content:read,file_variables:read");
1334
+ figmaAuthUrl.searchParams.set("scope", "file_content:read,file_variables:read,library_content:read");
1314
1335
  figmaAuthUrl.searchParams.set("state", stateToken);
1315
1336
  figmaAuthUrl.searchParams.set("response_type", "code");
1316
1337
  return Response.redirect(figmaAuthUrl.toString(), 302);
@@ -1558,7 +1579,7 @@ export default {
1558
1579
  return new Response(JSON.stringify({
1559
1580
  status: "healthy",
1560
1581
  service: "Figma Console MCP",
1561
- version: "1.12.0",
1582
+ version: "1.13.0",
1562
1583
  endpoints: {
1563
1584
  mcp: ["/sse", "/mcp"],
1564
1585
  oauth_mcp_spec: ["/.well-known/oauth-authorization-server", "/authorize", "/token", "/oauth/register"],
@@ -1604,13 +1625,13 @@ export default {
1604
1625
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
1605
1626
  <title>Figma Console MCP - The Most Comprehensive MCP Server for Figma</title>
1606
1627
  <link rel="icon" type="image/svg+xml" href="https://docs.figma-console-mcp.southleft.com/favicon.svg">
1607
- <meta name="description" content="Turn your Figma design system into a living API. 57+ tools give AI assistants deep access to design tokens, component specs, variables, and programmatic design creation.">
1628
+ <meta name="description" content="Turn your Figma design system into a living API. 59+ tools give AI assistants deep access to design tokens, component specs, variables, and programmatic design creation.">
1608
1629
 
1609
1630
  <!-- Open Graph -->
1610
1631
  <meta property="og:type" content="website">
1611
1632
  <meta property="og:url" content="https://figma-console-mcp.southleft.com">
1612
1633
  <meta property="og:title" content="Figma Console MCP - Turn Your Design System Into a Living API">
1613
- <meta property="og:description" content="The most comprehensive MCP server for Figma. 57+ tools give AI assistants deep access to design tokens, components, variables, and programmatic design creation.">
1634
+ <meta property="og:description" content="The most comprehensive MCP server for Figma. 59+ tools give AI assistants deep access to design tokens, components, variables, and programmatic design creation.">
1614
1635
  <meta property="og:image" content="https://docs.figma-console-mcp.southleft.com/images/og-image.jpg">
1615
1636
  <meta property="og:image:width" content="1200">
1616
1637
  <meta property="og:image:height" content="630">
@@ -1618,7 +1639,7 @@ export default {
1618
1639
  <!-- Twitter -->
1619
1640
  <meta name="twitter:card" content="summary_large_image">
1620
1641
  <meta name="twitter:title" content="Figma Console MCP - Turn Your Design System Into a Living API">
1621
- <meta name="twitter:description" content="The most comprehensive MCP server for Figma. 57+ tools give AI assistants deep access to design tokens, components, variables, and programmatic design creation.">
1642
+ <meta name="twitter:description" content="The most comprehensive MCP server for Figma. 59+ tools give AI assistants deep access to design tokens, components, variables, and programmatic design creation.">
1622
1643
  <meta name="twitter:image" content="https://docs.figma-console-mcp.southleft.com/images/og-image.jpg">
1623
1644
 
1624
1645
  <meta name="theme-color" content="#0D9488">
@@ -2502,7 +2523,7 @@ export default {
2502
2523
  <div class="grid-cell showcase-cell rule-left">
2503
2524
  <div class="showcase-label">What AI Can Access</div>
2504
2525
  <div class="showcase-stat">
2505
- <span class="number">56+</span>
2526
+ <span class="number">59+</span>
2506
2527
  <span class="label">MCP tools for Figma</span>
2507
2528
  </div>
2508
2529
  <div class="capability-list">
@@ -2519,8 +2540,16 @@ export default {
2519
2540
  <span>Programmatic design creation</span>
2520
2541
  </div>
2521
2542
  <div class="capability-item">
2522
- <svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg>
2523
- <span>Real-time plugin debugging</span>
2543
+ <svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
2544
+ <span>WCAG accessibility linting</span>
2545
+ </div>
2546
+ <div class="capability-item">
2547
+ <svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z"/></svg>
2548
+ <span>Cloud relay for web AI clients</span>
2549
+ </div>
2550
+ <div class="capability-item">
2551
+ <svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/><path d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/></svg>
2552
+ <span>Visual debugging and screenshots</span>
2524
2553
  </div>
2525
2554
  </div>
2526
2555
  </div>
@@ -2568,8 +2597,8 @@ export default {
2568
2597
  <div class="capability-icon">
2569
2598
  <svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg>
2570
2599
  </div>
2571
- <h3>Plugin Debugging</h3>
2572
- <p>Capture real-time console logs from Figma plugins. Let AI analyze errors and suggest fixes without context switching.</p>
2600
+ <h3>Visual Debugging</h3>
2601
+ <p>Capture screenshots, inspect node properties, and track selection changes. Let AI analyze your designs and suggest improvements.</p>
2573
2602
  </div>
2574
2603
  </div>
2575
2604
 
@@ -2599,7 +2628,11 @@ export default {
2599
2628
  </div>
2600
2629
  <div class="prompt-item">
2601
2630
  <svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
2602
- <span>"Why is my plugin throwing this error?"</span>
2631
+ <span>"Check my design for accessibility issues"</span>
2632
+ </div>
2633
+ <div class="prompt-item">
2634
+ <svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
2635
+ <span>"Connect to my Figma plugin and create a card component"</span>
2603
2636
  </div>
2604
2637
  </div>
2605
2638
  </div>
@@ -2623,7 +2656,7 @@ export default {
2623
2656
  </li>
2624
2657
  <li>
2625
2658
  <svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M5 13l4 4L19 7"/></svg>
2626
- <span>Debug Figma plugins without leaving your workflow</span>
2659
+ <span>Lint designs for accessibility and quality issues</span>
2627
2660
  </li>
2628
2661
  </ul>
2629
2662
  </div>
@@ -2684,7 +2717,7 @@ export default {
2684
2717
  <div class="grid-cell getting-started-cell">
2685
2718
  <div class="getting-started-content">
2686
2719
  <h3>Ready to get started?</h3>
2687
- <p>Setup varies based on your needs: remote mode for quick API access, or local mode for full plugin debugging. Our docs will guide you through the right path.</p>
2720
+ <p>Three ways to connect: local mode for full capabilities, cloud mode for web AI clients like Claude.ai and v0, or remote mode for quick read-only access. Our docs will guide you through the right path.</p>
2688
2721
  </div>
2689
2722
  <div class="getting-started-actions">
2690
2723
  <a href="https://docs.figma-console-mcp.southleft.com/setup" class="btn btn-primary">