@mp3wizard/figma-console-mcp 1.20.2 → 1.22.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 +10 -9
- package/dist/cloudflare/core/accessibility-tools.js +306 -0
- package/dist/cloudflare/core/cloud-websocket-connector.js +11 -0
- package/dist/cloudflare/core/design-code-tools.js +160 -2
- package/dist/cloudflare/core/figjam-tools.js +25 -7
- package/dist/cloudflare/core/figma-api.js +1 -10
- package/dist/cloudflare/core/figma-desktop-connector.js +2 -0
- package/dist/cloudflare/core/websocket-connector.js +11 -0
- package/dist/cloudflare/core/websocket-server.js +61 -3
- package/dist/cloudflare/core/write-tools.js +49 -4
- package/dist/cloudflare/index.js +17 -10
- package/dist/core/accessibility-tools.d.ts +21 -0
- package/dist/core/accessibility-tools.d.ts.map +1 -0
- package/dist/core/accessibility-tools.js +307 -0
- package/dist/core/accessibility-tools.js.map +1 -0
- package/dist/core/design-code-tools.d.ts.map +1 -1
- package/dist/core/design-code-tools.js +160 -2
- package/dist/core/design-code-tools.js.map +1 -1
- package/dist/core/figjam-tools.d.ts.map +1 -1
- package/dist/core/figjam-tools.js +25 -7
- package/dist/core/figjam-tools.js.map +1 -1
- package/dist/core/figma-api.d.ts.map +1 -1
- package/dist/core/figma-api.js +1 -10
- package/dist/core/figma-api.js.map +1 -1
- package/dist/core/figma-connector.d.ts +1 -0
- package/dist/core/figma-connector.d.ts.map +1 -1
- package/dist/core/figma-desktop-connector.d.ts +1 -0
- package/dist/core/figma-desktop-connector.d.ts.map +1 -1
- package/dist/core/figma-desktop-connector.js +2 -0
- package/dist/core/figma-desktop-connector.js.map +1 -1
- package/dist/core/types/design-code.d.ts +8 -0
- package/dist/core/types/design-code.d.ts.map +1 -1
- package/dist/core/websocket-connector.d.ts +1 -0
- package/dist/core/websocket-connector.d.ts.map +1 -1
- package/dist/core/websocket-connector.js +11 -0
- package/dist/core/websocket-connector.js.map +1 -1
- package/dist/core/websocket-server.d.ts +18 -1
- package/dist/core/websocket-server.d.ts.map +1 -1
- package/dist/core/websocket-server.js +61 -3
- package/dist/core/websocket-server.js.map +1 -1
- package/dist/core/write-tools.d.ts.map +1 -1
- package/dist/core/write-tools.js +49 -4
- package/dist/core/write-tools.js.map +1 -1
- package/dist/local.d.ts +13 -0
- package/dist/local.d.ts.map +1 -1
- package/dist/local.js +181 -23
- package/dist/local.js.map +1 -1
- package/figma-desktop-bridge/code.js +1020 -1
- package/figma-desktop-bridge/ui-full.html +37 -0
- package/figma-desktop-bridge/ui.html +15 -2
- package/package.json +7 -99
|
@@ -97,16 +97,7 @@ export class FigmaAPI {
|
|
|
97
97
|
// OAuth tokens start with 'figu_' and require Authorization: Bearer header
|
|
98
98
|
// Personal Access Tokens use X-Figma-Token header
|
|
99
99
|
const isOAuthToken = this.accessToken.startsWith('figu_');
|
|
100
|
-
|
|
101
|
-
const tokenPreview = this.accessToken ? `${this.accessToken.substring(0, 10)}...` : 'NO TOKEN';
|
|
102
|
-
logger.info({
|
|
103
|
-
url,
|
|
104
|
-
tokenPreview,
|
|
105
|
-
hasToken: !!this.accessToken,
|
|
106
|
-
tokenLength: this.accessToken?.length,
|
|
107
|
-
isOAuthToken,
|
|
108
|
-
authMethod: isOAuthToken ? 'Bearer' : 'X-Figma-Token'
|
|
109
|
-
}, 'Making Figma API request with token');
|
|
100
|
+
logger.debug({ url, authMethod: isOAuthToken ? 'Bearer' : 'X-Figma-Token' }, 'Making Figma API request');
|
|
110
101
|
const headers = {
|
|
111
102
|
'Content-Type': 'application/json',
|
|
112
103
|
...(options.headers || {}),
|
|
@@ -1262,6 +1262,8 @@ export class FigmaDesktopConnector {
|
|
|
1262
1262
|
throw error;
|
|
1263
1263
|
}
|
|
1264
1264
|
}
|
|
1265
|
+
// Component accessibility audit — not supported via legacy CDP transport
|
|
1266
|
+
async auditComponentAccessibility() { throw new Error('Component accessibility audit requires WebSocket transport'); }
|
|
1265
1267
|
// FigJam operations — not supported via legacy CDP transport
|
|
1266
1268
|
async createSticky() { throw new Error('FigJam operations require WebSocket transport'); }
|
|
1267
1269
|
async createStickies() { throw new Error('FigJam operations require WebSocket transport'); }
|
|
@@ -266,6 +266,17 @@ export class WebSocketConnector {
|
|
|
266
266
|
return this.wsServer.sendCommand('LINT_DESIGN', params, 120000);
|
|
267
267
|
}
|
|
268
268
|
// ============================================================================
|
|
269
|
+
// Component accessibility audit
|
|
270
|
+
// ============================================================================
|
|
271
|
+
async auditComponentAccessibility(nodeId, targetSize) {
|
|
272
|
+
const params = {};
|
|
273
|
+
if (nodeId)
|
|
274
|
+
params.nodeId = nodeId;
|
|
275
|
+
if (targetSize !== undefined)
|
|
276
|
+
params.targetSize = targetSize;
|
|
277
|
+
return this.wsServer.sendCommand('AUDIT_COMPONENT_ACCESSIBILITY', params, 120000);
|
|
278
|
+
}
|
|
279
|
+
// ============================================================================
|
|
269
280
|
// FigJam operations
|
|
270
281
|
// ============================================================================
|
|
271
282
|
async createSticky(params) {
|
|
@@ -71,6 +71,8 @@ export class FigmaWebSocketServer extends EventEmitter {
|
|
|
71
71
|
this.documentChangeBufferSize = 200;
|
|
72
72
|
/** Cached plugin UI HTML content — loaded once and served to bootloader requests */
|
|
73
73
|
this._pluginUIContent = null;
|
|
74
|
+
/** Heartbeat interval for detecting dead connections via ping/pong */
|
|
75
|
+
this._heartbeatInterval = null;
|
|
74
76
|
this.options = options;
|
|
75
77
|
this._startedAt = Date.now();
|
|
76
78
|
}
|
|
@@ -103,12 +105,15 @@ export class FigmaWebSocketServer extends EventEmitter {
|
|
|
103
105
|
}
|
|
104
106
|
// Health/version endpoint
|
|
105
107
|
if (url === '/health' || url === '/') {
|
|
108
|
+
const now = Date.now();
|
|
109
|
+
const connectedClients = Array.from(this.clients.values()).filter(c => c.ws.readyState === WebSocket.OPEN && (now - c.lastPongAt) < 90000).length;
|
|
106
110
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
107
111
|
res.end(JSON.stringify({
|
|
108
112
|
status: 'ok',
|
|
109
113
|
version: SERVER_VERSION,
|
|
110
114
|
clients: this.clients.size,
|
|
111
|
-
|
|
115
|
+
connectedClients,
|
|
116
|
+
uptime: Math.floor((now - this._startedAt) / 1000),
|
|
112
117
|
}));
|
|
113
118
|
return;
|
|
114
119
|
}
|
|
@@ -185,6 +190,7 @@ export class FigmaWebSocketServer extends EventEmitter {
|
|
|
185
190
|
// Start listening on the HTTP server (which also handles WS upgrades)
|
|
186
191
|
this.httpServer.listen(this.options.port, this.options.host || 'localhost', () => {
|
|
187
192
|
this._isStarted = true;
|
|
193
|
+
this.startHeartbeat();
|
|
188
194
|
logger.info({ port: this.options.port, host: this.options.host || 'localhost' }, 'WebSocket bridge server started (with HTTP plugin UI endpoint)');
|
|
189
195
|
resolve();
|
|
190
196
|
});
|
|
@@ -242,6 +248,18 @@ export class FigmaWebSocketServer extends EventEmitter {
|
|
|
242
248
|
ws.on('error', (error) => {
|
|
243
249
|
logger.error({ error }, 'WebSocket client error');
|
|
244
250
|
});
|
|
251
|
+
// Track pong responses for heartbeat-based liveness detection.
|
|
252
|
+
// Browser WebSocket clients auto-respond to pings per RFC 6455 —
|
|
253
|
+
// no plugin-side code changes needed.
|
|
254
|
+
ws.isAlive = true;
|
|
255
|
+
ws.on('pong', () => {
|
|
256
|
+
ws.isAlive = true;
|
|
257
|
+
// Update lastPongAt on the named client if identified
|
|
258
|
+
const found = this.findClientByWs(ws);
|
|
259
|
+
if (found) {
|
|
260
|
+
found.client.lastPongAt = Date.now();
|
|
261
|
+
}
|
|
262
|
+
});
|
|
245
263
|
});
|
|
246
264
|
}
|
|
247
265
|
catch (error) {
|
|
@@ -420,6 +438,7 @@ export class FigmaWebSocketServer extends EventEmitter {
|
|
|
420
438
|
documentChanges: existing?.documentChanges || [],
|
|
421
439
|
consoleLogs: existing?.consoleLogs || [],
|
|
422
440
|
lastActivity: Date.now(),
|
|
441
|
+
lastPongAt: Date.now(),
|
|
423
442
|
gracePeriodTimer: null,
|
|
424
443
|
});
|
|
425
444
|
// Most recently connected file becomes active (user just opened the plugin there).
|
|
@@ -528,11 +547,35 @@ export class FigmaWebSocketServer extends EventEmitter {
|
|
|
528
547
|
});
|
|
529
548
|
}
|
|
530
549
|
/**
|
|
531
|
-
*
|
|
550
|
+
* Start the heartbeat interval that pings all connected clients every 30s.
|
|
551
|
+
* Detects silently dropped connections (e.g., macOS sleep, network change)
|
|
552
|
+
* that the OS TCP keepalive would take 30-120s to catch.
|
|
553
|
+
* Browser WebSocket clients auto-respond to pings per RFC 6455.
|
|
554
|
+
*/
|
|
555
|
+
startHeartbeat() {
|
|
556
|
+
this._heartbeatInterval = setInterval(() => {
|
|
557
|
+
if (!this.wss)
|
|
558
|
+
return;
|
|
559
|
+
for (const ws of this.wss.clients) {
|
|
560
|
+
if (ws.isAlive === false) {
|
|
561
|
+
logger.info('Terminating unresponsive WebSocket client (missed heartbeat pong)');
|
|
562
|
+
ws.terminate();
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
ws.isAlive = false;
|
|
566
|
+
ws.ping();
|
|
567
|
+
}
|
|
568
|
+
}, 30000);
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Check if any named client is connected (transport availability check).
|
|
572
|
+
* Checks both socket readyState and heartbeat pong freshness to avoid
|
|
573
|
+
* reporting phantom-connected state on silently dropped connections.
|
|
532
574
|
*/
|
|
533
575
|
isClientConnected() {
|
|
576
|
+
const now = Date.now();
|
|
534
577
|
for (const [, client] of this.clients) {
|
|
535
|
-
if (client.ws.readyState === WebSocket.OPEN) {
|
|
578
|
+
if (client.ws.readyState === WebSocket.OPEN && (now - client.lastPongAt) < 90000) {
|
|
536
579
|
return true;
|
|
537
580
|
}
|
|
538
581
|
}
|
|
@@ -687,6 +730,16 @@ export class FigmaWebSocketServer extends EventEmitter {
|
|
|
687
730
|
}
|
|
688
731
|
return files;
|
|
689
732
|
}
|
|
733
|
+
/**
|
|
734
|
+
* Get the last pong timestamp for the active client.
|
|
735
|
+
* Returns null if no active client or no pong received yet.
|
|
736
|
+
*/
|
|
737
|
+
getActiveClientLastPongAt() {
|
|
738
|
+
if (!this._activeFileKey)
|
|
739
|
+
return null;
|
|
740
|
+
const client = this.clients.get(this._activeFileKey);
|
|
741
|
+
return client?.lastPongAt ?? null;
|
|
742
|
+
}
|
|
690
743
|
/**
|
|
691
744
|
* Set the active file by fileKey. Returns true if the file is connected.
|
|
692
745
|
*/
|
|
@@ -745,6 +798,11 @@ export class FigmaWebSocketServer extends EventEmitter {
|
|
|
745
798
|
* Stop the server and clean up all connections
|
|
746
799
|
*/
|
|
747
800
|
async stop() {
|
|
801
|
+
// Clear heartbeat interval
|
|
802
|
+
if (this._heartbeatInterval) {
|
|
803
|
+
clearInterval(this._heartbeatInterval);
|
|
804
|
+
this._heartbeatInterval = null;
|
|
805
|
+
}
|
|
748
806
|
// Clear all per-client grace period timers
|
|
749
807
|
for (const [, client] of this.clients) {
|
|
750
808
|
if (client.gracePeriodTimer) {
|
|
@@ -2055,13 +2055,17 @@ return {
|
|
|
2055
2055
|
}
|
|
2056
2056
|
});
|
|
2057
2057
|
// Tool: Lint Design for accessibility and quality issues
|
|
2058
|
-
server.tool("figma_lint_design", "Run accessibility (WCAG) and design quality checks on the current page or a specific node tree. " +
|
|
2059
|
-
"
|
|
2060
|
-
"
|
|
2058
|
+
server.tool("figma_lint_design", "Run comprehensive accessibility (WCAG 2.2) and design quality checks on the current page or a specific node tree. " +
|
|
2059
|
+
"WCAG checks (13 rules): color contrast (AA), non-text contrast (1.4.11), color-only differentiation (1.4.1), " +
|
|
2060
|
+
"focus indicators (2.4.7), text sizing, touch targets, line height, letter spacing, paragraph spacing (1.4.12), " +
|
|
2061
|
+
"image alt text (1.1.1), heading hierarchy (1.3.1), reflow/responsive (1.4.10), and reading order (1.3.2). " +
|
|
2062
|
+
"Design system checks: hardcoded colors, missing text styles, default names, detached components. " +
|
|
2063
|
+
"Layout checks: missing auto-layout, empty containers. " +
|
|
2064
|
+
"Returns categorized findings with severity levels (critical/warning/info). " +
|
|
2061
2065
|
"Use natural language like 'check my design for accessibility issues' or 'lint this page'. " +
|
|
2062
2066
|
"Requires Desktop Bridge plugin.", {
|
|
2063
2067
|
nodeId: z.string().optional().describe("Node ID to lint (defaults to current page)"),
|
|
2064
|
-
rules: z.array(z.string()).optional().describe("Rule filter: ['all'] (default), ['wcag'], ['design-system'], ['layout'], or specific rule IDs like ['wcag-contrast', '
|
|
2068
|
+
rules: z.array(z.string()).optional().describe("Rule filter: ['all'] (default), ['wcag'] (13 WCAG rules), ['design-system'], ['layout'], or specific rule IDs like ['wcag-contrast', 'wcag-focus-indicator', 'wcag-image-alt']"),
|
|
2065
2069
|
maxDepth: z.number().optional().describe("Maximum tree depth to traverse (default: 10)"),
|
|
2066
2070
|
maxFindings: z.number().optional().describe("Maximum findings before stopping (default: 100)"),
|
|
2067
2071
|
}, async ({ nodeId, rules, maxDepth, maxFindings }) => {
|
|
@@ -2096,4 +2100,45 @@ return {
|
|
|
2096
2100
|
};
|
|
2097
2101
|
}
|
|
2098
2102
|
});
|
|
2103
|
+
// Tool: Audit Component Accessibility
|
|
2104
|
+
server.tool("figma_audit_component_accessibility", "Deep accessibility audit for a specific component or component set. Produces a scorecard covering: " +
|
|
2105
|
+
"state coverage (default/hover/focus/disabled/error/active/loading), focus indicator quality and contrast, " +
|
|
2106
|
+
"non-color differentiation (WCAG 1.4.1), target size consistency (WCAG 2.5.8), annotation completeness, " +
|
|
2107
|
+
"and color-blind simulation (protanopia/deuteranopia/tritanopia). Returns per-category scores (0-100) " +
|
|
2108
|
+
"and prioritized recommendations. Use after designing a component to validate accessibility before handoff. " +
|
|
2109
|
+
"Requires Desktop Bridge plugin.", {
|
|
2110
|
+
nodeId: z.string().optional().describe("Node ID of a COMPONENT_SET, COMPONENT, or INSTANCE to audit. Falls back to current selection if omitted."),
|
|
2111
|
+
targetSize: z.number().optional().describe("Minimum touch target size in px (default: 24 per WCAG 2.5.8). Use 44 for iOS or 48 for Android guidelines."),
|
|
2112
|
+
}, async ({ nodeId, targetSize }) => {
|
|
2113
|
+
try {
|
|
2114
|
+
const connector = await getDesktopConnector();
|
|
2115
|
+
const result = await connector.auditComponentAccessibility(nodeId, targetSize);
|
|
2116
|
+
if (!result.success) {
|
|
2117
|
+
throw new Error(result.error || "Audit failed");
|
|
2118
|
+
}
|
|
2119
|
+
return {
|
|
2120
|
+
content: [
|
|
2121
|
+
{
|
|
2122
|
+
type: "text",
|
|
2123
|
+
text: JSON.stringify(result.data || result, null, 2),
|
|
2124
|
+
},
|
|
2125
|
+
],
|
|
2126
|
+
};
|
|
2127
|
+
}
|
|
2128
|
+
catch (error) {
|
|
2129
|
+
logger.error({ error }, "Failed to audit component accessibility");
|
|
2130
|
+
return {
|
|
2131
|
+
content: [
|
|
2132
|
+
{
|
|
2133
|
+
type: "text",
|
|
2134
|
+
text: JSON.stringify({
|
|
2135
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2136
|
+
hint: "Make sure the Desktop Bridge plugin is running. Provide a COMPONENT_SET nodeId or select one in Figma.",
|
|
2137
|
+
}),
|
|
2138
|
+
},
|
|
2139
|
+
],
|
|
2140
|
+
isError: true,
|
|
2141
|
+
};
|
|
2142
|
+
}
|
|
2143
|
+
});
|
|
2099
2144
|
}
|
package/dist/cloudflare/index.js
CHANGED
|
@@ -23,6 +23,7 @@ import { registerCommentTools } from "./core/comment-tools.js";
|
|
|
23
23
|
import { registerAnnotationTools } from "./core/annotation-tools.js";
|
|
24
24
|
import { registerDeepComponentTools } from "./core/deep-component-tools.js";
|
|
25
25
|
import { registerDesignSystemTools } from "./core/design-system-tools.js";
|
|
26
|
+
import { registerAccessibilityTools } from "./core/accessibility-tools.js";
|
|
26
27
|
import { generatePairingCode } from "./core/cloud-websocket-relay.js";
|
|
27
28
|
import { CloudWebSocketConnector } from "./core/cloud-websocket-connector.js";
|
|
28
29
|
import { registerWriteTools } from "./core/write-tools.js";
|
|
@@ -68,7 +69,7 @@ export class FigmaConsoleMCPv3 extends McpAgent {
|
|
|
68
69
|
super(...arguments);
|
|
69
70
|
this.server = new McpServer({
|
|
70
71
|
name: "Figma Console MCP",
|
|
71
|
-
version: "1.
|
|
72
|
+
version: "1.22.0",
|
|
72
73
|
});
|
|
73
74
|
this.browserManager = null;
|
|
74
75
|
this.consoleMonitor = null;
|
|
@@ -795,6 +796,14 @@ export class FigmaConsoleMCPv3 extends McpAgent {
|
|
|
795
796
|
// Register Design System Kit tool
|
|
796
797
|
registerDesignSystemTools(this.server, async () => await this.getFigmaAPI(), () => this.browserManager?.getCurrentUrl() || null, undefined, // variablesCache
|
|
797
798
|
{ isRemoteMode: true });
|
|
799
|
+
// Register code-side accessibility scanning (axe-core + JSDOM)
|
|
800
|
+
// Note: May not work in Cloudflare Workers due to JSDOM dependency
|
|
801
|
+
try {
|
|
802
|
+
registerAccessibilityTools(this.server);
|
|
803
|
+
}
|
|
804
|
+
catch (e) {
|
|
805
|
+
// Silently skip if axe-core/jsdom not available in Workers environment
|
|
806
|
+
}
|
|
798
807
|
// Note: MCP Apps (Token Browser, Dashboard) are registered in local.ts only
|
|
799
808
|
// They require Node.js file system APIs that don't work in Cloudflare Workers
|
|
800
809
|
}
|
|
@@ -1046,7 +1055,7 @@ export default {
|
|
|
1046
1055
|
});
|
|
1047
1056
|
const statelessServer = new McpServer({
|
|
1048
1057
|
name: "Figma Console MCP",
|
|
1049
|
-
version: "1.
|
|
1058
|
+
version: "1.22.0",
|
|
1050
1059
|
});
|
|
1051
1060
|
// ================================================================
|
|
1052
1061
|
// Cloud Write Relay — Pairing Tool (stateless /mcp path)
|
|
@@ -1510,9 +1519,7 @@ export default {
|
|
|
1510
1519
|
const expiresIn = tokenData.expires_in;
|
|
1511
1520
|
logger.info({
|
|
1512
1521
|
sessionId,
|
|
1513
|
-
|
|
1514
|
-
accessTokenPreview: accessToken ? accessToken.substring(0, 10) + "..." : null,
|
|
1515
|
-
hasRefreshToken: !!refreshToken,
|
|
1522
|
+
hasTokens: !!accessToken && !!refreshToken,
|
|
1516
1523
|
expiresIn
|
|
1517
1524
|
}, "Token exchange successful");
|
|
1518
1525
|
// IMPORTANT: Use KV storage for tokens since Durable Object storage is instance-specific
|
|
@@ -1683,7 +1690,7 @@ export default {
|
|
|
1683
1690
|
return new Response(JSON.stringify({
|
|
1684
1691
|
status: "healthy",
|
|
1685
1692
|
service: "Figma Console MCP",
|
|
1686
|
-
version: "1.
|
|
1693
|
+
version: "1.22.0",
|
|
1687
1694
|
endpoints: {
|
|
1688
1695
|
mcp: ["/sse", "/mcp"],
|
|
1689
1696
|
oauth_mcp_spec: ["/.well-known/oauth-authorization-server", "/authorize", "/token", "/oauth/register"],
|
|
@@ -1729,13 +1736,13 @@ export default {
|
|
|
1729
1736
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1730
1737
|
<title>Figma Console MCP - The Most Comprehensive MCP Server for Figma</title>
|
|
1731
1738
|
<link rel="icon" type="image/svg+xml" href="https://docs.figma-console-mcp.southleft.com/favicon.svg">
|
|
1732
|
-
<meta name="description" content="Turn your Figma design system into a living API.
|
|
1739
|
+
<meta name="description" content="Turn your Figma design system into a living API. 94+ tools give AI assistants deep access to design tokens, component specs, variables, and programmatic design creation.">
|
|
1733
1740
|
|
|
1734
1741
|
<!-- Open Graph -->
|
|
1735
1742
|
<meta property="og:type" content="website">
|
|
1736
1743
|
<meta property="og:url" content="https://figma-console-mcp.southleft.com">
|
|
1737
1744
|
<meta property="og:title" content="Figma Console MCP - Turn Your Design System Into a Living API">
|
|
1738
|
-
<meta property="og:description" content="The most comprehensive MCP server for Figma.
|
|
1745
|
+
<meta property="og:description" content="The most comprehensive MCP server for Figma. 94+ tools give AI assistants deep access to design tokens, components, variables, and programmatic design creation.">
|
|
1739
1746
|
<meta property="og:image" content="https://docs.figma-console-mcp.southleft.com/images/og-image.jpg">
|
|
1740
1747
|
<meta property="og:image:width" content="1200">
|
|
1741
1748
|
<meta property="og:image:height" content="630">
|
|
@@ -1743,7 +1750,7 @@ export default {
|
|
|
1743
1750
|
<!-- Twitter -->
|
|
1744
1751
|
<meta name="twitter:card" content="summary_large_image">
|
|
1745
1752
|
<meta name="twitter:title" content="Figma Console MCP - Turn Your Design System Into a Living API">
|
|
1746
|
-
<meta name="twitter:description" content="The most comprehensive MCP server for Figma.
|
|
1753
|
+
<meta name="twitter:description" content="The most comprehensive MCP server for Figma. 94+ tools give AI assistants deep access to design tokens, components, variables, and programmatic design creation.">
|
|
1747
1754
|
<meta name="twitter:image" content="https://docs.figma-console-mcp.southleft.com/images/og-image.jpg">
|
|
1748
1755
|
|
|
1749
1756
|
<meta name="theme-color" content="#0D9488">
|
|
@@ -2630,7 +2637,7 @@ export default {
|
|
|
2630
2637
|
<div class="grid-cell showcase-cell rule-left">
|
|
2631
2638
|
<div class="showcase-label">What AI Can Access</div>
|
|
2632
2639
|
<div class="showcase-stat">
|
|
2633
|
-
<span class="number">
|
|
2640
|
+
<span class="number">94+</span>
|
|
2634
2641
|
<span class="label">MCP tools for Figma</span>
|
|
2635
2642
|
</div>
|
|
2636
2643
|
<div class="capability-list">
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code-side accessibility scanning via axe-core + JSDOM.
|
|
3
|
+
*
|
|
4
|
+
* Delegates all rule logic to axe-core (Deque) — the MCP never owns
|
|
5
|
+
* a rule database. JSDOM provides a lightweight DOM for structural checks
|
|
6
|
+
* (~50 rules: ARIA, semantics, alt text, form labels, headings, landmarks).
|
|
7
|
+
*
|
|
8
|
+
* Visual rules (color contrast, focus-visible) are NOT available via JSDOM —
|
|
9
|
+
* those are handled by the design-side figma_lint_design tool.
|
|
10
|
+
*/
|
|
11
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
12
|
+
/**
|
|
13
|
+
* Extract a CodeSpec.accessibility object from HTML + axe-core results.
|
|
14
|
+
* This bridges Phase 3 (code scanning) → Phase 4 (parity comparison).
|
|
15
|
+
*
|
|
16
|
+
* Parses the HTML to extract semantic element, ARIA attributes, and states.
|
|
17
|
+
* Uses axe-core results to infer what the code supports.
|
|
18
|
+
*/
|
|
19
|
+
export declare function axeResultsToCodeSpec(html: string, axeResults: any): Record<string, any>;
|
|
20
|
+
export declare function registerAccessibilityTools(server: McpServer): void;
|
|
21
|
+
//# sourceMappingURL=accessibility-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accessibility-tools.d.ts","sourceRoot":"","sources":["../../src/core/accessibility-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA6FpE;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAoGvF;AA+DD,wBAAgB,0BAA0B,CACzC,MAAM,EAAE,SAAS,GACf,IAAI,CAyEN"}
|