update_element
Modify properties of existing Excalidraw elements, such as position, size, colors, text, and style, to refine or update diagrams programmatically.
Instructions
Update an existing Excalidraw element
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| backgroundColor | No | ||
| fontFamily | No | ||
| fontSize | No | ||
| height | No | ||
| id | Yes | ||
| opacity | No | ||
| roughness | No | ||
| strokeColor | No | ||
| strokeWidth | No | ||
| text | No | ||
| type | No | ||
| width | No | ||
| x | No | ||
| y | No |
Implementation Reference
- src/index.ts:567-601 (handler)Main handler for the 'update_element' MCP tool. Validates input using Zod schemas, constructs the update payload, converts text to Excalidraw label format if needed, syncs the update to the canvas via HTTP API using updateElementOnCanvas helper, and returns a success response with the updated element details.case 'update_element': { const params = ElementIdSchema.merge(ElementSchema.partial()).parse(args); const { id, ...updates } = params; if (!id) throw new Error('Element ID is required'); // Build update payload with timestamp and version increment const updatePayload: Partial<ServerElement> & { id: string } = { id, ...updates, updatedAt: new Date().toISOString() }; // Convert text to label format for Excalidraw const excalidrawElement = convertTextToLabel(updatePayload as ServerElement); // Update element directly on HTTP server (no local storage) const canvasElement = await updateElementOnCanvas(excalidrawElement); if (!canvasElement) { throw new Error('Failed to update element: HTTP server unavailable or element not found'); } logger.info('Element updated via MCP and synced to canvas', { id: excalidrawElement.id, synced: !!canvasElement }); return { content: [{ type: 'text', text: `Element updated successfully!\n\n${JSON.stringify(canvasElement, null, 2)}\n\n✅ Synced to canvas` }] }; }
- src/index.ts:259-285 (registration)Registration of the 'update_element' tool in the MCP tools array, including name, description, and JSON input schema definition.{ name: 'update_element', description: 'Update an existing Excalidraw element', inputSchema: { type: 'object', properties: { id: { type: 'string' }, type: { type: 'string', enum: Object.values(EXCALIDRAW_ELEMENT_TYPES) }, x: { type: 'number' }, y: { type: 'number' }, width: { type: 'number' }, height: { type: 'number' }, backgroundColor: { type: 'string' }, strokeColor: { type: 'string' }, strokeWidth: { type: 'number' }, roughness: { type: 'number' }, opacity: { type: 'number' }, text: { type: 'string' }, fontSize: { type: 'number' }, fontFamily: { type: 'string' } }, required: ['id'] } },
- src/index.ts:127-130 (helper)Helper function that performs the actual canvas sync for element updates by calling the generic syncToCanvas function with 'update' operation.async function updateElementOnCanvas(elementData: Partial<ServerElement> & { id: string }): Promise<ServerElement | null> { const result = await syncToCanvas('update', elementData); return result?.element || null; }
- src/server.ts:113-133 (schema)Zod schema used by the Express server PUT /api/elements/:id endpoint for validating update requests, which is called by the MCP tool's sync helper.const UpdateElementSchema = z.object({ id: z.string(), type: z.enum(Object.values(EXCALIDRAW_ELEMENT_TYPES) as [ExcalidrawElementType, ...ExcalidrawElementType[]]).optional(), x: z.number().optional(), y: z.number().optional(), width: z.number().optional(), height: z.number().optional(), backgroundColor: z.string().optional(), strokeColor: z.string().optional(), strokeWidth: z.number().optional(), roughness: z.number().optional(), opacity: z.number().optional(), text: z.string().optional(), label: z.object({ text: z.string() }).optional(), fontSize: z.number().optional(), fontFamily: z.string().optional(), groupIds: z.array(z.string()).optional(), locked: z.boolean().optional() });
- src/server.ts:194-241 (handler)Backend Express handler for PUT /api/elements/:id, which performs the actual element update in memory storage, broadcasts via WebSocket, and returns the updated element. Called indirectly by MCP tool via HTTP sync.app.put('/api/elements/:id', (req: Request, res: Response) => { try { const { id } = req.params; const updates = UpdateElementSchema.parse({ id, ...req.body }); if (!id) { return res.status(400).json({ success: false, error: 'Element ID is required' }); } const existingElement = elements.get(id); if (!existingElement) { return res.status(404).json({ success: false, error: `Element with ID ${id} not found` }); } const updatedElement: ServerElement = { ...existingElement, ...updates, updatedAt: new Date().toISOString(), version: (existingElement.version || 0) + 1 }; elements.set(id, updatedElement); // Broadcast to all connected clients const message: ElementUpdatedMessage = { type: 'element_updated', element: updatedElement }; broadcast(message); res.json({ success: true, element: updatedElement }); } catch (error) { logger.error('Error updating element:', error); res.status(400).json({ success: false, error: (error as Error).message }); } });