figma-console-mcp 1.17.2 → 1.17.4
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 +12 -11
- package/dist/cloudflare/core/figma-tools.js +86 -28
- package/dist/cloudflare/core/port-discovery.js +88 -0
- package/dist/cloudflare/index.js +6 -6
- package/dist/core/port-discovery.d.ts +21 -0
- package/dist/core/port-discovery.d.ts.map +1 -1
- package/dist/core/port-discovery.js +88 -0
- package/dist/core/port-discovery.js.map +1 -1
- package/dist/local.d.ts.map +1 -1
- package/dist/local.js +29 -1
- package/dist/local.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,9 +51,9 @@ Figma Console MCP connects AI assistants (like Claude) to Figma, enabling:
|
|
|
51
51
|
| Real-time monitoring (console, selection) | ✅ | ❌ | ❌ |
|
|
52
52
|
| Desktop Bridge plugin | ✅ | ✅ | ❌ |
|
|
53
53
|
| Requires Node.js | Yes | **No** | No |
|
|
54
|
-
| **Total tools available** | **
|
|
54
|
+
| **Total tools available** | **84+** | **43** | **22** |
|
|
55
55
|
|
|
56
|
-
> **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
|
|
56
|
+
> **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 84+ tools with real-time monitoring.
|
|
57
57
|
|
|
58
58
|
---
|
|
59
59
|
|
|
@@ -61,7 +61,7 @@ Figma Console MCP connects AI assistants (like Claude) to Figma, enabling:
|
|
|
61
61
|
|
|
62
62
|
**Best for:** Designers who want full AI-assisted design capabilities.
|
|
63
63
|
|
|
64
|
-
**What you get:** All
|
|
64
|
+
**What you get:** All 84+ tools including design creation, variable management, and component instantiation.
|
|
65
65
|
|
|
66
66
|
#### Prerequisites
|
|
67
67
|
|
|
@@ -74,7 +74,8 @@ Figma Console MCP connects AI assistants (like Claude) to Figma, enabling:
|
|
|
74
74
|
1. Go to [Manage personal access tokens](https://help.figma.com/hc/en-us/articles/8085703771159-Manage-personal-access-tokens) in Figma Help
|
|
75
75
|
2. Follow the steps to **create a new personal access token**
|
|
76
76
|
3. Enter description: `Figma Console MCP`
|
|
77
|
-
4.
|
|
77
|
+
4. Set scopes: **File content** (Read), **Variables** (Read), **Comments** (Read and write)
|
|
78
|
+
5. **Copy the token** — you won't see it again! (starts with `figd_`)
|
|
78
79
|
|
|
79
80
|
#### Step 2: Configure Your MCP Client
|
|
80
81
|
|
|
@@ -155,7 +156,7 @@ Create a simple frame with a blue background
|
|
|
155
156
|
|
|
156
157
|
**Best for:** Developers who want to modify source code or contribute to the project.
|
|
157
158
|
|
|
158
|
-
**What you get:** Same
|
|
159
|
+
**What you get:** Same 84+ tools as NPX, plus full source code access.
|
|
159
160
|
|
|
160
161
|
#### Quick Setup
|
|
161
162
|
|
|
@@ -244,7 +245,7 @@ Ready for design creation? Follow the [NPX Setup](#-npx-setup-recommended) guide
|
|
|
244
245
|
|
|
245
246
|
**Best for:** Using Claude.ai, v0, Replit, or Lovable to create and modify Figma designs — no Node.js required.
|
|
246
247
|
|
|
247
|
-
**What you get:**
|
|
248
|
+
**What you get:** 76 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.
|
|
248
249
|
|
|
249
250
|
#### Prerequisites
|
|
250
251
|
|
|
@@ -301,7 +302,7 @@ AI Client → Cloud MCP Server → Durable Object Relay → Desktop Bridge Plugi
|
|
|
301
302
|
| Feature | NPX (Recommended) | Cloud Mode | Local Git | Remote SSE |
|
|
302
303
|
|---------|-------------------|------------|-----------|------------|
|
|
303
304
|
| **Setup time** | ~10 minutes | ~5 minutes | ~15 minutes | ~2 minutes |
|
|
304
|
-
| **Total tools** | **
|
|
305
|
+
| **Total tools** | **84+** | **43** | **84+** | **22** (read-only) |
|
|
305
306
|
| **Design creation** | ✅ | ✅ | ✅ | ❌ |
|
|
306
307
|
| **Variable management** | ✅ | ✅ | ✅ | ❌ |
|
|
307
308
|
| **Component instantiation** | ✅ | ✅ | ✅ | ❌ |
|
|
@@ -316,7 +317,7 @@ AI Client → Cloud MCP Server → Durable Object Relay → Desktop Bridge Plugi
|
|
|
316
317
|
| **Automatic updates** | ✅ (`@latest`) | ✅ | Manual (`git pull`) | ✅ |
|
|
317
318
|
| **Source code access** | ❌ | ❌ | ✅ | ❌ |
|
|
318
319
|
|
|
319
|
-
> **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
|
|
320
|
+
> **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 84+ tools.
|
|
320
321
|
|
|
321
322
|
**📖 [Complete Feature Comparison](docs/mode-comparison.md)**
|
|
322
323
|
|
|
@@ -362,7 +363,7 @@ When you first use design system tools:
|
|
|
362
363
|
### Local Mode - Personal Access Token (Manual)
|
|
363
364
|
|
|
364
365
|
1. Visit https://help.figma.com/hc/en-us/articles/8085703771159-Manage-personal-access-tokens
|
|
365
|
-
2. Generate token
|
|
366
|
+
2. Generate token with scopes: **File content** (Read), **Variables** (Read), **Comments** (Read and write)
|
|
366
367
|
3. Add to MCP config as `FIGMA_ACCESS_TOKEN` environment variable
|
|
367
368
|
|
|
368
369
|
---
|
|
@@ -648,7 +649,7 @@ The **Figma Desktop Bridge** plugin is the recommended way to connect Figma to t
|
|
|
648
649
|
- The MCP server communicates via **WebSocket** through the Desktop Bridge plugin
|
|
649
650
|
- The server tries port 9223 first, then automatically falls back through ports 9224–9232 if needed
|
|
650
651
|
- The plugin scans all ports in the range and connects to every active server it finds
|
|
651
|
-
- All
|
|
652
|
+
- All 84+ tools work through the WebSocket transport
|
|
652
653
|
|
|
653
654
|
**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).
|
|
654
655
|
|
|
@@ -785,7 +786,7 @@ The architecture supports adding new apps with minimal boilerplate — each app
|
|
|
785
786
|
|
|
786
787
|
## 🛤️ Roadmap
|
|
787
788
|
|
|
788
|
-
**Current Status:** v1.17.0 (Stable) - Production-ready with FigJam + Slides support, Cloud Write Relay, Design System Kit, WebSocket-only connectivity, smart multi-file tracking,
|
|
789
|
+
**Current Status:** v1.17.0 (Stable) - Production-ready with FigJam + Slides support, Cloud Write Relay, Design System Kit, WebSocket-only connectivity, smart multi-file tracking, 84+ tools, Comments API, and MCP Apps
|
|
789
790
|
|
|
790
791
|
**Recent Releases:**
|
|
791
792
|
- [x] **v1.17.0** - Figma Slides Support: 15 new tools for managing presentations — slides, transitions, content, reordering, and navigation. Inspired by Toni Haidamous (PR #11).
|
|
@@ -1198,15 +1198,23 @@ export function registerFigmaAPITools(server, getFigmaAPI, getCurrentUrl, getCon
|
|
|
1198
1198
|
// =====================================================================
|
|
1199
1199
|
// FETCH LOGIC: No cache or cache invalid/refresh requested
|
|
1200
1200
|
// =====================================================================
|
|
1201
|
-
// Check if REST API token is available
|
|
1201
|
+
// Check if REST API token is available
|
|
1202
1202
|
const hasToken = !!process.env.FIGMA_ACCESS_TOKEN;
|
|
1203
1203
|
let restApiSucceeded = false;
|
|
1204
|
+
// Detect Desktop Bridge availability early (needed for priority decision)
|
|
1205
|
+
if (ensureInitialized && !getDesktopConnector && !parseFromConsole) {
|
|
1206
|
+
logger.info("Calling ensureInitialized to initialize browser manager (legacy path)");
|
|
1207
|
+
await ensureInitialized();
|
|
1208
|
+
}
|
|
1209
|
+
const browserManager = getBrowserManager?.();
|
|
1210
|
+
const hasDesktopConnection = !!getDesktopConnector || !!browserManager;
|
|
1204
1211
|
// PRIORITY LOGIC:
|
|
1205
|
-
// 1. If
|
|
1206
|
-
// 2. If no
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1212
|
+
// 1. If Desktop Bridge connected → Try Desktop Bridge FIRST (instant, all plans, full Plugin API data)
|
|
1213
|
+
// 2. If no Desktop Bridge OR it fails → Try REST API as fallback (Enterprise users)
|
|
1214
|
+
// 3. If both fail → Console snippet fallback (manual user step)
|
|
1215
|
+
logger.info({ hasToken, hasDesktopConnection }, "Authentication method detection");
|
|
1216
|
+
// Try REST API only when Desktop Bridge is NOT available
|
|
1217
|
+
if (hasToken && !parseFromConsole && !hasDesktopConnection) {
|
|
1210
1218
|
try {
|
|
1211
1219
|
logger.info({ fileKey, includePublished, verbosity, enrich }, "Fetching variables via REST API (priority: token detected)");
|
|
1212
1220
|
const api = await getFigmaAPI();
|
|
@@ -1449,26 +1457,9 @@ export function registerFigmaAPITools(server, getFigmaAPI, getCurrentUrl, getCon
|
|
|
1449
1457
|
// Don't throw - fall through to Desktop Bridge
|
|
1450
1458
|
}
|
|
1451
1459
|
}
|
|
1452
|
-
//
|
|
1453
|
-
//
|
|
1454
|
-
if (
|
|
1455
|
-
logger.info("Calling ensureInitialized to initialize browser manager (legacy path)");
|
|
1456
|
-
await ensureInitialized();
|
|
1457
|
-
}
|
|
1458
|
-
const browserManager = getBrowserManager?.();
|
|
1459
|
-
const hasDesktopConnection = !!getDesktopConnector || !!browserManager;
|
|
1460
|
-
logger.info({ hasBrowserManager: !!browserManager, hasDesktopConnector: !!getDesktopConnector, parseFromConsole, hasToken, restApiSucceeded }, "Desktop connection check");
|
|
1461
|
-
// Debug: Log why Desktop connection might be skipped
|
|
1462
|
-
if (!hasDesktopConnection) {
|
|
1463
|
-
logger.error("Desktop connection skipped: neither connector nor browserManager available");
|
|
1464
|
-
}
|
|
1465
|
-
else if (parseFromConsole) {
|
|
1466
|
-
logger.info("Desktop connection skipped: parseFromConsole is true");
|
|
1467
|
-
}
|
|
1468
|
-
else if (restApiSucceeded) {
|
|
1469
|
-
logger.info("Desktop connection skipped: REST API already succeeded");
|
|
1470
|
-
}
|
|
1471
|
-
if (hasDesktopConnection && !parseFromConsole && (!hasToken || !restApiSucceeded)) {
|
|
1460
|
+
// PRIMARY: Try Desktop Bridge (instant, all plans, full Plugin API data including aliases)
|
|
1461
|
+
// Also used as fallback when REST API fails (403, timeout, rate limit)
|
|
1462
|
+
if (hasDesktopConnection && !parseFromConsole && !restApiSucceeded) {
|
|
1472
1463
|
try {
|
|
1473
1464
|
logger.info({ fileKey }, "Attempting to get variables via Desktop connection");
|
|
1474
1465
|
let connector;
|
|
@@ -1683,10 +1674,77 @@ export function registerFigmaAPITools(server, getFigmaAPI, getCurrentUrl, getCon
|
|
|
1683
1674
|
catch (logError) {
|
|
1684
1675
|
// Ignore logging errors
|
|
1685
1676
|
}
|
|
1686
|
-
// Continue to try
|
|
1677
|
+
// Continue to try REST API fallback
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
// SECONDARY FALLBACK: Try REST API if Desktop Bridge failed/unavailable and token exists
|
|
1681
|
+
if (hasToken && !parseFromConsole && !restApiSucceeded) {
|
|
1682
|
+
try {
|
|
1683
|
+
logger.info({ fileKey }, "Attempting REST API fallback for variables");
|
|
1684
|
+
const api = await getFigmaAPI();
|
|
1685
|
+
const { local, published, localError } = await withTimeout(api.getAllVariables(fileKey), 30000, 'Figma Variables API');
|
|
1686
|
+
if (!localError && local) {
|
|
1687
|
+
let localFormatted = formatVariables(local);
|
|
1688
|
+
let publishedFormatted = includePublished ? formatVariables(published) : null;
|
|
1689
|
+
// Apply filters
|
|
1690
|
+
if (format === 'filtered') {
|
|
1691
|
+
const filteredLocal = applyFilters({ variables: localFormatted.variables, variableCollections: localFormatted.collections }, { collection, namePattern, mode }, verbosity || "standard");
|
|
1692
|
+
localFormatted = { summary: localFormatted.summary, collections: filteredLocal.variableCollections, variables: filteredLocal.variables };
|
|
1693
|
+
}
|
|
1694
|
+
// Apply verbosity
|
|
1695
|
+
if (verbosity && verbosity !== 'full') {
|
|
1696
|
+
const verbosityFiltered = applyFilters({ variables: localFormatted.variables, variableCollections: localFormatted.collections }, {}, verbosity);
|
|
1697
|
+
localFormatted = { ...localFormatted, collections: verbosityFiltered.variableCollections, variables: verbosityFiltered.variables };
|
|
1698
|
+
}
|
|
1699
|
+
// Cache
|
|
1700
|
+
const dataForCache = {
|
|
1701
|
+
fileKey,
|
|
1702
|
+
local: { summary: localFormatted.summary, collections: localFormatted.collections, variables: localFormatted.variables },
|
|
1703
|
+
...(includePublished && publishedFormatted && { published: { summary: publishedFormatted.summary, collections: publishedFormatted.collections, variables: publishedFormatted.variables } }),
|
|
1704
|
+
verbosity: verbosity || "standard",
|
|
1705
|
+
enriched: enrich || false,
|
|
1706
|
+
timestamp: Date.now(),
|
|
1707
|
+
source: "rest_api",
|
|
1708
|
+
};
|
|
1709
|
+
if (variablesCache) {
|
|
1710
|
+
variablesCache.set(fileKey, { data: dataForCache, timestamp: Date.now() });
|
|
1711
|
+
}
|
|
1712
|
+
// Apply alias resolution
|
|
1713
|
+
if (resolveAliases && localFormatted.variables?.length > 0) {
|
|
1714
|
+
const allVariablesMap = new Map();
|
|
1715
|
+
const collectionsMap = new Map();
|
|
1716
|
+
for (const v of localFormatted.variables || [])
|
|
1717
|
+
allVariablesMap.set(v.id, v);
|
|
1718
|
+
for (const c of localFormatted.collections || [])
|
|
1719
|
+
collectionsMap.set(c.id, c);
|
|
1720
|
+
localFormatted.variables = resolveVariableAliases(localFormatted.variables, allVariablesMap, collectionsMap);
|
|
1721
|
+
}
|
|
1722
|
+
restApiSucceeded = true;
|
|
1723
|
+
logger.info({ fileKey }, "REST API fallback succeeded");
|
|
1724
|
+
const responseData = {
|
|
1725
|
+
fileKey,
|
|
1726
|
+
local: { summary: localFormatted.summary, collections: localFormatted.collections, variables: localFormatted.variables },
|
|
1727
|
+
verbosity: verbosity || "standard",
|
|
1728
|
+
enriched: enrich || false,
|
|
1729
|
+
};
|
|
1730
|
+
return adaptiveResponse(responseData, {
|
|
1731
|
+
toolName: "figma_get_variables",
|
|
1732
|
+
suggestedActions: [
|
|
1733
|
+
"Use verbosity='inventory' or 'summary' for large variable sets",
|
|
1734
|
+
"Apply filters: collection, namePattern, or mode parameters",
|
|
1735
|
+
],
|
|
1736
|
+
});
|
|
1737
|
+
}
|
|
1738
|
+
else {
|
|
1739
|
+
logger.warn({ error: localError, fileKey }, "REST API fallback also failed (likely non-Enterprise plan)");
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
catch (restFallbackError) {
|
|
1743
|
+
const msg = restFallbackError instanceof Error ? restFallbackError.message : String(restFallbackError);
|
|
1744
|
+
logger.warn({ error: msg, fileKey }, "REST API fallback failed");
|
|
1687
1745
|
}
|
|
1688
1746
|
}
|
|
1689
|
-
//
|
|
1747
|
+
// LAST RESORT: Parse from console logs if requested
|
|
1690
1748
|
if (parseFromConsole) {
|
|
1691
1749
|
const consoleMonitor = getConsoleMonitor?.();
|
|
1692
1750
|
if (!consoleMonitor) {
|
|
@@ -41,6 +41,8 @@ const PORT_FILE_DIR = tmpdir();
|
|
|
41
41
|
export const MAX_PORT_FILE_AGE_MS = 4 * 60 * 60 * 1000;
|
|
42
42
|
/** Maximum time since last heartbeat before a process is considered stale (5 minutes) */
|
|
43
43
|
export const HEARTBEAT_STALE_MS = 5 * 60 * 1000;
|
|
44
|
+
/** Minimum age before an instance can be evicted as last resort (2 minutes) */
|
|
45
|
+
export const EVICTION_MIN_AGE_MS = 2 * 60 * 1000;
|
|
44
46
|
/** Interval between heartbeat refreshes (30 seconds) */
|
|
45
47
|
export const HEARTBEAT_INTERVAL_MS = 30 * 1000;
|
|
46
48
|
/**
|
|
@@ -336,6 +338,92 @@ export function cleanupOrphanedProcesses(preferredPort = DEFAULT_WS_PORT) {
|
|
|
336
338
|
}
|
|
337
339
|
return cleaned;
|
|
338
340
|
}
|
|
341
|
+
/**
|
|
342
|
+
* Last-resort eviction: terminate the oldest MCP server instance to free a port.
|
|
343
|
+
*
|
|
344
|
+
* Called ONLY when all ports in the range are exhausted after both cleanup phases
|
|
345
|
+
* (cleanupStalePortFiles + cleanupOrphanedProcesses) have already run. This handles
|
|
346
|
+
* the case where old instances are still alive and heartbeating but no longer needed
|
|
347
|
+
* (e.g., from yesterday's Claude Desktop session that was closed without terminating
|
|
348
|
+
* the MCP server process).
|
|
349
|
+
*
|
|
350
|
+
* Safety guards:
|
|
351
|
+
* - Only evicts instances older than EVICTION_MIN_AGE_MS (2 min) to prevent cascade
|
|
352
|
+
* - Never evicts our own PID
|
|
353
|
+
* - Re-reads port file before kill to avoid TOCTOU race
|
|
354
|
+
* - Uses SIGTERM for graceful shutdown
|
|
355
|
+
* - Waits briefly for port release before returning
|
|
356
|
+
*
|
|
357
|
+
* @returns true if an instance was evicted (caller should retry port binding), false otherwise
|
|
358
|
+
*/
|
|
359
|
+
export function evictOldestInstance(preferredPort = DEFAULT_WS_PORT) {
|
|
360
|
+
const myPid = process.pid;
|
|
361
|
+
const ports = getPortRange(preferredPort);
|
|
362
|
+
const candidates = [];
|
|
363
|
+
// Collect all valid port file entries that aren't us
|
|
364
|
+
for (const port of ports) {
|
|
365
|
+
const filePath = getPortFilePath(port);
|
|
366
|
+
try {
|
|
367
|
+
if (!existsSync(filePath))
|
|
368
|
+
continue;
|
|
369
|
+
const raw = readFileSync(filePath, 'utf-8');
|
|
370
|
+
const data = JSON.parse(raw);
|
|
371
|
+
if (data.pid === myPid)
|
|
372
|
+
continue; // Never evict ourselves
|
|
373
|
+
if (!isProcessAlive(data.pid)) {
|
|
374
|
+
// Dead process — just clean up the file (port should already be free)
|
|
375
|
+
try {
|
|
376
|
+
unlinkSync(filePath);
|
|
377
|
+
}
|
|
378
|
+
catch { /* best-effort */ }
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
candidates.push({ ...data, filePath });
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
// Corrupt or unreadable — skip
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
if (candidates.length === 0) {
|
|
388
|
+
logger.debug('No eviction candidates — ports may be held by non-MCP processes');
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
// Sort by startedAt ascending — oldest first
|
|
392
|
+
candidates.sort((a, b) => new Date(a.startedAt).getTime() - new Date(b.startedAt).getTime());
|
|
393
|
+
const oldest = candidates[0];
|
|
394
|
+
const ageMs = Date.now() - new Date(oldest.startedAt).getTime();
|
|
395
|
+
// Safety: don't evict instances that started recently (prevents cascade)
|
|
396
|
+
if (ageMs < EVICTION_MIN_AGE_MS) {
|
|
397
|
+
logger.info({ port: oldest.port, pid: oldest.pid, ageSeconds: Math.round(ageMs / 1000) }, 'Oldest instance is too recent to evict — skipping');
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
// Re-read the port file to avoid TOCTOU race
|
|
401
|
+
try {
|
|
402
|
+
const raw = readFileSync(oldest.filePath, 'utf-8');
|
|
403
|
+
const freshData = JSON.parse(raw);
|
|
404
|
+
if (freshData.pid !== oldest.pid) {
|
|
405
|
+
// PID changed between reads — another process took over, skip
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
catch {
|
|
410
|
+
// File disappeared — port may already be free
|
|
411
|
+
return true;
|
|
412
|
+
}
|
|
413
|
+
logger.info({ port: oldest.port, pid: oldest.pid, startedAt: oldest.startedAt, ageHours: Math.round(ageMs / 3600000 * 10) / 10 }, 'Evicting oldest MCP server instance to free port (all ports exhausted)');
|
|
414
|
+
terminateProcess(oldest.pid);
|
|
415
|
+
try {
|
|
416
|
+
unlinkSync(oldest.filePath);
|
|
417
|
+
}
|
|
418
|
+
catch { /* best-effort */ }
|
|
419
|
+
// Brief wait for the port to be released by the OS
|
|
420
|
+
try {
|
|
421
|
+
const { execSync } = require('child_process');
|
|
422
|
+
execSync('sleep 0.5', { timeout: 2000 });
|
|
423
|
+
}
|
|
424
|
+
catch { /* non-critical */ }
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
339
427
|
/**
|
|
340
428
|
* Register process exit handlers to clean up port advertisement file.
|
|
341
429
|
* Should be called once after the port is successfully bound.
|
package/dist/cloudflare/index.js
CHANGED
|
@@ -40,7 +40,7 @@ export class FigmaConsoleMCPv3 extends McpAgent {
|
|
|
40
40
|
super(...arguments);
|
|
41
41
|
this.server = new McpServer({
|
|
42
42
|
name: "Figma Console MCP",
|
|
43
|
-
version: "1.17.
|
|
43
|
+
version: "1.17.4",
|
|
44
44
|
});
|
|
45
45
|
this.browserManager = null;
|
|
46
46
|
this.consoleMonitor = null;
|
|
@@ -956,7 +956,7 @@ export default {
|
|
|
956
956
|
});
|
|
957
957
|
const statelessServer = new McpServer({
|
|
958
958
|
name: "Figma Console MCP",
|
|
959
|
-
version: "1.17.
|
|
959
|
+
version: "1.17.4",
|
|
960
960
|
});
|
|
961
961
|
// ================================================================
|
|
962
962
|
// Cloud Write Relay — Pairing Tool (stateless /mcp path)
|
|
@@ -1589,7 +1589,7 @@ export default {
|
|
|
1589
1589
|
return new Response(JSON.stringify({
|
|
1590
1590
|
status: "healthy",
|
|
1591
1591
|
service: "Figma Console MCP",
|
|
1592
|
-
version: "1.17.
|
|
1592
|
+
version: "1.17.4",
|
|
1593
1593
|
endpoints: {
|
|
1594
1594
|
mcp: ["/sse", "/mcp"],
|
|
1595
1595
|
oauth_mcp_spec: ["/.well-known/oauth-authorization-server", "/authorize", "/token", "/oauth/register"],
|
|
@@ -1635,13 +1635,13 @@ export default {
|
|
|
1635
1635
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1636
1636
|
<title>Figma Console MCP - The Most Comprehensive MCP Server for Figma</title>
|
|
1637
1637
|
<link rel="icon" type="image/svg+xml" href="https://docs.figma-console-mcp.southleft.com/favicon.svg">
|
|
1638
|
-
<meta name="description" content="Turn your Figma design system into a living API.
|
|
1638
|
+
<meta name="description" content="Turn your Figma design system into a living API. 84+ tools give AI assistants deep access to design tokens, component specs, variables, and programmatic design creation.">
|
|
1639
1639
|
|
|
1640
1640
|
<!-- Open Graph -->
|
|
1641
1641
|
<meta property="og:type" content="website">
|
|
1642
1642
|
<meta property="og:url" content="https://figma-console-mcp.southleft.com">
|
|
1643
1643
|
<meta property="og:title" content="Figma Console MCP - Turn Your Design System Into a Living API">
|
|
1644
|
-
<meta property="og:description" content="The most comprehensive MCP server for Figma.
|
|
1644
|
+
<meta property="og:description" content="The most comprehensive MCP server for Figma. 84+ tools give AI assistants deep access to design tokens, components, variables, and programmatic design creation.">
|
|
1645
1645
|
<meta property="og:image" content="https://docs.figma-console-mcp.southleft.com/images/og-image.jpg">
|
|
1646
1646
|
<meta property="og:image:width" content="1200">
|
|
1647
1647
|
<meta property="og:image:height" content="630">
|
|
@@ -1649,7 +1649,7 @@ export default {
|
|
|
1649
1649
|
<!-- Twitter -->
|
|
1650
1650
|
<meta name="twitter:card" content="summary_large_image">
|
|
1651
1651
|
<meta name="twitter:title" content="Figma Console MCP - Turn Your Design System Into a Living API">
|
|
1652
|
-
<meta name="twitter:description" content="The most comprehensive MCP server for Figma.
|
|
1652
|
+
<meta name="twitter:description" content="The most comprehensive MCP server for Figma. 84+ tools give AI assistants deep access to design tokens, components, variables, and programmatic design creation.">
|
|
1653
1653
|
<meta name="twitter:image" content="https://docs.figma-console-mcp.southleft.com/images/og-image.jpg">
|
|
1654
1654
|
|
|
1655
1655
|
<meta name="theme-color" content="#0D9488">
|
|
@@ -32,6 +32,8 @@ export declare const PORT_RANGE_SIZE = 10;
|
|
|
32
32
|
export declare const MAX_PORT_FILE_AGE_MS: number;
|
|
33
33
|
/** Maximum time since last heartbeat before a process is considered stale (5 minutes) */
|
|
34
34
|
export declare const HEARTBEAT_STALE_MS: number;
|
|
35
|
+
/** Minimum age before an instance can be evicted as last resort (2 minutes) */
|
|
36
|
+
export declare const EVICTION_MIN_AGE_MS: number;
|
|
35
37
|
/** Interval between heartbeat refreshes (30 seconds) */
|
|
36
38
|
export declare const HEARTBEAT_INTERVAL_MS: number;
|
|
37
39
|
export interface PortFileData {
|
|
@@ -113,6 +115,25 @@ export declare function cleanupStalePortFiles(): number;
|
|
|
113
115
|
* then this catches any remaining ghosts.
|
|
114
116
|
*/
|
|
115
117
|
export declare function cleanupOrphanedProcesses(preferredPort?: number): number;
|
|
118
|
+
/**
|
|
119
|
+
* Last-resort eviction: terminate the oldest MCP server instance to free a port.
|
|
120
|
+
*
|
|
121
|
+
* Called ONLY when all ports in the range are exhausted after both cleanup phases
|
|
122
|
+
* (cleanupStalePortFiles + cleanupOrphanedProcesses) have already run. This handles
|
|
123
|
+
* the case where old instances are still alive and heartbeating but no longer needed
|
|
124
|
+
* (e.g., from yesterday's Claude Desktop session that was closed without terminating
|
|
125
|
+
* the MCP server process).
|
|
126
|
+
*
|
|
127
|
+
* Safety guards:
|
|
128
|
+
* - Only evicts instances older than EVICTION_MIN_AGE_MS (2 min) to prevent cascade
|
|
129
|
+
* - Never evicts our own PID
|
|
130
|
+
* - Re-reads port file before kill to avoid TOCTOU race
|
|
131
|
+
* - Uses SIGTERM for graceful shutdown
|
|
132
|
+
* - Waits briefly for port release before returning
|
|
133
|
+
*
|
|
134
|
+
* @returns true if an instance was evicted (caller should retry port binding), false otherwise
|
|
135
|
+
*/
|
|
136
|
+
export declare function evictOldestInstance(preferredPort?: number): boolean;
|
|
116
137
|
/**
|
|
117
138
|
* Register process exit handlers to clean up port advertisement file.
|
|
118
139
|
* Should be called once after the port is successfully bound.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"port-discovery.d.ts","sourceRoot":"","sources":["../../src/core/port-discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AASH,uCAAuC;AACvC,eAAO,MAAM,eAAe,OAAO,CAAC;AAEpC,mEAAmE;AACnE,eAAO,MAAM,eAAe,KAAK,CAAC;AAQlC,qFAAqF;AACrF,eAAO,MAAM,oBAAoB,QAAqB,CAAC;AAEvD,yFAAyF;AACzF,eAAO,MAAM,kBAAkB,QAAgB,CAAC;AAEhD,wDAAwD;AACxD,eAAO,MAAM,qBAAqB,QAAY,CAAC;AAE/C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,sFAAsF;IACtF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,aAAa,GAAE,MAAwB,GAAG,MAAM,EAAE,CAM9E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,MAAoB,GAAG,IAAI,CAiB5E;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAa3D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAUlD;AAcD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAY3D;AAkBD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAoB9D;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,aAAa,GAAE,MAAwB,GAAG,YAAY,EAAE,CAW/F;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAsC9C;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,aAAa,GAAE,MAAwB,GAAG,MAAM,CAkExF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAatD"}
|
|
1
|
+
{"version":3,"file":"port-discovery.d.ts","sourceRoot":"","sources":["../../src/core/port-discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AASH,uCAAuC;AACvC,eAAO,MAAM,eAAe,OAAO,CAAC;AAEpC,mEAAmE;AACnE,eAAO,MAAM,eAAe,KAAK,CAAC;AAQlC,qFAAqF;AACrF,eAAO,MAAM,oBAAoB,QAAqB,CAAC;AAEvD,yFAAyF;AACzF,eAAO,MAAM,kBAAkB,QAAgB,CAAC;AAEhD,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,QAAgB,CAAC;AAEjD,wDAAwD;AACxD,eAAO,MAAM,qBAAqB,QAAY,CAAC;AAE/C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,sFAAsF;IACtF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,aAAa,GAAE,MAAwB,GAAG,MAAM,EAAE,CAM9E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,MAAoB,GAAG,IAAI,CAiB5E;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAa3D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAUlD;AAcD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAY3D;AAkBD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAoB9D;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,aAAa,GAAE,MAAwB,GAAG,YAAY,EAAE,CAW/F;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAsC9C;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,aAAa,GAAE,MAAwB,GAAG,MAAM,CAkExF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,GAAE,MAAwB,GAAG,OAAO,CA0EpF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAatD"}
|
|
@@ -41,6 +41,8 @@ const PORT_FILE_DIR = tmpdir();
|
|
|
41
41
|
export const MAX_PORT_FILE_AGE_MS = 4 * 60 * 60 * 1000;
|
|
42
42
|
/** Maximum time since last heartbeat before a process is considered stale (5 minutes) */
|
|
43
43
|
export const HEARTBEAT_STALE_MS = 5 * 60 * 1000;
|
|
44
|
+
/** Minimum age before an instance can be evicted as last resort (2 minutes) */
|
|
45
|
+
export const EVICTION_MIN_AGE_MS = 2 * 60 * 1000;
|
|
44
46
|
/** Interval between heartbeat refreshes (30 seconds) */
|
|
45
47
|
export const HEARTBEAT_INTERVAL_MS = 30 * 1000;
|
|
46
48
|
/**
|
|
@@ -336,6 +338,92 @@ export function cleanupOrphanedProcesses(preferredPort = DEFAULT_WS_PORT) {
|
|
|
336
338
|
}
|
|
337
339
|
return cleaned;
|
|
338
340
|
}
|
|
341
|
+
/**
|
|
342
|
+
* Last-resort eviction: terminate the oldest MCP server instance to free a port.
|
|
343
|
+
*
|
|
344
|
+
* Called ONLY when all ports in the range are exhausted after both cleanup phases
|
|
345
|
+
* (cleanupStalePortFiles + cleanupOrphanedProcesses) have already run. This handles
|
|
346
|
+
* the case where old instances are still alive and heartbeating but no longer needed
|
|
347
|
+
* (e.g., from yesterday's Claude Desktop session that was closed without terminating
|
|
348
|
+
* the MCP server process).
|
|
349
|
+
*
|
|
350
|
+
* Safety guards:
|
|
351
|
+
* - Only evicts instances older than EVICTION_MIN_AGE_MS (2 min) to prevent cascade
|
|
352
|
+
* - Never evicts our own PID
|
|
353
|
+
* - Re-reads port file before kill to avoid TOCTOU race
|
|
354
|
+
* - Uses SIGTERM for graceful shutdown
|
|
355
|
+
* - Waits briefly for port release before returning
|
|
356
|
+
*
|
|
357
|
+
* @returns true if an instance was evicted (caller should retry port binding), false otherwise
|
|
358
|
+
*/
|
|
359
|
+
export function evictOldestInstance(preferredPort = DEFAULT_WS_PORT) {
|
|
360
|
+
const myPid = process.pid;
|
|
361
|
+
const ports = getPortRange(preferredPort);
|
|
362
|
+
const candidates = [];
|
|
363
|
+
// Collect all valid port file entries that aren't us
|
|
364
|
+
for (const port of ports) {
|
|
365
|
+
const filePath = getPortFilePath(port);
|
|
366
|
+
try {
|
|
367
|
+
if (!existsSync(filePath))
|
|
368
|
+
continue;
|
|
369
|
+
const raw = readFileSync(filePath, 'utf-8');
|
|
370
|
+
const data = JSON.parse(raw);
|
|
371
|
+
if (data.pid === myPid)
|
|
372
|
+
continue; // Never evict ourselves
|
|
373
|
+
if (!isProcessAlive(data.pid)) {
|
|
374
|
+
// Dead process — just clean up the file (port should already be free)
|
|
375
|
+
try {
|
|
376
|
+
unlinkSync(filePath);
|
|
377
|
+
}
|
|
378
|
+
catch { /* best-effort */ }
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
candidates.push({ ...data, filePath });
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
// Corrupt or unreadable — skip
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
if (candidates.length === 0) {
|
|
388
|
+
logger.debug('No eviction candidates — ports may be held by non-MCP processes');
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
// Sort by startedAt ascending — oldest first
|
|
392
|
+
candidates.sort((a, b) => new Date(a.startedAt).getTime() - new Date(b.startedAt).getTime());
|
|
393
|
+
const oldest = candidates[0];
|
|
394
|
+
const ageMs = Date.now() - new Date(oldest.startedAt).getTime();
|
|
395
|
+
// Safety: don't evict instances that started recently (prevents cascade)
|
|
396
|
+
if (ageMs < EVICTION_MIN_AGE_MS) {
|
|
397
|
+
logger.info({ port: oldest.port, pid: oldest.pid, ageSeconds: Math.round(ageMs / 1000) }, 'Oldest instance is too recent to evict — skipping');
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
// Re-read the port file to avoid TOCTOU race
|
|
401
|
+
try {
|
|
402
|
+
const raw = readFileSync(oldest.filePath, 'utf-8');
|
|
403
|
+
const freshData = JSON.parse(raw);
|
|
404
|
+
if (freshData.pid !== oldest.pid) {
|
|
405
|
+
// PID changed between reads — another process took over, skip
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
catch {
|
|
410
|
+
// File disappeared — port may already be free
|
|
411
|
+
return true;
|
|
412
|
+
}
|
|
413
|
+
logger.info({ port: oldest.port, pid: oldest.pid, startedAt: oldest.startedAt, ageHours: Math.round(ageMs / 3600000 * 10) / 10 }, 'Evicting oldest MCP server instance to free port (all ports exhausted)');
|
|
414
|
+
terminateProcess(oldest.pid);
|
|
415
|
+
try {
|
|
416
|
+
unlinkSync(oldest.filePath);
|
|
417
|
+
}
|
|
418
|
+
catch { /* best-effort */ }
|
|
419
|
+
// Brief wait for the port to be released by the OS
|
|
420
|
+
try {
|
|
421
|
+
const { execSync } = require('child_process');
|
|
422
|
+
execSync('sleep 0.5', { timeout: 2000 });
|
|
423
|
+
}
|
|
424
|
+
catch { /* non-critical */ }
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
339
427
|
/**
|
|
340
428
|
* Register process exit handlers to clean up port advertisement file.
|
|
341
429
|
* Should be called once after the port is successfully bound.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"port-discovery.js","sourceRoot":"","sources":["../../src/core/port-discovery.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"port-discovery.js","sourceRoot":"","sources":["../../src/core/port-discovery.ts"],"names":[],"mappings":"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"}
|
package/dist/local.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../src/local.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;GAYG;
|
|
1
|
+
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../src/local.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;GAYG;AAoFH;;;GAGG;AACH,cAAM,oBAAoB;IACzB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,cAAc,CAAoC;IAC1D,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,gBAAgB,CAAgC;IACxD,OAAO,CAAC,QAAQ,CAAqC;IACrD,OAAO,CAAC,cAAc,CAA+C;IACrE,uGAAuG;IACvG,OAAO,CAAC,YAAY,CAAuB;IAC3C,6DAA6D;IAC7D,OAAO,CAAC,eAAe,CAA2B;IAClD,8EAA8E;IAC9E,OAAO,CAAC,gBAAgB,CAA+C;IACvE,OAAO,CAAC,MAAM,CAAe;IAI7B,OAAO,CAAC,cAAc,CAMR;;IA2Ed;;OAEG;YACW,WAAW;IA0BzB;;;OAGG;YACW,mBAAmB;IA6CjC;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAiBzB;;OAEG;YACW,iBAAiB;IAqB/B,wDAAwD;IACxD,OAAO,CAAC,gBAAgB,CAAuB;IAE/C;;;OAGG;IACH,OAAO,CAAC,aAAa;IAgBrB;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAuB1B;;OAEG;YACW,iBAAiB;IA+I/B;;OAEG;IACH,OAAO,CAAC,aAAa;IAggLrB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA+L5B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAgC/B;AA4ED,OAAO,EAAE,oBAAoB,EAAE,CAAC"}
|
package/dist/local.js
CHANGED
|
@@ -31,7 +31,7 @@ import { registerDesignSystemTools } from "./core/design-system-tools.js";
|
|
|
31
31
|
import { FigmaDesktopConnector } from "./core/figma-desktop-connector.js";
|
|
32
32
|
import { FigmaWebSocketServer } from "./core/websocket-server.js";
|
|
33
33
|
import { WebSocketConnector } from "./core/websocket-connector.js";
|
|
34
|
-
import { DEFAULT_WS_PORT, getPortRange, advertisePort, unadvertisePort, registerPortCleanup, discoverActiveInstances, cleanupStalePortFiles, cleanupOrphanedProcesses, refreshPortAdvertisement, HEARTBEAT_INTERVAL_MS, } from "./core/port-discovery.js";
|
|
34
|
+
import { DEFAULT_WS_PORT, getPortRange, advertisePort, unadvertisePort, registerPortCleanup, discoverActiveInstances, cleanupStalePortFiles, cleanupOrphanedProcesses, evictOldestInstance, refreshPortAdvertisement, HEARTBEAT_INTERVAL_MS, } from "./core/port-discovery.js";
|
|
35
35
|
import { registerTokenBrowserApp } from "./apps/token-browser/server.js";
|
|
36
36
|
import { registerDesignSystemDashboardApp } from "./apps/design-system-dashboard/server.js";
|
|
37
37
|
import { registerFigJamTools } from "./core/figjam-tools.js";
|
|
@@ -5056,6 +5056,34 @@ return {
|
|
|
5056
5056
|
break;
|
|
5057
5057
|
}
|
|
5058
5058
|
}
|
|
5059
|
+
// Phase 3: If all ports exhausted, try evicting the oldest instance and retry ONCE
|
|
5060
|
+
if (!boundPort && evictOldestInstance(this.wsPreferredPort)) {
|
|
5061
|
+
for (const port of portsToTry) {
|
|
5062
|
+
try {
|
|
5063
|
+
this.wsServer = new FigmaWebSocketServer({ port, host: wsHost });
|
|
5064
|
+
await this.wsServer.start();
|
|
5065
|
+
const addr = this.wsServer.address();
|
|
5066
|
+
boundPort = addr?.port ?? port;
|
|
5067
|
+
this.wsActualPort = boundPort;
|
|
5068
|
+
logger.info({ wsPort: boundPort, eviction: true }, "WebSocket bridge server started after evicting stale instance");
|
|
5069
|
+
advertisePort(boundPort, wsHost);
|
|
5070
|
+
registerPortCleanup(boundPort);
|
|
5071
|
+
const heartbeatPort = boundPort;
|
|
5072
|
+
this.wsHeartbeatTimer = setInterval(() => refreshPortAdvertisement(heartbeatPort), HEARTBEAT_INTERVAL_MS);
|
|
5073
|
+
this.wsHeartbeatTimer.unref();
|
|
5074
|
+
break;
|
|
5075
|
+
}
|
|
5076
|
+
catch (wsError) {
|
|
5077
|
+
const errorCode = wsError instanceof Error ? wsError.code : undefined;
|
|
5078
|
+
if (errorCode === "EADDRINUSE") {
|
|
5079
|
+
this.wsServer = null;
|
|
5080
|
+
continue;
|
|
5081
|
+
}
|
|
5082
|
+
this.wsServer = null;
|
|
5083
|
+
break;
|
|
5084
|
+
}
|
|
5085
|
+
}
|
|
5086
|
+
}
|
|
5059
5087
|
if (!boundPort) {
|
|
5060
5088
|
this.wsStartupError = {
|
|
5061
5089
|
code: "EADDRINUSE",
|