Skip to main content
Glama

Figma MCP Server

by sichang824
widget-api.ts4.53 kB
/** * Service for interacting with Figma Widget API */ import axios from 'axios'; import { env } from '../config/env.js'; import { z } from 'zod'; const FIGMA_API_BASE_URL = 'https://api.figma.com/v1'; // Widget data schemas export const WidgetNodeSchema = z.object({ id: z.string(), name: z.string(), type: z.literal('WIDGET'), widgetId: z.string().optional(), widgetSync: z.string().optional(), pluginData: z.record(z.unknown()).optional(), sharedPluginData: z.record(z.record(z.unknown())).optional(), }); export type WidgetNode = z.infer<typeof WidgetNodeSchema>; export const WidgetSyncDataSchema = z.record(z.unknown()); export type WidgetSyncData = z.infer<typeof WidgetSyncDataSchema>; /** * Service for interacting with Figma Widget API */ export class WidgetApiService { private readonly headers: Record<string, string>; constructor(accessToken: string = env.FIGMA_PERSONAL_ACCESS_TOKEN) { this.headers = { 'X-Figma-Token': accessToken, }; } /** * Get all widget nodes in a file */ async getWidgetNodes(fileKey: string): Promise<WidgetNode[]> { try { const response = await axios.get(, { headers: this.headers, }); const file = response.data; return this.findAllWidgetNodes(file.document); } catch (error) { console.error('Error fetching widget nodes:', error); throw error; } } /** * Get a specific widget node by ID */ async getWidgetNode(fileKey: string, nodeId: string): Promise<WidgetNode | null> { try { const response = await axios.get(, { headers: this.headers, }); const node = response.data.nodes[nodeId]?.document; if (!node || node.type !== 'WIDGET') { return null; } return WidgetNodeSchema.parse(node); } catch (error) { console.error('Error fetching widget node:', error); throw error; } } /** * Get the widget sync data (state) for a specific widget */ async getWidgetSyncData(fileKey: string, nodeId: string): Promise<WidgetSyncData | null> { try { const widgetNode = await this.getWidgetNode(fileKey, nodeId); if (!widgetNode || !widgetNode.widgetSync) { return null; } // Parse the widgetSync data string (it's stored as a JSON string) try { return JSON.parse(widgetNode.widgetSync); } catch (parseError) { console.error('Error parsing widget sync data:', parseError); return null; } } catch (error) { console.error('Error fetching widget sync data:', error); throw error; } } /** * Create a widget instance in a file (requires special access) * Note: This is only available to Figma widget developers or partners. */ async createWidget(fileKey: string, options: { name: string, widgetId: string, x: number, y: number, initialSyncData?: Record<string, any>, parentNodeId?: string, }): Promise<{ widgetNodeId: string } | null> { try { // This endpoint might not be publicly available const response = await axios.post( , options, { headers: this.headers } ); return response.data; } catch (error) { console.error('Error creating widget:', error); throw error; } } /** * Update a widget's properties (requires widget developer access) * Note: This functionality is limited to Figma widget developers. */ async updateWidgetProperties(fileKey: string, nodeId: string, properties: Record<string, any>): Promise<boolean> { try { // This endpoint might not be publicly available await axios.patch( , { properties }, { headers: this.headers } ); return true; } catch (error) { console.error('Error updating widget properties:', error); throw error; } } /** * Helper method to recursively find all widget nodes in a file */ private findAllWidgetNodes(node: any): WidgetNode[] { let widgets: WidgetNode[] = []; if (node.type === 'WIDGET') { try { widgets.push(WidgetNodeSchema.parse(node)); } catch (error) { console.error('Error parsing widget node:', error); } } if (node.children) { for (const child of node.children) { widgets = widgets.concat(this.findAllWidgetNodes(child)); } } return widgets; } } export default new WidgetApiService();

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sichang824/mcp-figma'

If you have feedback or need assistance with the MCP directory API, please join our Discord server