UNPKG

spex-mcp

Version:

MCP server for Figma SpeX plugin and Cursor AI integration

299 lines (275 loc) 9.23 kB
/** * MCPToolsManager handles all MCP tools for Cursor AI integration * Supports image injection as per Cursor MCP documentation */ export class MCPToolsManager { constructor(figmaManager) { this.figmaManager = figmaManager; } /** * Get list of all available MCP tools for Cursor AI */ getToolsList() { return [ { name: "hello-world", description: "Returns a simple hello world message", inputSchema: { type: "object", properties: {}, required: [], }, }, { name: "get-specs-readme", description: "Fetches the README.md file from the SpeX plugin that contains documentation about the exported design specs", inputSchema: { type: "object", properties: {}, required: [], }, }, { name: "get-spec-files-manifest", description: "Fetches the manifest.yaml file from the SpeX plugin to confirm design specs are ready and get the list of available spec files", inputSchema: { type: "object", properties: {}, required: [], }, }, { name: "get-a-spec-file", description: "Fetches a specific design specification file from the SpeX plugin by filename", inputSchema: { type: "object", properties: { file_name: { type: "string", description: "The name of the spec file to retrieve (e.g., 'screen.yaml', 'components/button.yaml')" } }, required: ["file_name"], }, }, { name: "get-page-thumbnail", description: "Fetches a thumbnail image of the current page or screen from the Figma design", inputSchema: { type: "object", properties: {}, required: [], }, }, ]; } /** * Handle MCP tool calls from Cursor AI */ async handleToolCall(name, args = {}) { switch (name) { case "hello-world": return this.handleHelloWorld(); case "get-specs-readme": return this.handleGetSpecsReadme(); case "get-spec-files-manifest": return this.handleGetSpecFilesManifest(); case "get-a-spec-file": return this.handleGetASpecFile(args); case "get-page-thumbnail": return this.handleGetPageThumbnail(args); default: throw new Error(`Unknown tool: ${name}`); } } /** * Handle hello world tool call */ handleHelloWorld() { return { content: [ { type: "text", text: "Hello World from SpeX MCP Server! 🎨", }, ], }; } /** * Handle get specs readme tool call */ async handleGetSpecsReadme() { try { const result = await this.figmaManager.requestSpecFile('get-specs-readme'); if (result.success && result.data) { return { content: [ { type: "text", text: result.data.content, }, ], }; } else { return { content: [ { type: "text", text: `Error fetching README: ${result.error || 'Unknown error'}`, }, ], }; } } catch (error) { return { content: [ { type: "text", text: `Error requesting README: ${error.message}`, }, ], }; } } /** * Handle get spec files manifest tool call */ async handleGetSpecFilesManifest() { try { const result = await this.figmaManager.requestSpecFile('get-spec-files-manifest'); if (result.success && result.data) { return { content: [ { type: "text", text: result.data.content, }, ], }; } else { return { content: [ { type: "text", text: `Error fetching manifest: ${result.error || 'Unknown error'}`, }, ], }; } } catch (error) { return { content: [ { type: "text", text: `Error requesting manifest: ${error.message}`, }, ], }; } } /** * Handle get a spec file tool call */ async handleGetASpecFile(args) { try { const { file_name } = args; if (!file_name) { return { content: [ { type: "text", text: "Error: file_name parameter is required", }, ], }; } const result = await this.figmaManager.requestSpecFile('get-a-spec-file', file_name); if (result.success && result.data) { return { content: [ { type: "text", text: result.data.content, }, ], }; } else { return { content: [ { type: "text", text: `Error fetching file '${file_name}': ${result.error || 'Unknown error'}`, }, ], }; } } catch (error) { return { content: [ { type: "text", text: `Error requesting file: ${error.message}`, }, ], }; } } /** * Handle get component screenshot tool call * Returns visual screenshot of a component for reference */ /** * Handle get page thumbnail tool call * Returns thumbnail image of the current page/screen from plugin's preview files */ async handleGetPageThumbnail(args) { try { const result = await this.figmaManager.requestSpecFile('get-page-thumbnail'); if (result.success && result.data) { // Check if response contains image data if (result.data.image_data && result.data.mime_type) { return { content: [ { type: "text", text: "Page thumbnail from Figma design:", }, { type: "image", data: result.data.image_data, mimeType: result.data.mime_type, }, ], }; } else { return { content: [ { type: "text", text: result.data.content || "Page thumbnail is not available as image data", }, ], }; } } else { return { content: [ { type: "text", text: `Error fetching page thumbnail: ${result.error || 'Unknown error'}`, }, ], }; } } catch (error) { return { content: [ { type: "text", text: `Error requesting page thumbnail: ${error.message}`, }, ], }; } } }