similarity-figma
Compare Figma design prototypes with generated code page screenshots to verify visual consistency and ensure accurate implementation.
Instructions
获取Figma原型图,请你结合项目源码并通过原型图与生成的代码页面的截图进行相似性比对
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| fileKey | Yes | The key of the Figma file to fetch, often found in a provided URL like figma.com/(file|design)/<fileKey>/... | |
| nodeId | No | The ID of the node to fetch, often found as URL parameter node-id=<nodeId>, always use if provided | |
| url | Yes | 当前项目代码页面的URL地址,注意不是figma网址 |
Implementation Reference
- src/services/similarity/index.ts:51-141 (handler)The execute function that implements the core logic of the 'similarity-figma' tool: fetches Figma image using fileKey/nodeId, screenshots the project URL, converts to image content using imageContent, and bundles with a prompt for similarity analysis.execute: async ({ url, fileKey, nodeId, }, { session, }: { session: any }) => { try { const figmaService = this.figmaToolsCore.figmaService const screenshotService = new ScreenshotService() console.log(`Processing similarity check for URL: ${url}, Figma fileKey: ${fileKey}, nodeId: ${nodeId || 'not provided'}`) // 分步执行并添加错误处理 let figmaImg try { figmaImg = await figmaService.getImageData(fileKey, nodeId as string) console.log('Successfully fetched Figma image') } catch (figmaError) { Logger.error('Failed to fetch Figma image:', figmaError) return { isError: true, content: [{ type: 'text', text: `Error fetching Figma image: ${figmaError instanceof Error ? figmaError.message : JSON.stringify(figmaError)}` }], } } let screenshotImg try { screenshotImg = await screenshotService.takeScreenshot(url) console.log('Successfully captured screenshot') } catch (screenshotError) { Logger.error('Failed to take screenshot:', screenshotError) return { isError: true, content: [{ type: 'text', text: `Error taking screenshot of ${url}: ${screenshotError instanceof Error ? screenshotError.message : JSON.stringify(screenshotError)}` }], } } // 处理图片转换,添加错误处理 let figmaImgData let screenshotImgData try { figmaImgData = await imageContent({ url: figmaImg, }) console.log('Successfully converted Figma image') } catch (figmaConvertError) { Logger.error('Failed to convert Figma image:', figmaConvertError) return { isError: true, content: [{ type: 'text', text: `Error converting Figma image: ${figmaConvertError instanceof Error ? figmaConvertError.message : JSON.stringify(figmaConvertError)}` }], } } try { screenshotImgData = await imageContent({ buffer: screenshotImg, }) console.log('Successfully converted screenshot image') } catch (screenshotConvertError) { Logger.error('Failed to convert screenshot image:', screenshotConvertError) return { isError: true, content: [{ type: 'text', text: `Error converting screenshot image: ${screenshotConvertError instanceof Error ? screenshotConvertError.message : JSON.stringify(screenshotConvertError)}` }], } } // console.log('figmaImgData', figmaImgData) console.log('screenshotImgData', screenshotImgData) const prompt = similarityPrompt return { content: [ { type: 'text', text: prompt }, figmaImgData, screenshotImgData, ], } } catch (error) { const message = error instanceof Error ? error.message : JSON.stringify(error) Logger.error(`Error fetching file ${fileKey}:`, message) return { isError: true, content: [{ type: 'text', text: `Error fetching file: ${message}` }], } } },
- Zod schema defining the input parameters for the tool: url (project page URL), fileKey (Figma file key), nodeId (optional node ID).parameters: z.object({ url: z .string() .describe('当前项目代码页面的URL地址,注意不是figma网址'), fileKey: z .string() .describe( 'The key of the Figma file to fetch, often found in a provided URL like figma.com/(file|design)/<fileKey>/...', ), nodeId: z .string() .optional() .describe( 'The ID of the node to fetch, often found as URL parameter node-id=<nodeId>, always use if provided', ), }),
- src/services/similarity/index.ts:32-142 (registration)Registers the 'similarity-figma' tool using server.addTool(), including name, description, parameters schema, and execute handler.this.server.addTool({ name: 'similarity-figma', description: '获取Figma原型图,请你结合项目源码并通过原型图与生成的代码页面的截图进行相似性比对', parameters: z.object({ url: z .string() .describe('当前项目代码页面的URL地址,注意不是figma网址'), fileKey: z .string() .describe( 'The key of the Figma file to fetch, often found in a provided URL like figma.com/(file|design)/<fileKey>/...', ), nodeId: z .string() .optional() .describe( 'The ID of the node to fetch, often found as URL parameter node-id=<nodeId>, always use if provided', ), }), execute: async ({ url, fileKey, nodeId, }, { session, }: { session: any }) => { try { const figmaService = this.figmaToolsCore.figmaService const screenshotService = new ScreenshotService() console.log(`Processing similarity check for URL: ${url}, Figma fileKey: ${fileKey}, nodeId: ${nodeId || 'not provided'}`) // 分步执行并添加错误处理 let figmaImg try { figmaImg = await figmaService.getImageData(fileKey, nodeId as string) console.log('Successfully fetched Figma image') } catch (figmaError) { Logger.error('Failed to fetch Figma image:', figmaError) return { isError: true, content: [{ type: 'text', text: `Error fetching Figma image: ${figmaError instanceof Error ? figmaError.message : JSON.stringify(figmaError)}` }], } } let screenshotImg try { screenshotImg = await screenshotService.takeScreenshot(url) console.log('Successfully captured screenshot') } catch (screenshotError) { Logger.error('Failed to take screenshot:', screenshotError) return { isError: true, content: [{ type: 'text', text: `Error taking screenshot of ${url}: ${screenshotError instanceof Error ? screenshotError.message : JSON.stringify(screenshotError)}` }], } } // 处理图片转换,添加错误处理 let figmaImgData let screenshotImgData try { figmaImgData = await imageContent({ url: figmaImg, }) console.log('Successfully converted Figma image') } catch (figmaConvertError) { Logger.error('Failed to convert Figma image:', figmaConvertError) return { isError: true, content: [{ type: 'text', text: `Error converting Figma image: ${figmaConvertError instanceof Error ? figmaConvertError.message : JSON.stringify(figmaConvertError)}` }], } } try { screenshotImgData = await imageContent({ buffer: screenshotImg, }) console.log('Successfully converted screenshot image') } catch (screenshotConvertError) { Logger.error('Failed to convert screenshot image:', screenshotConvertError) return { isError: true, content: [{ type: 'text', text: `Error converting screenshot image: ${screenshotConvertError instanceof Error ? screenshotConvertError.message : JSON.stringify(screenshotConvertError)}` }], } } // console.log('figmaImgData', figmaImgData) console.log('screenshotImgData', screenshotImgData) const prompt = similarityPrompt return { content: [ { type: 'text', text: prompt }, figmaImgData, screenshotImgData, ], } } catch (error) { const message = error instanceof Error ? error.message : JSON.stringify(error) Logger.error(`Error fetching file ${fileKey}:`, message) return { isError: true, content: [{ type: 'text', text: `Error fetching file: ${message}` }], } } }, })
- src/server.ts:39-39 (registration)Top-level registration call in the main MCP server that invokes SimilarityTools.registerTools() to add the tool.this.similarityTools.registerTools()
- takeScreenshot method from ScreenshotService class, used in the handler to capture screenshot of the provided project URL using Puppeteer.async takeScreenshot(url: string, options?: { fileName?: string fullPage?: boolean width?: number height?: number timeout?: number }) { const browser = await puppeteer.launch({ headless: true, executablePath: await this.getChromeExecutablePath(), args: ['--no-sandbox', '--disable-setuid-sandbox'] }) try { // 创建新页面 const page = await browser.newPage() // 设置视口大小 await page.setViewport({ width: 375, height: 0, }) // 导航到指定URL,等待网络空闲 await page.goto(url, { timeout: options?.timeout || 30000, waitUntil: 'networkidle0', }) // 执行截图 const imageBuffer = await page.screenshot({ fullPage: options?.fullPage || false, }) // 将 Uint8Array 转换为 Buffer const buffer = Buffer.from(imageBuffer) // const imageBufferStr = buffer.toString('base64') // console.log('imageBufferStr', imageBufferStr) return buffer } finally { // 确保浏览器关闭 await browser.close() } }