set_multiple_annotations
Enable parallel annotation application to nodes in Figma designs, streamlining collaborative workflows with Cursor AI integration.
Instructions
Set multiple annotations parallelly in a node
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Input Schema (JSON Schema)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {},
"type": "object"
}
Implementation Reference
- src/talk_to_figma_mcp/server.ts:1061-1171 (registration)MCP tool registration, schema definition, and handler for 'set_multiple_annotations'. The handler proxies the call to the Figma plugin via sendCommandToFigma and formats the response with progress information.server.tool( "set_multiple_annotations", "Set multiple annotations parallelly in a node", { nodeId: z .string() .describe("The ID of the node containing the elements to annotate"), annotations: z .array( z.object({ nodeId: z.string().describe("The ID of the node to annotate"), labelMarkdown: z.string().describe("The annotation text in markdown format"), categoryId: z.string().optional().describe("The ID of the annotation category"), annotationId: z.string().optional().describe("The ID of the annotation to update (if updating existing annotation)"), properties: z.array(z.object({ type: z.string() })).optional().describe("Additional properties for the annotation") }) ) .describe("Array of annotations to apply"), }, async ({ nodeId, annotations }, extra) => { try { if (!annotations || annotations.length === 0) { return { content: [ { type: "text", text: "No annotations provided", }, ], }; } // Initial response to indicate we're starting the process const initialStatus = { type: "text" as const, text: `Starting annotation process for ${annotations.length} nodes. This will be processed in batches of 5...`, }; // Track overall progress let totalProcessed = 0; const totalToProcess = annotations.length; // Use the plugin's set_multiple_annotations function with chunking const result = await sendCommandToFigma("set_multiple_annotations", { nodeId, annotations, }); // Cast the result to a specific type to work with it safely interface AnnotationResult { success: boolean; nodeId: string; annotationsApplied?: number; annotationsFailed?: number; totalAnnotations?: number; completedInChunks?: number; results?: Array<{ success: boolean; nodeId: string; error?: string; annotationId?: string; }>; } const typedResult = result as AnnotationResult; // Format the results for display const success = typedResult.annotationsApplied && typedResult.annotationsApplied > 0; const progressText = ` Annotation process completed: - ${typedResult.annotationsApplied || 0} of ${totalToProcess} successfully applied - ${typedResult.annotationsFailed || 0} failed - Processed in ${typedResult.completedInChunks || 1} batches `; // Detailed results const detailedResults = typedResult.results || []; const failedResults = detailedResults.filter(item => !item.success); // Create the detailed part of the response let detailedResponse = ""; if (failedResults.length > 0) { detailedResponse = `\n\nNodes that failed:\n${failedResults.map(item => `- ${item.nodeId}: ${item.error || "Unknown error"}` ).join('\n')}`; } return { content: [ initialStatus, { type: "text" as const, text: progressText + detailedResponse, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error setting multiple annotations: ${error instanceof Error ? error.message : String(error) }`, }, ], }; } } );
- src/cursor_mcp_plugin/code.js:2403-2489 (handler)Figma plugin-side handler for the 'set_multiple_annotations' command. Iterates over the annotations array, calls setAnnotation for each, tracks success/failure, and returns summary statistics.async function setMultipleAnnotations(params) { console.log("=== setMultipleAnnotations Debug Start ==="); console.log("Input params:", JSON.stringify(params, null, 2)); const { nodeId, annotations } = params; if (!annotations || annotations.length === 0) { console.error("Validation failed: No annotations provided"); return { success: false, error: "No annotations provided" }; } console.log( `Processing ${annotations.length} annotations for node ${nodeId}` ); const results = []; let successCount = 0; let failureCount = 0; // Process annotations sequentially for (let i = 0; i < annotations.length; i++) { const annotation = annotations[i]; console.log( `\nProcessing annotation ${i + 1}/${annotations.length}:`, JSON.stringify(annotation, null, 2) ); try { console.log("Calling setAnnotation with params:", { nodeId: annotation.nodeId, labelMarkdown: annotation.labelMarkdown, categoryId: annotation.categoryId, properties: annotation.properties, }); const result = await setAnnotation({ nodeId: annotation.nodeId, labelMarkdown: annotation.labelMarkdown, categoryId: annotation.categoryId, properties: annotation.properties, }); console.log("setAnnotation result:", JSON.stringify(result, null, 2)); if (result.success) { successCount++; results.push({ success: true, nodeId: annotation.nodeId }); console.log(`✓ Annotation ${i + 1} applied successfully`); } else { failureCount++; results.push({ success: false, nodeId: annotation.nodeId, error: result.error, }); console.error(`✗ Annotation ${i + 1} failed:`, result.error); } } catch (error) { failureCount++; const errorResult = { success: false, nodeId: annotation.nodeId, error: error.message, }; results.push(errorResult); console.error(`✗ Annotation ${i + 1} failed with error:`, error); console.error("Error details:", { message: error.message, stack: error.stack, }); } } const summary = { success: successCount > 0, annotationsApplied: successCount, annotationsFailed: failureCount, totalAnnotations: annotations.length, results: results, }; console.log("\n=== setMultipleAnnotations Summary ==="); console.log(JSON.stringify(summary, null, 2)); console.log("=== setMultipleAnnotations Debug End ==="); return summary; }
- Helper function setAnnotation used by setMultipleAnnotations to apply a single annotation to a node. Validates parameters, creates annotation object, sets node.annotations array.async function setAnnotation(params) { try { console.log("=== setAnnotation Debug Start ==="); console.log("Input params:", JSON.stringify(params, null, 2)); const { nodeId, annotationId, labelMarkdown, categoryId, properties } = params; // Validate required parameters if (!nodeId) { console.error("Validation failed: Missing nodeId"); return { success: false, error: "Missing nodeId" }; } if (!labelMarkdown) { console.error("Validation failed: Missing labelMarkdown"); return { success: false, error: "Missing labelMarkdown" }; } console.log("Attempting to get node:", nodeId); // Get and validate node const node = await figma.getNodeByIdAsync(nodeId); console.log("Node lookup result:", { id: nodeId, found: !!node, type: node ? node.type : undefined, name: node ? node.name : undefined, hasAnnotations: node ? "annotations" in node : false, }); if (!node) { console.error("Node lookup failed:", nodeId); return { success: false, error: `Node not found: ${nodeId}` }; } // Validate node supports annotations if (!("annotations" in node)) { console.error("Node annotation support check failed:", { nodeType: node.type, nodeId: node.id, }); return { success: false, error: `Node type ${node.type} does not support annotations`, }; } // Create the annotation object const newAnnotation = { labelMarkdown, }; // Validate and add categoryId if provided if (categoryId) { console.log("Adding categoryId to annotation:", categoryId); newAnnotation.categoryId = categoryId; } // Validate and add properties if provided if (properties && Array.isArray(properties) && properties.length > 0) { console.log( "Adding properties to annotation:", JSON.stringify(properties, null, 2) ); newAnnotation.properties = properties; } // Log current annotations before update console.log("Current node annotations:", node.annotations); // Overwrite annotations console.log( "Setting new annotation:", JSON.stringify(newAnnotation, null, 2) ); node.annotations = [newAnnotation]; // Verify the update console.log("Updated node annotations:", node.annotations); console.log("=== setAnnotation Debug End ==="); return { success: true, nodeId: node.id, name: node.name, annotations: node.annotations, }; } catch (error) { console.error("=== setAnnotation Error ==="); console.error("Error details:", { message: error.message, stack: error.stack, params: JSON.stringify(params, null, 2), }); return { success: false, error: error.message }; } }
- src/cursor_mcp_plugin/code.js:167-168 (handler)Dispatch case in handleCommand that routes 'set_multiple_annotations' command to the setMultipleAnnotations handler function.case "set_multiple_annotations": return await setMultipleAnnotations(params);