@mp3wizard/figma-console-mcp 1.14.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/LICENSE +21 -0
- package/README.md +816 -0
- package/dist/apps/design-system-dashboard/scoring/accessibility.d.ts +14 -0
- package/dist/apps/design-system-dashboard/scoring/accessibility.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/accessibility.js +278 -0
- package/dist/apps/design-system-dashboard/scoring/accessibility.js.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/component-metadata.d.ts +29 -0
- package/dist/apps/design-system-dashboard/scoring/component-metadata.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/component-metadata.js +358 -0
- package/dist/apps/design-system-dashboard/scoring/component-metadata.js.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/consistency.d.ts +14 -0
- package/dist/apps/design-system-dashboard/scoring/consistency.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/consistency.js +342 -0
- package/dist/apps/design-system-dashboard/scoring/consistency.js.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/coverage.d.ts +14 -0
- package/dist/apps/design-system-dashboard/scoring/coverage.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/coverage.js +231 -0
- package/dist/apps/design-system-dashboard/scoring/coverage.js.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/engine.d.ts +27 -0
- package/dist/apps/design-system-dashboard/scoring/engine.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/engine.js +93 -0
- package/dist/apps/design-system-dashboard/scoring/engine.js.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/naming-semantics.d.ts +14 -0
- package/dist/apps/design-system-dashboard/scoring/naming-semantics.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/naming-semantics.js +309 -0
- package/dist/apps/design-system-dashboard/scoring/naming-semantics.js.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/token-architecture.d.ts +14 -0
- package/dist/apps/design-system-dashboard/scoring/token-architecture.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/token-architecture.js +350 -0
- package/dist/apps/design-system-dashboard/scoring/token-architecture.js.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/types.d.ts +89 -0
- package/dist/apps/design-system-dashboard/scoring/types.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/scoring/types.js +41 -0
- package/dist/apps/design-system-dashboard/scoring/types.js.map +1 -0
- package/dist/apps/design-system-dashboard/server.d.ts +24 -0
- package/dist/apps/design-system-dashboard/server.d.ts.map +1 -0
- package/dist/apps/design-system-dashboard/server.js +160 -0
- package/dist/apps/design-system-dashboard/server.js.map +1 -0
- package/dist/apps/token-browser/server.d.ts +26 -0
- package/dist/apps/token-browser/server.d.ts.map +1 -0
- package/dist/apps/token-browser/server.js +137 -0
- package/dist/apps/token-browser/server.js.map +1 -0
- package/dist/browser/base.d.ts +58 -0
- package/dist/browser/base.d.ts.map +1 -0
- package/dist/browser/base.js +6 -0
- package/dist/browser/base.js.map +1 -0
- package/dist/browser/local.d.ts +87 -0
- package/dist/browser/local.d.ts.map +1 -0
- package/dist/browser/local.js +318 -0
- package/dist/browser/local.js.map +1 -0
- package/dist/cloudflare/apps/design-system-dashboard/scoring/accessibility.js +277 -0
- package/dist/cloudflare/apps/design-system-dashboard/scoring/component-metadata.js +357 -0
- package/dist/cloudflare/apps/design-system-dashboard/scoring/consistency.js +341 -0
- package/dist/cloudflare/apps/design-system-dashboard/scoring/coverage.js +230 -0
- package/dist/cloudflare/apps/design-system-dashboard/scoring/engine.js +92 -0
- package/dist/cloudflare/apps/design-system-dashboard/scoring/naming-semantics.js +308 -0
- package/dist/cloudflare/apps/design-system-dashboard/scoring/token-architecture.js +349 -0
- package/dist/cloudflare/apps/design-system-dashboard/scoring/types.js +40 -0
- package/dist/cloudflare/apps/design-system-dashboard/server.js +159 -0
- package/dist/cloudflare/apps/token-browser/server.js +136 -0
- package/dist/cloudflare/browser/base.js +5 -0
- package/dist/cloudflare/browser/cloudflare.js +156 -0
- package/dist/cloudflare/browser-manager.js +157 -0
- package/dist/cloudflare/core/cloud-websocket-connector.js +267 -0
- package/dist/cloudflare/core/cloud-websocket-relay.js +199 -0
- package/dist/cloudflare/core/comment-tools.js +292 -0
- package/dist/cloudflare/core/config.js +161 -0
- package/dist/cloudflare/core/console-monitor.js +427 -0
- package/dist/cloudflare/core/design-code-tools.js +2504 -0
- package/dist/cloudflare/core/design-system-manifest.js +260 -0
- package/dist/cloudflare/core/design-system-tools.js +863 -0
- package/dist/cloudflare/core/enrichment/enrichment-service.js +272 -0
- package/dist/cloudflare/core/enrichment/index.js +7 -0
- package/dist/cloudflare/core/enrichment/relationship-mapper.js +351 -0
- package/dist/cloudflare/core/enrichment/style-resolver.js +326 -0
- package/dist/cloudflare/core/figma-api.js +409 -0
- package/dist/cloudflare/core/figma-connector.js +7 -0
- package/dist/cloudflare/core/figma-desktop-connector.js +1184 -0
- package/dist/cloudflare/core/figma-reconstruction-spec.js +402 -0
- package/dist/cloudflare/core/figma-style-extractor.js +311 -0
- package/dist/cloudflare/core/figma-tools.js +2947 -0
- package/dist/cloudflare/core/logger.js +53 -0
- package/dist/cloudflare/core/port-discovery.js +282 -0
- package/dist/cloudflare/core/snippet-injector.js +96 -0
- package/dist/cloudflare/core/types/design-code.js +4 -0
- package/dist/cloudflare/core/types/enriched.js +5 -0
- package/dist/cloudflare/core/types/index.js +4 -0
- package/dist/cloudflare/core/websocket-connector.js +256 -0
- package/dist/cloudflare/core/websocket-server.js +646 -0
- package/dist/cloudflare/core/write-tools.js +2091 -0
- package/dist/cloudflare/index.js +2899 -0
- package/dist/cloudflare/test-browser.js +88 -0
- package/dist/core/comment-tools.d.ts +11 -0
- package/dist/core/comment-tools.d.ts.map +1 -0
- package/dist/core/comment-tools.js +293 -0
- package/dist/core/comment-tools.js.map +1 -0
- package/dist/core/config.d.ts +17 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +162 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/console-monitor.d.ts +82 -0
- package/dist/core/console-monitor.d.ts.map +1 -0
- package/dist/core/console-monitor.js +428 -0
- package/dist/core/console-monitor.js.map +1 -0
- package/dist/core/design-code-tools.d.ts +127 -0
- package/dist/core/design-code-tools.d.ts.map +1 -0
- package/dist/core/design-code-tools.js +2505 -0
- package/dist/core/design-code-tools.js.map +1 -0
- package/dist/core/design-system-manifest.d.ts +272 -0
- package/dist/core/design-system-manifest.d.ts.map +1 -0
- package/dist/core/design-system-manifest.js +261 -0
- package/dist/core/design-system-manifest.js.map +1 -0
- package/dist/core/design-system-tools.d.ts +17 -0
- package/dist/core/design-system-tools.d.ts.map +1 -0
- package/dist/core/design-system-tools.js +864 -0
- package/dist/core/design-system-tools.js.map +1 -0
- package/dist/core/enrichment/enrichment-service.d.ts +52 -0
- package/dist/core/enrichment/enrichment-service.d.ts.map +1 -0
- package/dist/core/enrichment/enrichment-service.js +273 -0
- package/dist/core/enrichment/enrichment-service.js.map +1 -0
- package/dist/core/enrichment/index.d.ts +8 -0
- package/dist/core/enrichment/index.d.ts.map +1 -0
- package/dist/core/enrichment/index.js +8 -0
- package/dist/core/enrichment/index.js.map +1 -0
- package/dist/core/enrichment/relationship-mapper.d.ts +106 -0
- package/dist/core/enrichment/relationship-mapper.d.ts.map +1 -0
- package/dist/core/enrichment/relationship-mapper.js +352 -0
- package/dist/core/enrichment/relationship-mapper.js.map +1 -0
- package/dist/core/enrichment/style-resolver.d.ts +80 -0
- package/dist/core/enrichment/style-resolver.d.ts.map +1 -0
- package/dist/core/enrichment/style-resolver.js +327 -0
- package/dist/core/enrichment/style-resolver.js.map +1 -0
- package/dist/core/figma-api.d.ts +201 -0
- package/dist/core/figma-api.d.ts.map +1 -0
- package/dist/core/figma-api.js +410 -0
- package/dist/core/figma-api.js.map +1 -0
- package/dist/core/figma-connector.d.ts +48 -0
- package/dist/core/figma-connector.d.ts.map +1 -0
- package/dist/core/figma-connector.js +8 -0
- package/dist/core/figma-connector.js.map +1 -0
- package/dist/core/figma-desktop-connector.d.ts +265 -0
- package/dist/core/figma-desktop-connector.d.ts.map +1 -0
- package/dist/core/figma-desktop-connector.js +1184 -0
- package/dist/core/figma-desktop-connector.js.map +1 -0
- package/dist/core/figma-reconstruction-spec.d.ts +166 -0
- package/dist/core/figma-reconstruction-spec.d.ts.map +1 -0
- package/dist/core/figma-reconstruction-spec.js +403 -0
- package/dist/core/figma-reconstruction-spec.js.map +1 -0
- package/dist/core/figma-style-extractor.d.ts +76 -0
- package/dist/core/figma-style-extractor.d.ts.map +1 -0
- package/dist/core/figma-style-extractor.js +312 -0
- package/dist/core/figma-style-extractor.js.map +1 -0
- package/dist/core/figma-tools.d.ts +23 -0
- package/dist/core/figma-tools.d.ts.map +1 -0
- package/dist/core/figma-tools.js +2948 -0
- package/dist/core/figma-tools.js.map +1 -0
- package/dist/core/logger.d.ts +22 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +54 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/port-discovery.d.ts +110 -0
- package/dist/core/port-discovery.d.ts.map +1 -0
- package/dist/core/port-discovery.js +283 -0
- package/dist/core/port-discovery.js.map +1 -0
- package/dist/core/snippet-injector.d.ts +24 -0
- package/dist/core/snippet-injector.d.ts.map +1 -0
- package/dist/core/snippet-injector.js +97 -0
- package/dist/core/snippet-injector.js.map +1 -0
- package/dist/core/types/design-code.d.ts +262 -0
- package/dist/core/types/design-code.d.ts.map +1 -0
- package/dist/core/types/design-code.js +5 -0
- package/dist/core/types/design-code.js.map +1 -0
- package/dist/core/types/enriched.d.ts +213 -0
- package/dist/core/types/enriched.d.ts.map +1 -0
- package/dist/core/types/enriched.js +6 -0
- package/dist/core/types/enriched.js.map +1 -0
- package/dist/core/types/index.d.ts +112 -0
- package/dist/core/types/index.d.ts.map +1 -0
- package/dist/core/types/index.js +5 -0
- package/dist/core/types/index.js.map +1 -0
- package/dist/core/websocket-connector.d.ts +55 -0
- package/dist/core/websocket-connector.d.ts.map +1 -0
- package/dist/core/websocket-connector.js +257 -0
- package/dist/core/websocket-connector.js.map +1 -0
- package/dist/core/websocket-server.d.ts +191 -0
- package/dist/core/websocket-server.d.ts.map +1 -0
- package/dist/core/websocket-server.js +647 -0
- package/dist/core/websocket-server.js.map +1 -0
- package/dist/core/write-tools.d.ts +7 -0
- package/dist/core/write-tools.d.ts.map +1 -0
- package/dist/core/write-tools.js +2092 -0
- package/dist/core/write-tools.js.map +1 -0
- package/dist/local.d.ts +84 -0
- package/dist/local.d.ts.map +1 -0
- package/dist/local.js +5039 -0
- package/dist/local.js.map +1 -0
- package/figma-desktop-bridge/README.md +313 -0
- package/figma-desktop-bridge/code.js +2818 -0
- package/figma-desktop-bridge/manifest.json +67 -0
- package/figma-desktop-bridge/ui.html +1236 -0
- package/package.json +87 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test script to verify Browser Rendering API access
|
|
3
|
+
* Run with: npx wrangler dev and visit /test-browser
|
|
4
|
+
*/
|
|
5
|
+
import puppeteer from '@cloudflare/puppeteer';
|
|
6
|
+
export async function testBrowserRendering(env) {
|
|
7
|
+
const results = {
|
|
8
|
+
timestamp: new Date().toISOString(),
|
|
9
|
+
tests: [],
|
|
10
|
+
};
|
|
11
|
+
// Test 1: Check BROWSER binding exists
|
|
12
|
+
results.tests.push({
|
|
13
|
+
name: 'BROWSER binding exists',
|
|
14
|
+
passed: !!env.BROWSER,
|
|
15
|
+
details: env.BROWSER ? 'BROWSER binding found' : 'BROWSER binding missing',
|
|
16
|
+
});
|
|
17
|
+
if (!env.BROWSER) {
|
|
18
|
+
return {
|
|
19
|
+
...results,
|
|
20
|
+
overall: 'FAILED',
|
|
21
|
+
message: 'BROWSER binding not found. Check wrangler.jsonc configuration.',
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
// Test 2: Try to launch browser
|
|
25
|
+
try {
|
|
26
|
+
const browser = await puppeteer.launch(env.BROWSER, { keep_alive: 60000 });
|
|
27
|
+
results.tests.push({
|
|
28
|
+
name: 'Browser launch',
|
|
29
|
+
passed: true,
|
|
30
|
+
details: 'Successfully launched browser instance',
|
|
31
|
+
});
|
|
32
|
+
// Test 3: Try to create page
|
|
33
|
+
try {
|
|
34
|
+
const page = await browser.newPage();
|
|
35
|
+
results.tests.push({
|
|
36
|
+
name: 'Create browser page',
|
|
37
|
+
passed: true,
|
|
38
|
+
details: 'Successfully created new page',
|
|
39
|
+
});
|
|
40
|
+
// Test 4: Try to navigate
|
|
41
|
+
try {
|
|
42
|
+
await page.goto('https://example.com', { waitUntil: 'networkidle0' });
|
|
43
|
+
results.tests.push({
|
|
44
|
+
name: 'Navigate to URL',
|
|
45
|
+
passed: true,
|
|
46
|
+
details: 'Successfully navigated to example.com',
|
|
47
|
+
});
|
|
48
|
+
// Test 5: Get page title
|
|
49
|
+
const title = await page.title();
|
|
50
|
+
results.tests.push({
|
|
51
|
+
name: 'Read page content',
|
|
52
|
+
passed: true,
|
|
53
|
+
details: `Page title: "${title}"`,
|
|
54
|
+
});
|
|
55
|
+
await page.close();
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
results.tests.push({
|
|
59
|
+
name: 'Navigate to URL',
|
|
60
|
+
passed: false,
|
|
61
|
+
error: error instanceof Error ? error.message : String(error),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
results.tests.push({
|
|
67
|
+
name: 'Create browser page',
|
|
68
|
+
passed: false,
|
|
69
|
+
error: error instanceof Error ? error.message : String(error),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
await browser.close();
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
results.tests.push({
|
|
76
|
+
name: 'Browser launch',
|
|
77
|
+
passed: false,
|
|
78
|
+
error: error instanceof Error ? error.message : String(error),
|
|
79
|
+
hint: 'Browser Rendering API may not be enabled on your account',
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const allPassed = results.tests.every((test) => test.passed);
|
|
83
|
+
return {
|
|
84
|
+
...results,
|
|
85
|
+
overall: allPassed ? 'PASSED' : 'FAILED',
|
|
86
|
+
summary: `${results.tests.filter((t) => t.passed).length}/${results.tests.length} tests passed`,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Figma Comments MCP Tools
|
|
3
|
+
* Tools for getting, posting, and deleting comments on Figma files via REST API.
|
|
4
|
+
* Works in both local and Cloudflare Workers modes — no Plugin API dependency.
|
|
5
|
+
*/
|
|
6
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
import type { FigmaAPI } from "./figma-api.js";
|
|
8
|
+
export declare function registerCommentTools(server: McpServer, getFigmaAPI: () => Promise<FigmaAPI>, getCurrentUrl: () => string | null, options?: {
|
|
9
|
+
isRemoteMode?: boolean;
|
|
10
|
+
}): void;
|
|
11
|
+
//# sourceMappingURL=comment-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment-tools.d.ts","sourceRoot":"","sources":["../../src/core/comment-tools.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAU/C,wBAAgB,oBAAoB,CACnC,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,EACpC,aAAa,EAAE,MAAM,MAAM,GAAG,IAAI,EAClC,OAAO,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,GAClC,IAAI,CAgUN"}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Figma Comments MCP Tools
|
|
3
|
+
* Tools for getting, posting, and deleting comments on Figma files via REST API.
|
|
4
|
+
* Works in both local and Cloudflare Workers modes — no Plugin API dependency.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { extractFileKey } from "./figma-api.js";
|
|
8
|
+
import { createChildLogger } from "./logger.js";
|
|
9
|
+
const logger = createChildLogger({ component: "comment-tools" });
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Tool Registration
|
|
12
|
+
// ============================================================================
|
|
13
|
+
export function registerCommentTools(server, getFigmaAPI, getCurrentUrl, options) {
|
|
14
|
+
// -----------------------------------------------------------------------
|
|
15
|
+
// Tool: figma_get_comments
|
|
16
|
+
// -----------------------------------------------------------------------
|
|
17
|
+
server.tool("figma_get_comments", "Get comments on a Figma file. Returns comment threads with author, message, timestamps, and pinned node locations. Use include_resolved to also see resolved comments.", {
|
|
18
|
+
fileUrl: z
|
|
19
|
+
.string()
|
|
20
|
+
.url()
|
|
21
|
+
.optional()
|
|
22
|
+
.describe("Figma file URL. Uses current URL if omitted."),
|
|
23
|
+
as_md: z
|
|
24
|
+
.boolean()
|
|
25
|
+
.optional()
|
|
26
|
+
.default(false)
|
|
27
|
+
.describe("Return comment message bodies as markdown. Default: false"),
|
|
28
|
+
include_resolved: z
|
|
29
|
+
.boolean()
|
|
30
|
+
.optional()
|
|
31
|
+
.default(false)
|
|
32
|
+
.describe("Include resolved (completed) comment threads. Default: false (only active comments)"),
|
|
33
|
+
}, async ({ fileUrl, as_md = false, include_resolved = false }) => {
|
|
34
|
+
try {
|
|
35
|
+
const url = fileUrl || getCurrentUrl();
|
|
36
|
+
if (!url) {
|
|
37
|
+
return {
|
|
38
|
+
content: [
|
|
39
|
+
{
|
|
40
|
+
type: "text",
|
|
41
|
+
text: JSON.stringify({
|
|
42
|
+
error: "no_file_url",
|
|
43
|
+
message: "No Figma file URL available. Pass the fileUrl parameter or ensure the Desktop Bridge plugin is open in Figma.",
|
|
44
|
+
}),
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
isError: true,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const fileKey = extractFileKey(url);
|
|
51
|
+
if (!fileKey) {
|
|
52
|
+
return {
|
|
53
|
+
content: [
|
|
54
|
+
{
|
|
55
|
+
type: "text",
|
|
56
|
+
text: JSON.stringify({
|
|
57
|
+
error: "invalid_url",
|
|
58
|
+
message: `Invalid Figma URL: ${url}`,
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
isError: true,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
logger.info({ fileKey, as_md, include_resolved }, "Fetching comments");
|
|
66
|
+
const api = await getFigmaAPI();
|
|
67
|
+
const response = await api.getComments(fileKey, { as_md });
|
|
68
|
+
const allComments = response.comments || [];
|
|
69
|
+
// Filter out resolved comments unless explicitly requested
|
|
70
|
+
const comments = include_resolved
|
|
71
|
+
? allComments
|
|
72
|
+
: allComments.filter((c) => !c.resolved_at);
|
|
73
|
+
const result = {
|
|
74
|
+
comments,
|
|
75
|
+
summary: {
|
|
76
|
+
total: allComments.length,
|
|
77
|
+
active: allComments.filter((c) => !c.resolved_at).length,
|
|
78
|
+
resolved: allComments.filter((c) => c.resolved_at).length,
|
|
79
|
+
returned: comments.length,
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
content: [
|
|
84
|
+
{
|
|
85
|
+
type: "text",
|
|
86
|
+
text: JSON.stringify(result),
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
93
|
+
logger.error({ error }, "Failed to get comments");
|
|
94
|
+
return {
|
|
95
|
+
content: [
|
|
96
|
+
{
|
|
97
|
+
type: "text",
|
|
98
|
+
text: JSON.stringify({
|
|
99
|
+
error: "get_comments_failed",
|
|
100
|
+
message: `Cannot get comments. ${message}`,
|
|
101
|
+
}),
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
isError: true,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
// -----------------------------------------------------------------------
|
|
109
|
+
// Tool: figma_post_comment
|
|
110
|
+
// -----------------------------------------------------------------------
|
|
111
|
+
server.tool("figma_post_comment", "Post a comment on a Figma file, optionally pinned to a specific design node. Use after figma_check_design_parity to notify designers of drift when code is the canonical source. Supports replies to existing comment threads. Limitation: @mentions are a Figma UI-only feature — including '@name' in the message renders as plain text, not a clickable mention tag, and does not trigger Figma notifications.", {
|
|
112
|
+
fileUrl: z
|
|
113
|
+
.string()
|
|
114
|
+
.url()
|
|
115
|
+
.optional()
|
|
116
|
+
.describe("Figma file URL. Uses current URL if omitted."),
|
|
117
|
+
message: z
|
|
118
|
+
.string()
|
|
119
|
+
.describe("The comment message text. Supports basic formatting."),
|
|
120
|
+
node_id: z
|
|
121
|
+
.string()
|
|
122
|
+
.optional()
|
|
123
|
+
.describe("Node ID to pin the comment to (e.g., '695:313'). Comment appears on that element in Figma."),
|
|
124
|
+
x: z
|
|
125
|
+
.number()
|
|
126
|
+
.optional()
|
|
127
|
+
.describe("X coordinate for comment placement (absolute canvas position). Used with node_id."),
|
|
128
|
+
y: z
|
|
129
|
+
.number()
|
|
130
|
+
.optional()
|
|
131
|
+
.describe("Y coordinate for comment placement (absolute canvas position). Used with node_id."),
|
|
132
|
+
reply_to_comment_id: z
|
|
133
|
+
.string()
|
|
134
|
+
.optional()
|
|
135
|
+
.describe("ID of an existing comment to reply to. Creates a threaded reply instead of a new top-level comment."),
|
|
136
|
+
}, async ({ fileUrl, message, node_id, x, y, reply_to_comment_id }) => {
|
|
137
|
+
try {
|
|
138
|
+
const url = fileUrl || getCurrentUrl();
|
|
139
|
+
if (!url) {
|
|
140
|
+
return {
|
|
141
|
+
content: [
|
|
142
|
+
{
|
|
143
|
+
type: "text",
|
|
144
|
+
text: JSON.stringify({
|
|
145
|
+
error: "no_file_url",
|
|
146
|
+
message: "No Figma file URL available. Pass the fileUrl parameter or ensure the Desktop Bridge plugin is open in Figma.",
|
|
147
|
+
}),
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
isError: true,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const fileKey = extractFileKey(url);
|
|
154
|
+
if (!fileKey) {
|
|
155
|
+
return {
|
|
156
|
+
content: [
|
|
157
|
+
{
|
|
158
|
+
type: "text",
|
|
159
|
+
text: JSON.stringify({
|
|
160
|
+
error: "invalid_url",
|
|
161
|
+
message: `Invalid Figma URL: ${url}`,
|
|
162
|
+
}),
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
isError: true,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
logger.info({ fileKey, node_id, reply_to_comment_id }, "Posting comment");
|
|
169
|
+
const api = await getFigmaAPI();
|
|
170
|
+
// Build client_meta for pinning to a node/position
|
|
171
|
+
// Figma API requires node_offset when node_id is present — default to (0,0) if not specified
|
|
172
|
+
let clientMeta;
|
|
173
|
+
if (node_id) {
|
|
174
|
+
clientMeta = {
|
|
175
|
+
node_id,
|
|
176
|
+
node_offset: { x: x ?? 0, y: y ?? 0 },
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
const result = await api.postComment(fileKey, message, clientMeta, reply_to_comment_id);
|
|
180
|
+
return {
|
|
181
|
+
content: [
|
|
182
|
+
{
|
|
183
|
+
type: "text",
|
|
184
|
+
text: JSON.stringify({
|
|
185
|
+
success: true,
|
|
186
|
+
comment: {
|
|
187
|
+
id: result.id,
|
|
188
|
+
message: result.message,
|
|
189
|
+
created_at: result.created_at,
|
|
190
|
+
user: result.user,
|
|
191
|
+
client_meta: result.client_meta,
|
|
192
|
+
order_id: result.order_id,
|
|
193
|
+
},
|
|
194
|
+
}),
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
const message_text = error instanceof Error ? error.message : String(error);
|
|
201
|
+
logger.error({ error }, "Failed to post comment");
|
|
202
|
+
return {
|
|
203
|
+
content: [
|
|
204
|
+
{
|
|
205
|
+
type: "text",
|
|
206
|
+
text: JSON.stringify({
|
|
207
|
+
error: "post_comment_failed",
|
|
208
|
+
message: `Cannot post comment. ${message_text}`,
|
|
209
|
+
}),
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
isError: true,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
// -----------------------------------------------------------------------
|
|
217
|
+
// Tool: figma_delete_comment
|
|
218
|
+
// -----------------------------------------------------------------------
|
|
219
|
+
server.tool("figma_delete_comment", "Delete a comment from a Figma file by its comment ID. Use figma_get_comments to find comment IDs first.", {
|
|
220
|
+
fileUrl: z
|
|
221
|
+
.string()
|
|
222
|
+
.url()
|
|
223
|
+
.optional()
|
|
224
|
+
.describe("Figma file URL. Uses current URL if omitted."),
|
|
225
|
+
comment_id: z
|
|
226
|
+
.string()
|
|
227
|
+
.describe("The ID of the comment to delete. Get IDs from figma_get_comments."),
|
|
228
|
+
}, async ({ fileUrl, comment_id }) => {
|
|
229
|
+
try {
|
|
230
|
+
const url = fileUrl || getCurrentUrl();
|
|
231
|
+
if (!url) {
|
|
232
|
+
return {
|
|
233
|
+
content: [
|
|
234
|
+
{
|
|
235
|
+
type: "text",
|
|
236
|
+
text: JSON.stringify({
|
|
237
|
+
error: "no_file_url",
|
|
238
|
+
message: "No Figma file URL available. Pass the fileUrl parameter or ensure the Desktop Bridge plugin is open in Figma.",
|
|
239
|
+
}),
|
|
240
|
+
},
|
|
241
|
+
],
|
|
242
|
+
isError: true,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
const fileKey = extractFileKey(url);
|
|
246
|
+
if (!fileKey) {
|
|
247
|
+
return {
|
|
248
|
+
content: [
|
|
249
|
+
{
|
|
250
|
+
type: "text",
|
|
251
|
+
text: JSON.stringify({
|
|
252
|
+
error: "invalid_url",
|
|
253
|
+
message: `Invalid Figma URL: ${url}`,
|
|
254
|
+
}),
|
|
255
|
+
},
|
|
256
|
+
],
|
|
257
|
+
isError: true,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
logger.info({ fileKey, comment_id }, "Deleting comment");
|
|
261
|
+
const api = await getFigmaAPI();
|
|
262
|
+
await api.deleteComment(fileKey, comment_id);
|
|
263
|
+
return {
|
|
264
|
+
content: [
|
|
265
|
+
{
|
|
266
|
+
type: "text",
|
|
267
|
+
text: JSON.stringify({
|
|
268
|
+
success: true,
|
|
269
|
+
deleted_comment_id: comment_id,
|
|
270
|
+
}),
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
277
|
+
logger.error({ error }, "Failed to delete comment");
|
|
278
|
+
return {
|
|
279
|
+
content: [
|
|
280
|
+
{
|
|
281
|
+
type: "text",
|
|
282
|
+
text: JSON.stringify({
|
|
283
|
+
error: "delete_comment_failed",
|
|
284
|
+
message: `Cannot delete comment. ${message}`,
|
|
285
|
+
}),
|
|
286
|
+
},
|
|
287
|
+
],
|
|
288
|
+
isError: true,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=comment-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment-tools.js","sourceRoot":"","sources":["../../src/core/comment-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration management for Figma Console MCP server
|
|
3
|
+
*/
|
|
4
|
+
import type { ServerConfig } from './types/index.js';
|
|
5
|
+
/**
|
|
6
|
+
* Load configuration from file or use defaults
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadConfig(): ServerConfig;
|
|
9
|
+
/**
|
|
10
|
+
* Validate configuration
|
|
11
|
+
*/
|
|
12
|
+
export declare function validateConfig(config: ServerConfig): void;
|
|
13
|
+
/**
|
|
14
|
+
* Get configuration with validation
|
|
15
|
+
*/
|
|
16
|
+
export declare function getConfig(): ServerConfig;
|
|
17
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAqErD;;GAEG;AACH,wBAAgB,UAAU,IAAI,YAAY,CAqBzC;AA+BD;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAkCzD;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,YAAY,CAIxC"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration management for Figma Console MCP server
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, existsSync } from 'fs';
|
|
5
|
+
import { homedir } from 'os';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
/**
|
|
8
|
+
* Auto-detect server mode based on environment
|
|
9
|
+
*/
|
|
10
|
+
function detectMode() {
|
|
11
|
+
// If running in Workers environment, return cloudflare
|
|
12
|
+
if (typeof globalThis !== 'undefined' && 'caches' in globalThis) {
|
|
13
|
+
return 'cloudflare';
|
|
14
|
+
}
|
|
15
|
+
// Explicit env var override
|
|
16
|
+
const modeEnv = process.env.FIGMA_MCP_MODE?.toLowerCase();
|
|
17
|
+
if (modeEnv === 'local' || modeEnv === 'cloudflare') {
|
|
18
|
+
return modeEnv;
|
|
19
|
+
}
|
|
20
|
+
// Default to local for Node.js environments
|
|
21
|
+
return 'local';
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Default configuration values
|
|
25
|
+
*/
|
|
26
|
+
const DEFAULT_CONFIG = {
|
|
27
|
+
mode: detectMode(),
|
|
28
|
+
browser: {
|
|
29
|
+
headless: false,
|
|
30
|
+
args: [
|
|
31
|
+
'--disable-blink-features=AutomationControlled',
|
|
32
|
+
'--disable-dev-shm-usage',
|
|
33
|
+
// '--no-sandbox' removed from defaults; enable via config file if required by your environment
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
console: {
|
|
37
|
+
bufferSize: 1000,
|
|
38
|
+
filterLevels: ['log', 'info', 'warn', 'error', 'debug'],
|
|
39
|
+
truncation: {
|
|
40
|
+
maxStringLength: 500,
|
|
41
|
+
maxArrayLength: 10,
|
|
42
|
+
maxObjectDepth: 3,
|
|
43
|
+
removeDuplicates: true,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
screenshots: {
|
|
47
|
+
defaultFormat: 'png',
|
|
48
|
+
quality: 90,
|
|
49
|
+
storePath: join(process.env.TMPDIR || '/tmp', 'figma-console-mcp', 'screenshots'),
|
|
50
|
+
},
|
|
51
|
+
local: {
|
|
52
|
+
debugHost: process.env.FIGMA_DEBUG_HOST || 'localhost',
|
|
53
|
+
debugPort: parseInt(process.env.FIGMA_DEBUG_PORT || '9222', 10),
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Possible config file locations (checked in order)
|
|
58
|
+
*/
|
|
59
|
+
const CONFIG_PATHS = [
|
|
60
|
+
// Environment variable override
|
|
61
|
+
process.env.FIGMA_CONSOLE_CONFIG,
|
|
62
|
+
// Project-local config
|
|
63
|
+
join(process.cwd(), '.figma-console-mcp.json'),
|
|
64
|
+
join(process.cwd(), 'figma-console-mcp.json'),
|
|
65
|
+
// User home config
|
|
66
|
+
join(homedir(), '.config', 'figma-console-mcp', 'config.json'),
|
|
67
|
+
join(homedir(), '.figma-console-mcp.json'),
|
|
68
|
+
].filter((path) => path !== undefined);
|
|
69
|
+
/**
|
|
70
|
+
* Load configuration from file or use defaults
|
|
71
|
+
*/
|
|
72
|
+
export function loadConfig() {
|
|
73
|
+
// Try to load from config file
|
|
74
|
+
for (const configPath of CONFIG_PATHS) {
|
|
75
|
+
if (existsSync(configPath)) {
|
|
76
|
+
try {
|
|
77
|
+
const fileContent = readFileSync(configPath, 'utf-8');
|
|
78
|
+
const userConfig = JSON.parse(fileContent);
|
|
79
|
+
// Deep merge with defaults
|
|
80
|
+
const config = mergeConfig(DEFAULT_CONFIG, userConfig);
|
|
81
|
+
return config;
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
console.error(`Failed to load config from ${configPath}:`, error);
|
|
85
|
+
// Continue to next config path
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// No config file found, use defaults
|
|
90
|
+
return DEFAULT_CONFIG;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Deep merge two configuration objects
|
|
94
|
+
*/
|
|
95
|
+
function mergeConfig(defaults, overrides) {
|
|
96
|
+
return {
|
|
97
|
+
mode: overrides.mode || defaults.mode,
|
|
98
|
+
browser: {
|
|
99
|
+
...defaults.browser,
|
|
100
|
+
...(overrides.browser || {}),
|
|
101
|
+
},
|
|
102
|
+
console: {
|
|
103
|
+
...defaults.console,
|
|
104
|
+
...(overrides.console || {}),
|
|
105
|
+
truncation: {
|
|
106
|
+
...defaults.console.truncation,
|
|
107
|
+
...(overrides.console?.truncation || {}),
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
screenshots: {
|
|
111
|
+
...defaults.screenshots,
|
|
112
|
+
...(overrides.screenshots || {}),
|
|
113
|
+
},
|
|
114
|
+
local: {
|
|
115
|
+
...defaults.local,
|
|
116
|
+
...(overrides.local || {}),
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Validate configuration
|
|
122
|
+
*/
|
|
123
|
+
export function validateConfig(config) {
|
|
124
|
+
// Validate browser config
|
|
125
|
+
if (!Array.isArray(config.browser.args)) {
|
|
126
|
+
throw new Error('browser.args must be an array');
|
|
127
|
+
}
|
|
128
|
+
// Validate console config
|
|
129
|
+
if (config.console.bufferSize <= 0) {
|
|
130
|
+
throw new Error('console.bufferSize must be positive');
|
|
131
|
+
}
|
|
132
|
+
if (!Array.isArray(config.console.filterLevels)) {
|
|
133
|
+
throw new Error('console.filterLevels must be an array');
|
|
134
|
+
}
|
|
135
|
+
// Validate truncation config
|
|
136
|
+
const { truncation } = config.console;
|
|
137
|
+
if (truncation.maxStringLength <= 0) {
|
|
138
|
+
throw new Error('console.truncation.maxStringLength must be positive');
|
|
139
|
+
}
|
|
140
|
+
if (truncation.maxArrayLength <= 0) {
|
|
141
|
+
throw new Error('console.truncation.maxArrayLength must be positive');
|
|
142
|
+
}
|
|
143
|
+
if (truncation.maxObjectDepth <= 0) {
|
|
144
|
+
throw new Error('console.truncation.maxObjectDepth must be positive');
|
|
145
|
+
}
|
|
146
|
+
// Validate screenshot config
|
|
147
|
+
if (!['png', 'jpeg'].includes(config.screenshots.defaultFormat)) {
|
|
148
|
+
throw new Error('screenshots.defaultFormat must be "png" or "jpeg"');
|
|
149
|
+
}
|
|
150
|
+
if (config.screenshots.quality < 0 || config.screenshots.quality > 100) {
|
|
151
|
+
throw new Error('screenshots.quality must be between 0 and 100');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get configuration with validation
|
|
156
|
+
*/
|
|
157
|
+
export function getConfig() {
|
|
158
|
+
const config = loadConfig();
|
|
159
|
+
validateConfig(config);
|
|
160
|
+
return config;
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}
|