@atezer/figma-mcp-bridge 1.1.2 → 1.2.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 +0 -11
- package/README.md +11 -2
- package/dist/cloudflare/core/figma-tools.js +290 -254
- package/dist/cloudflare/core/plugin-bridge-server.js +64 -16
- package/dist/core/figma-tools.d.ts.map +1 -1
- package/dist/core/figma-tools.js +290 -254
- package/dist/core/figma-tools.js.map +1 -1
- package/dist/core/plugin-bridge-server.d.ts +5 -1
- package/dist/core/plugin-bridge-server.d.ts.map +1 -1
- package/dist/core/plugin-bridge-server.js +64 -16
- package/dist/core/plugin-bridge-server.js.map +1 -1
- package/dist/local-plugin-only.d.ts.map +1 -1
- package/dist/local-plugin-only.js +243 -111
- package/dist/local-plugin-only.js.map +1 -1
- package/dist/local.js +323 -183
- package/dist/local.js.map +1 -1
- package/f-mcp-plugin/code.js +27 -0
- package/f-mcp-plugin/manifest.json +1 -1
- package/f-mcp-plugin/ui.html +100 -29
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-plugin-only.d.ts","sourceRoot":"","sources":["../src/local-plugin-only.ts"],"names":[],"mappings":";AAEA;;;;;;;;;GASG;AA0CH,wBAAsB,IAAI,
|
|
1
|
+
{"version":3,"file":"local-plugin-only.d.ts","sourceRoot":"","sources":["../src/local-plugin-only.ts"],"names":[],"mappings":";AAEA;;;;;;;;;GASG;AA0CH,wBAAsB,IAAI,kBAm2BzB"}
|
|
@@ -56,17 +56,21 @@ export async function main() {
|
|
|
56
56
|
bridge.start();
|
|
57
57
|
const server = new McpServer({
|
|
58
58
|
name: "F-MCP ATezer Bridge (Plugin-only)",
|
|
59
|
-
version: "1.
|
|
59
|
+
version: "1.1.2",
|
|
60
60
|
});
|
|
61
61
|
// ---- figma_get_file_data_plugin (no REST, no token) ----
|
|
62
|
-
server.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
server.registerTool("figma_get_file_data", {
|
|
63
|
+
description: "Get file structure and document tree from the open Figma file. No REST API or token needed. Uses plugin only. Start with depth=1 and verbosity=summary for minimal tokens. Use includeLayout/includeVisual/includeTypography for pixel-perfect spec (auto-layout, constraints, fills, typography).",
|
|
64
|
+
inputSchema: {
|
|
65
|
+
depth: z.number().min(0).max(3).optional().default(1),
|
|
66
|
+
verbosity: z.enum(["summary", "standard", "full"]).optional().default("summary"),
|
|
67
|
+
includeLayout: z.boolean().optional(),
|
|
68
|
+
includeVisual: z.boolean().optional(),
|
|
69
|
+
includeTypography: z.boolean().optional(),
|
|
70
|
+
includeCodeReady: z.boolean().optional(),
|
|
71
|
+
outputHint: z.enum(["react", "tailwind"]).optional(),
|
|
72
|
+
},
|
|
73
|
+
annotations: { readOnlyHint: true },
|
|
70
74
|
}, async ({ depth, verbosity, includeLayout, includeVisual, includeTypography, includeCodeReady, outputHint }) => {
|
|
71
75
|
try {
|
|
72
76
|
const conn = getConnector(bridge);
|
|
@@ -94,16 +98,20 @@ export async function main() {
|
|
|
94
98
|
}
|
|
95
99
|
});
|
|
96
100
|
// ---- figma_get_design_context (get_design_context tarzı, token tasarruflu, Figma token yok) ----
|
|
97
|
-
server.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
101
|
+
server.registerTool("figma_get_design_context", {
|
|
102
|
+
description: "Design context for a node or whole file: structure + text, and optionally layout/visual/typography. Returns roleHint/suiComponent (SUI-style name), layoutSummary, colorHex, variantSummary/suggestedProps for instances, incompleteReasons, hasImageFill. Use outputHint: react or tailwind for code-ready layoutSummary. No Figma REST API, no token.",
|
|
103
|
+
inputSchema: {
|
|
104
|
+
nodeId: z.string().optional(),
|
|
105
|
+
depth: z.number().min(0).max(3).optional().default(2),
|
|
106
|
+
verbosity: z.enum(["summary", "standard", "full"]).optional().default("standard"),
|
|
107
|
+
excludeScreenshot: z.boolean().optional(),
|
|
108
|
+
includeLayout: z.boolean().optional(),
|
|
109
|
+
includeVisual: z.boolean().optional(),
|
|
110
|
+
includeTypography: z.boolean().optional(),
|
|
111
|
+
includeCodeReady: z.boolean().optional(),
|
|
112
|
+
outputHint: z.enum(["react", "tailwind"]).optional(),
|
|
113
|
+
},
|
|
114
|
+
annotations: { readOnlyHint: true },
|
|
107
115
|
}, async ({ nodeId, depth, verbosity, includeLayout, includeVisual, includeTypography, includeCodeReady, outputHint }) => {
|
|
108
116
|
try {
|
|
109
117
|
const conn = getConnector(bridge);
|
|
@@ -133,8 +141,12 @@ export async function main() {
|
|
|
133
141
|
}
|
|
134
142
|
});
|
|
135
143
|
// ---- figma_get_variables (plugin only, token-friendly default) ----
|
|
136
|
-
server.
|
|
137
|
-
|
|
144
|
+
server.registerTool("figma_get_variables", {
|
|
145
|
+
description: "Get design tokens and variables from the open Figma file. No REST API or token. Returns summary by default to save tokens.",
|
|
146
|
+
inputSchema: {
|
|
147
|
+
verbosity: z.enum(["inventory", "summary", "standard", "full"]).optional().default("summary"),
|
|
148
|
+
},
|
|
149
|
+
annotations: { readOnlyHint: true },
|
|
138
150
|
}, async ({ verbosity }) => {
|
|
139
151
|
const conn = getConnector(bridge);
|
|
140
152
|
const raw = await conn.getVariablesFromPluginUI();
|
|
@@ -162,99 +174,155 @@ export async function main() {
|
|
|
162
174
|
return { content: [{ type: "text", text: JSON.stringify(out, null, 0) }] };
|
|
163
175
|
});
|
|
164
176
|
// ---- figma_get_component ----
|
|
165
|
-
server.
|
|
177
|
+
server.registerTool("figma_get_component", {
|
|
178
|
+
description: "Get component metadata by node ID from the open Figma file. No REST API. Use figma_get_file_data or figma_search_components to find nodeIds.",
|
|
179
|
+
inputSchema: { nodeId: z.string() },
|
|
180
|
+
annotations: { readOnlyHint: true },
|
|
181
|
+
}, async ({ nodeId }) => {
|
|
166
182
|
const conn = getConnector(bridge);
|
|
167
183
|
const result = await conn.getComponentFromPluginUI(nodeId);
|
|
168
184
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 0) }] };
|
|
169
185
|
});
|
|
170
186
|
// ---- figma_get_styles (plugin only) ----
|
|
171
|
-
server.
|
|
187
|
+
server.registerTool("figma_get_styles", {
|
|
188
|
+
description: "Get local paint, text, and effect styles from the open Figma file. No REST API. Default verbosity=summary for token saving.",
|
|
189
|
+
inputSchema: { verbosity: z.enum(["summary", "full"]).optional().default("summary") },
|
|
190
|
+
annotations: { readOnlyHint: true },
|
|
191
|
+
}, async ({ verbosity }) => {
|
|
172
192
|
const conn = getConnector(bridge);
|
|
173
193
|
const data = await conn.getLocalStyles(verbosity);
|
|
174
194
|
return { content: [{ type: "text", text: JSON.stringify(data || {}, null, 0) }] };
|
|
175
195
|
});
|
|
176
196
|
// ---- figma_execute ----
|
|
177
|
-
server.
|
|
178
|
-
|
|
179
|
-
|
|
197
|
+
server.registerTool("figma_execute", {
|
|
198
|
+
description: "Run JavaScript in the Figma plugin context. Full Plugin API available (figma.root, figma.createFrame, etc.). No token needed.",
|
|
199
|
+
inputSchema: {
|
|
200
|
+
code: z.string(),
|
|
201
|
+
timeout: z.number().optional().default(5000),
|
|
202
|
+
},
|
|
203
|
+
annotations: { destructiveHint: true },
|
|
180
204
|
}, async ({ code, timeout }) => {
|
|
181
205
|
const conn = getConnector(bridge);
|
|
182
206
|
const result = await conn.executeCodeViaUI(code, timeout);
|
|
183
207
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 0) }] };
|
|
184
208
|
});
|
|
185
209
|
// ---- figma_capture_screenshot ----
|
|
186
|
-
server.
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
210
|
+
server.registerTool("figma_capture_screenshot", {
|
|
211
|
+
description: "Capture screenshot of a node or current view from the plugin. No REST API.",
|
|
212
|
+
inputSchema: {
|
|
213
|
+
nodeId: z.string().optional(),
|
|
214
|
+
format: z.enum(["PNG", "JPG"]).optional().default("PNG"),
|
|
215
|
+
scale: z.number().optional().default(2),
|
|
216
|
+
},
|
|
217
|
+
annotations: { readOnlyHint: true },
|
|
190
218
|
}, async ({ nodeId, format, scale }) => {
|
|
191
219
|
const conn = getConnector(bridge);
|
|
192
220
|
const result = await conn.captureScreenshot(nodeId ?? null, { format, scale });
|
|
193
221
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 0) }] };
|
|
194
222
|
});
|
|
195
223
|
// ---- figma_set_instance_properties ----
|
|
196
|
-
server.
|
|
197
|
-
|
|
198
|
-
|
|
224
|
+
server.registerTool("figma_set_instance_properties", {
|
|
225
|
+
description: "Set component instance properties (TEXT, BOOLEAN, VARIANT, etc.).",
|
|
226
|
+
inputSchema: {
|
|
227
|
+
nodeId: z.string(),
|
|
228
|
+
properties: z.record(z.union([z.string(), z.boolean()])),
|
|
229
|
+
},
|
|
230
|
+
annotations: { destructiveHint: true },
|
|
199
231
|
}, async ({ nodeId, properties }) => {
|
|
200
232
|
const conn = getConnector(bridge);
|
|
201
233
|
const result = await conn.setInstanceProperties(nodeId, properties);
|
|
202
234
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 0) }] };
|
|
203
235
|
});
|
|
204
236
|
// ---- Variable CRUD ----
|
|
205
|
-
server.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
237
|
+
server.registerTool("figma_update_variable", {
|
|
238
|
+
description: "Update a variable value in a mode. Get IDs from figma_get_variables.",
|
|
239
|
+
inputSchema: {
|
|
240
|
+
variableId: z.string(),
|
|
241
|
+
modeId: z.string(),
|
|
242
|
+
value: z.union([z.string(), z.number(), z.boolean()]),
|
|
243
|
+
},
|
|
244
|
+
annotations: { destructiveHint: true },
|
|
209
245
|
}, async (p) => {
|
|
210
246
|
const conn = getConnector(bridge);
|
|
211
247
|
const result = await conn.updateVariable(p.variableId, p.modeId, p.value);
|
|
212
248
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 0) }] };
|
|
213
249
|
});
|
|
214
|
-
server.
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
250
|
+
server.registerTool("figma_create_variable", {
|
|
251
|
+
description: "Create a variable in a collection. Get collectionId from figma_get_variables.",
|
|
252
|
+
inputSchema: {
|
|
253
|
+
name: z.string(),
|
|
254
|
+
collectionId: z.string(),
|
|
255
|
+
resolvedType: z.enum(["COLOR", "FLOAT", "STRING", "BOOLEAN"]),
|
|
256
|
+
options: z.record(z.any()).optional(),
|
|
257
|
+
},
|
|
258
|
+
annotations: { destructiveHint: true },
|
|
219
259
|
}, async (p) => {
|
|
220
260
|
const conn = getConnector(bridge);
|
|
221
261
|
const result = await conn.createVariable(p.name, p.collectionId, p.resolvedType, p.options);
|
|
222
262
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 0) }] };
|
|
223
263
|
});
|
|
224
|
-
server.
|
|
264
|
+
server.registerTool("figma_create_variable_collection", {
|
|
265
|
+
description: "Create a variable collection.",
|
|
266
|
+
inputSchema: { name: z.string(), options: z.record(z.any()).optional() },
|
|
267
|
+
annotations: { destructiveHint: true },
|
|
268
|
+
}, async (p) => {
|
|
225
269
|
const conn = getConnector(bridge);
|
|
226
270
|
const result = await conn.createVariableCollection(p.name, p.options);
|
|
227
271
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 0) }] };
|
|
228
272
|
});
|
|
229
|
-
server.
|
|
273
|
+
server.registerTool("figma_delete_variable", {
|
|
274
|
+
description: "Delete a variable.",
|
|
275
|
+
inputSchema: { variableId: z.string() },
|
|
276
|
+
annotations: { destructiveHint: true },
|
|
277
|
+
}, async (p) => {
|
|
230
278
|
const conn = getConnector(bridge);
|
|
231
279
|
const result = await conn.deleteVariable(p.variableId);
|
|
232
280
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 0) }] };
|
|
233
281
|
});
|
|
234
|
-
server.
|
|
282
|
+
server.registerTool("figma_delete_variable_collection", {
|
|
283
|
+
description: "Delete a variable collection.",
|
|
284
|
+
inputSchema: { collectionId: z.string() },
|
|
285
|
+
annotations: { destructiveHint: true },
|
|
286
|
+
}, async (p) => {
|
|
235
287
|
const conn = getConnector(bridge);
|
|
236
288
|
const result = await conn.deleteVariableCollection(p.collectionId);
|
|
237
289
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 0) }] };
|
|
238
290
|
});
|
|
239
|
-
server.
|
|
291
|
+
server.registerTool("figma_rename_variable", {
|
|
292
|
+
description: "Rename a variable.",
|
|
293
|
+
inputSchema: { variableId: z.string(), newName: z.string() },
|
|
294
|
+
annotations: { destructiveHint: true },
|
|
295
|
+
}, async (p) => {
|
|
240
296
|
const conn = getConnector(bridge);
|
|
241
297
|
const result = await conn.renameVariable(p.variableId, p.newName);
|
|
242
298
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 0) }] };
|
|
243
299
|
});
|
|
244
|
-
server.
|
|
300
|
+
server.registerTool("figma_add_mode", {
|
|
301
|
+
description: "Add a mode to a collection.",
|
|
302
|
+
inputSchema: { collectionId: z.string(), modeName: z.string() },
|
|
303
|
+
annotations: { destructiveHint: true },
|
|
304
|
+
}, async (p) => {
|
|
245
305
|
const conn = getConnector(bridge);
|
|
246
306
|
const result = await conn.addMode(p.collectionId, p.modeName);
|
|
247
307
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 0) }] };
|
|
248
308
|
});
|
|
249
|
-
server.
|
|
309
|
+
server.registerTool("figma_rename_mode", {
|
|
310
|
+
description: "Rename a mode in a collection.",
|
|
311
|
+
inputSchema: { collectionId: z.string(), modeId: z.string(), newName: z.string() },
|
|
312
|
+
annotations: { destructiveHint: true },
|
|
313
|
+
}, async (p) => {
|
|
250
314
|
const conn = getConnector(bridge);
|
|
251
315
|
const result = await conn.renameMode(p.collectionId, p.modeId, p.newName);
|
|
252
316
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 0) }] };
|
|
253
317
|
});
|
|
254
318
|
// ---- Design system summary (minimal tokens) ----
|
|
255
|
-
server.
|
|
256
|
-
|
|
257
|
-
|
|
319
|
+
server.registerTool("figma_get_design_system_summary", {
|
|
320
|
+
description: "Get a compact overview: variable collection names and component counts. Minimal tokens. No REST API. Uses currentPageOnly: true by default to avoid timeout on large files (SUI); set currentPageOnly: false to scan entire file.",
|
|
321
|
+
inputSchema: {
|
|
322
|
+
currentPageOnly: z.boolean().optional().default(true),
|
|
323
|
+
limit: z.number().min(0).optional(),
|
|
324
|
+
},
|
|
325
|
+
annotations: { readOnlyHint: true },
|
|
258
326
|
}, async ({ currentPageOnly, limit }) => {
|
|
259
327
|
const conn = getConnector(bridge);
|
|
260
328
|
const [vars, components] = await Promise.all([
|
|
@@ -273,10 +341,14 @@ export async function main() {
|
|
|
273
341
|
return { content: [{ type: "text", text: JSON.stringify(out, null, 0) }] };
|
|
274
342
|
});
|
|
275
343
|
// ---- figma_search_components ----
|
|
276
|
-
server.
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
344
|
+
server.registerTool("figma_search_components", {
|
|
345
|
+
description: "Search local components by name. Returns nodeIds and names. No REST API. Uses currentPageOnly: true by default to avoid timeout on large files; set currentPageOnly: false to search entire file.",
|
|
346
|
+
inputSchema: {
|
|
347
|
+
query: z.string().optional(),
|
|
348
|
+
currentPageOnly: z.boolean().optional().default(true),
|
|
349
|
+
limit: z.number().min(0).optional(),
|
|
350
|
+
},
|
|
351
|
+
annotations: { readOnlyHint: true },
|
|
280
352
|
}, async ({ query, currentPageOnly, limit }) => {
|
|
281
353
|
const conn = getConnector(bridge);
|
|
282
354
|
const result = (await conn.getLocalComponents({ currentPageOnly, limit }));
|
|
@@ -293,33 +365,49 @@ export async function main() {
|
|
|
293
365
|
return { content: [{ type: "text", text: JSON.stringify({ success: true, components: summary }, null, 0) }] };
|
|
294
366
|
});
|
|
295
367
|
// ---- Node operations (short list) ----
|
|
296
|
-
server.
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
.
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
368
|
+
server.registerTool("figma_instantiate_component", {
|
|
369
|
+
description: "Create a component instance. Use componentKey from figma_search_components or nodeId for local components.",
|
|
370
|
+
inputSchema: {
|
|
371
|
+
componentKey: z.string(),
|
|
372
|
+
options: z
|
|
373
|
+
.object({
|
|
374
|
+
nodeId: z.string().optional(),
|
|
375
|
+
position: z.object({ x: z.number(), y: z.number() }).optional(),
|
|
376
|
+
parentId: z.string().optional(),
|
|
377
|
+
overrides: z.record(z.any()).optional(),
|
|
378
|
+
})
|
|
379
|
+
.optional(),
|
|
380
|
+
},
|
|
381
|
+
annotations: { destructiveHint: true },
|
|
306
382
|
}, async (p) => {
|
|
307
383
|
const conn = getConnector(bridge);
|
|
308
384
|
const result = await conn.instantiateComponent(p.componentKey, p.options || {});
|
|
309
385
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 0) }] };
|
|
310
386
|
});
|
|
311
|
-
server.
|
|
387
|
+
server.registerTool("figma_refresh_variables", {
|
|
388
|
+
description: "Refresh variables from the file.",
|
|
389
|
+
inputSchema: {},
|
|
390
|
+
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
391
|
+
}, async () => {
|
|
312
392
|
const conn = getConnector(bridge);
|
|
313
393
|
const result = await conn.refreshVariables();
|
|
314
394
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 0) }] };
|
|
315
395
|
});
|
|
316
396
|
// ---- Console (plugin buffer, no CDP) ----
|
|
317
|
-
server.
|
|
397
|
+
server.registerTool("figma_get_console_logs", {
|
|
398
|
+
description: "Get plugin console logs (log/warn/error) from the F-MCP plugin buffer. No CDP. Limit default 50.",
|
|
399
|
+
inputSchema: { limit: z.number().min(1).max(200).optional().default(50) },
|
|
400
|
+
annotations: { readOnlyHint: true },
|
|
401
|
+
}, async ({ limit }) => {
|
|
318
402
|
const conn = getConnector(bridge);
|
|
319
403
|
const data = await conn.getConsoleLogs(limit);
|
|
320
404
|
return { content: [{ type: "text", text: JSON.stringify({ success: true, ...data }, null, 0) }] };
|
|
321
405
|
});
|
|
322
|
-
server.
|
|
406
|
+
server.registerTool("figma_watch_console", {
|
|
407
|
+
description: "Stream new plugin console logs until timeout. Polls the plugin buffer. Timeout default 30s.",
|
|
408
|
+
inputSchema: { timeoutSeconds: z.number().min(1).max(120).optional().default(30) },
|
|
409
|
+
annotations: { readOnlyHint: true },
|
|
410
|
+
}, async ({ timeoutSeconds }) => {
|
|
323
411
|
const conn = getConnector(bridge);
|
|
324
412
|
const deadline = Date.now() + timeoutSeconds * 1000;
|
|
325
413
|
const seen = new Set();
|
|
@@ -339,34 +427,50 @@ export async function main() {
|
|
|
339
427
|
content: [{ type: "text", text: JSON.stringify({ success: true, stream, count: stream.length }, null, 0) }],
|
|
340
428
|
};
|
|
341
429
|
});
|
|
342
|
-
server.
|
|
430
|
+
server.registerTool("figma_clear_console", {
|
|
431
|
+
description: "Clear the plugin console log buffer.",
|
|
432
|
+
inputSchema: {},
|
|
433
|
+
annotations: { destructiveHint: true },
|
|
434
|
+
}, async () => {
|
|
343
435
|
const conn = getConnector(bridge);
|
|
344
436
|
await conn.clearConsole();
|
|
345
437
|
return { content: [{ type: "text", text: JSON.stringify({ success: true, message: "Console cleared" }, null, 0) }] };
|
|
346
438
|
});
|
|
347
439
|
// ---- set_description, get_component_image, get_component_for_development ----
|
|
348
|
-
server.
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
440
|
+
server.registerTool("figma_set_description", {
|
|
441
|
+
description: "Set description on a component, component set, or style node. Supports markdown (descriptionMarkdown).",
|
|
442
|
+
inputSchema: {
|
|
443
|
+
nodeId: z.string(),
|
|
444
|
+
description: z.string(),
|
|
445
|
+
descriptionMarkdown: z.string().optional(),
|
|
446
|
+
},
|
|
447
|
+
annotations: { destructiveHint: true },
|
|
352
448
|
}, async (p) => {
|
|
353
449
|
const conn = getConnector(bridge);
|
|
354
450
|
const result = await conn.setNodeDescription(p.nodeId, p.description, p.descriptionMarkdown);
|
|
355
451
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 0) }] };
|
|
356
452
|
});
|
|
357
|
-
server.
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
453
|
+
server.registerTool("figma_get_component_image", {
|
|
454
|
+
description: "Get screenshot of a node (component/frame). Returns base64 image. No REST API.",
|
|
455
|
+
inputSchema: {
|
|
456
|
+
nodeId: z.string(),
|
|
457
|
+
scale: z.number().min(0.5).max(4).optional().default(2),
|
|
458
|
+
format: z.enum(["PNG", "JPG"]).optional().default("PNG"),
|
|
459
|
+
},
|
|
460
|
+
annotations: { readOnlyHint: true },
|
|
361
461
|
}, async ({ nodeId, scale, format }) => {
|
|
362
462
|
const conn = getConnector(bridge);
|
|
363
463
|
const result = await conn.captureScreenshot(nodeId, { scale, format });
|
|
364
464
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 0) }] };
|
|
365
465
|
});
|
|
366
|
-
server.
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
466
|
+
server.registerTool("figma_get_component_for_development", {
|
|
467
|
+
description: "Get component metadata plus base64 screenshot in one call. For design-to-code workflows.",
|
|
468
|
+
inputSchema: {
|
|
469
|
+
nodeId: z.string(),
|
|
470
|
+
scale: z.number().min(0.5).max(4).optional().default(2),
|
|
471
|
+
format: z.enum(["PNG", "JPG"]).optional().default("PNG"),
|
|
472
|
+
},
|
|
473
|
+
annotations: { readOnlyHint: true },
|
|
370
474
|
}, async ({ nodeId, scale, format }) => {
|
|
371
475
|
const conn = getConnector(bridge);
|
|
372
476
|
const [component, screenshot] = await Promise.all([
|
|
@@ -378,53 +482,73 @@ export async function main() {
|
|
|
378
482
|
return { content: [{ type: "text", text: JSON.stringify(out, null, 0) }] };
|
|
379
483
|
});
|
|
380
484
|
// ---- Batch variables & setup_design_tokens & arrange_component_set ----
|
|
381
|
-
server.
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
485
|
+
server.registerTool("figma_batch_create_variables", {
|
|
486
|
+
description: "Create up to 100 variables in one call. Each item: collectionId, name, resolvedType (COLOR/FLOAT/STRING/BOOLEAN), value, modeId. Returns created and failed lists.",
|
|
487
|
+
inputSchema: {
|
|
488
|
+
items: z.array(z.object({
|
|
489
|
+
collectionId: z.string(),
|
|
490
|
+
name: z.string(),
|
|
491
|
+
resolvedType: z.enum(["COLOR", "FLOAT", "STRING", "BOOLEAN"]),
|
|
492
|
+
value: z.unknown().optional(),
|
|
493
|
+
modeId: z.string().optional(),
|
|
494
|
+
valuesByMode: z.record(z.unknown()).optional(),
|
|
495
|
+
})).max(100),
|
|
496
|
+
},
|
|
497
|
+
annotations: { destructiveHint: true },
|
|
390
498
|
}, async ({ items }) => {
|
|
391
499
|
const conn = getConnector(bridge);
|
|
392
500
|
const result = await conn.batchCreateVariables(items);
|
|
393
501
|
return { content: [{ type: "text", text: JSON.stringify({ success: true, ...result }, null, 0) }] };
|
|
394
502
|
});
|
|
395
|
-
server.
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
503
|
+
server.registerTool("figma_batch_update_variables", {
|
|
504
|
+
description: "Update up to 100 variables. Each item: variableId, modeId, value. Returns updated and failed lists.",
|
|
505
|
+
inputSchema: {
|
|
506
|
+
items: z.array(z.object({
|
|
507
|
+
variableId: z.string(),
|
|
508
|
+
modeId: z.string(),
|
|
509
|
+
value: z.union([z.string(), z.number(), z.boolean()]),
|
|
510
|
+
})).max(100),
|
|
511
|
+
},
|
|
512
|
+
annotations: { destructiveHint: true },
|
|
401
513
|
}, async ({ items }) => {
|
|
402
514
|
const conn = getConnector(bridge);
|
|
403
515
|
const result = await conn.batchUpdateVariables(items);
|
|
404
516
|
return { content: [{ type: "text", text: JSON.stringify({ success: true, ...result }, null, 0) }] };
|
|
405
517
|
});
|
|
406
|
-
server.
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
518
|
+
server.registerTool("figma_setup_design_tokens", {
|
|
519
|
+
description: "Atomically create a variable collection + modes + variables. Rollback on any error. Params: collectionName, modes (array), tokens (array of { name, type?, value? or values? }).",
|
|
520
|
+
inputSchema: {
|
|
521
|
+
collectionName: z.string(),
|
|
522
|
+
modes: z.array(z.string()).min(1),
|
|
523
|
+
tokens: z.array(z.object({
|
|
524
|
+
name: z.string(),
|
|
525
|
+
type: z.enum(["COLOR", "FLOAT", "STRING", "BOOLEAN"]).optional(),
|
|
526
|
+
value: z.unknown().optional(),
|
|
527
|
+
values: z.record(z.unknown()).optional(),
|
|
528
|
+
})),
|
|
529
|
+
},
|
|
530
|
+
annotations: { destructiveHint: true },
|
|
415
531
|
}, async (p) => {
|
|
416
532
|
const conn = getConnector(bridge);
|
|
417
533
|
const result = await conn.setupDesignTokens(p);
|
|
418
534
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 0) }] };
|
|
419
535
|
});
|
|
420
|
-
server.
|
|
536
|
+
server.registerTool("figma_arrange_component_set", {
|
|
537
|
+
description: "Combine multiple component nodes into one Figma component set (combineAsVariants). Params: nodeIds (array of at least 2 component node IDs). Returns new component set nodeId.",
|
|
538
|
+
inputSchema: { nodeIds: z.array(z.string()).min(2) },
|
|
539
|
+
annotations: { destructiveHint: true },
|
|
540
|
+
}, async ({ nodeIds }) => {
|
|
421
541
|
const conn = getConnector(bridge);
|
|
422
542
|
const result = await conn.arrangeComponentSet(nodeIds);
|
|
423
543
|
return { content: [{ type: "text", text: JSON.stringify({ success: true, ...result }, null, 0) }] };
|
|
424
544
|
});
|
|
425
545
|
// ---- figma_check_design_parity (design–code gap analysis) ----
|
|
426
|
-
server.
|
|
427
|
-
|
|
546
|
+
server.registerTool("figma_check_design_parity", {
|
|
547
|
+
description: "Compare Figma design tokens (variables + styles) with code-side tokens. Critical for design-code gap analysis. Returns matching, inFigmaOnly, inCodeOnly, and divergent (same name, different value). Optional codeTokens: JSON string of expected tokens, e.g. {\"primary\": \"#0066cc\", \"spacing.md\": 16} or {\"primary\": {\"value\": \"#0066cc\"}}.",
|
|
548
|
+
inputSchema: {
|
|
549
|
+
codeTokens: z.string().optional(),
|
|
550
|
+
},
|
|
551
|
+
annotations: { readOnlyHint: true },
|
|
428
552
|
}, async ({ codeTokens }) => {
|
|
429
553
|
try {
|
|
430
554
|
const conn = getConnector(bridge);
|
|
@@ -546,8 +670,12 @@ export async function main() {
|
|
|
546
670
|
}
|
|
547
671
|
});
|
|
548
672
|
// ---- figma_get_token_browser (Token Browser – kurulum özel MCP App) ----
|
|
549
|
-
server.
|
|
550
|
-
|
|
673
|
+
server.registerTool("figma_get_token_browser", {
|
|
674
|
+
description: "Token Browser: hierarchical view of design tokens for browsing. Returns variable collections with variables and modes, plus paint and text styles. Use for exploring and auditing tokens in the open Figma file. No REST API.",
|
|
675
|
+
inputSchema: {
|
|
676
|
+
verbosity: z.enum(["summary", "full"]).optional().default("summary"),
|
|
677
|
+
},
|
|
678
|
+
annotations: { readOnlyHint: true },
|
|
551
679
|
}, async ({ verbosity }) => {
|
|
552
680
|
try {
|
|
553
681
|
const conn = getConnector(bridge);
|
|
@@ -611,7 +739,11 @@ export async function main() {
|
|
|
611
739
|
}
|
|
612
740
|
});
|
|
613
741
|
// ---- figma_get_status (plugin-only) ----
|
|
614
|
-
server.
|
|
742
|
+
server.registerTool("figma_get_status", {
|
|
743
|
+
description: "Check if F-MCP ATezer Bridge plugin is connected. No REST API or token.",
|
|
744
|
+
inputSchema: {},
|
|
745
|
+
annotations: { readOnlyHint: true },
|
|
746
|
+
}, async () => {
|
|
615
747
|
const connected = bridge.isConnected();
|
|
616
748
|
const msg = connected
|
|
617
749
|
? "F-MCP ATezer Bridge plugin is connected. You can use all figma_* tools."
|