export_report
Generate a standalone HTML report with all UI audit findings. Runs screenshot, accessibility, performance, and code analysis, outputting a shareable file with zero external dependencies.
Instructions
Generate a standalone HTML report file with all audit findings embedded. Runs the full review pipeline (screenshot, accessibility, performance, code analysis) and outputs a beautiful, shareable HTML file with zero external dependencies.
Use this when the user wants a downloadable/shareable report of their UI review.
This tool is FREE — runs entirely within Claude Code.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | URL of the running application (e.g., http://localhost:3000) | |
| codeDirectory | Yes | Absolute path to the frontend source directory (e.g., /Users/me/project/src) | |
| outputPath | No | Output file path for the HTML report (defaults to ./uimax-report.html) |
Implementation Reference
- src/server.ts:295-355 (registration)The MCP tool registration for 'export_report'. Defines the schema (url, codeDirectory, outputPath) and the handler callback that orchestrates the full review and HTML report generation.
server.tool( "export_report", `Generate a standalone HTML report file with all audit findings embedded. Runs the full review pipeline (screenshot, accessibility, performance, code analysis) and outputs a beautiful, shareable HTML file with zero external dependencies. Use this when the user wants a downloadable/shareable report of their UI review. This tool is FREE — runs entirely within Claude Code.`, { url: z.string().url().describe("URL of the running application (e.g., http://localhost:3000)"), codeDirectory: z.string().describe("Absolute path to the frontend source directory (e.g., /Users/me/project/src)"), outputPath: z.string().optional().describe("Output file path for the HTML report (defaults to ./uimax-report.html)"), }, async ({ url, codeDirectory, outputPath }) => { try { const resolvedPath = resolve(outputPath ?? "./uimax-report.html"); // Run the full audit pipeline const reviewData = await runFullReview(url, codeDirectory); // Generate the self-contained HTML report const html = generateHtmlReport(reviewData); // Write to disk await writeFile(resolvedPath, html, "utf-8"); const violationCount = reviewData.accessibility.violations.length; const findingCount = reviewData.codeAnalysis.findings.length; const totalIssues = violationCount + findingCount; return { content: [ { type: "text" as const, text: [ `# UIMax Report Exported`, ``, `**File:** ${resolvedPath}`, `**URL:** ${url}`, `**Timestamp:** ${reviewData.timestamp}`, ``, `## Summary`, `- Accessibility violations: ${violationCount}`, `- Code findings: ${findingCount}`, `- Total issues: ${totalIssues}`, `- Load time: ${reviewData.performance.loadTime.toFixed(0)}ms`, `- Files analyzed: ${reviewData.codeAnalysis.totalFiles}`, ``, `The HTML report is self-contained with all CSS inline and the screenshot embedded as base64. Open it in any browser to view or share.`, ].join("\n"), }, ], }; } catch (error) { const message = error instanceof Error ? error.message : String(error); return { content: [{ type: "text" as const, text: `Report export failed: ${message}` }], isError: true, }; } } ); - src/server.ts:307-354 (handler)The handler logic for export_report. It runs the full review pipeline via runFullReview, generates a self-contained HTML report via generateHtmlReport, and writes it to disk.
async ({ url, codeDirectory, outputPath }) => { try { const resolvedPath = resolve(outputPath ?? "./uimax-report.html"); // Run the full audit pipeline const reviewData = await runFullReview(url, codeDirectory); // Generate the self-contained HTML report const html = generateHtmlReport(reviewData); // Write to disk await writeFile(resolvedPath, html, "utf-8"); const violationCount = reviewData.accessibility.violations.length; const findingCount = reviewData.codeAnalysis.findings.length; const totalIssues = violationCount + findingCount; return { content: [ { type: "text" as const, text: [ `# UIMax Report Exported`, ``, `**File:** ${resolvedPath}`, `**URL:** ${url}`, `**Timestamp:** ${reviewData.timestamp}`, ``, `## Summary`, `- Accessibility violations: ${violationCount}`, `- Code findings: ${findingCount}`, `- Total issues: ${totalIssues}`, `- Load time: ${reviewData.performance.loadTime.toFixed(0)}ms`, `- Files analyzed: ${reviewData.codeAnalysis.totalFiles}`, ``, `The HTML report is self-contained with all CSS inline and the screenshot embedded as base64. Open it in any browser to view or share.`, ].join("\n"), }, ], }; } catch (error) { const message = error instanceof Error ? error.message : String(error); return { content: [{ type: "text" as const, text: `Report export failed: ${message}` }], isError: true, }; } } - src/tools/html-report.ts:984-1010 (helper)The generateHtmlReport function in html-report.ts builds the complete standalone HTML report with inline CSS, embedded base64 screenshot, and all audit sections (grades, summary cards, accessibility, performance, SEO, code analysis).
export function generateHtmlReport(data: FullReviewResult): string { const title = `UIMax Report — ${data.url}`; return `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>${escapeHtml(title)}</title> <style>${generateStyles()}</style> </head> <body> <div class="container"> ${buildHeader(data)} ${buildGradeCards(data)} ${buildSummaryCards(data)} ${buildScreenshotSection(data)} ${buildAccessibilitySection(data)} ${buildPerformanceSection(data.performance)} ${buildSeoSection(data)} ${buildCodeAnalysisSection(data)} ${buildSeveritySummary(data)} ${buildFooter()} </div> </body> </html>`; } - src/tools/full-review.ts:31-103 (helper)The runFullReview function orchestrates the full audit pipeline: screenshot, accessibility, performance, code analysis, Lighthouse (optional), and SEO (optional). Returns a FullReviewResult used by the export_report handler.
export async function runFullReview( url: string, codeDirectory: string, viewport?: { width: number; height: number } ): Promise<FullReviewResult> { const width = viewport?.width ?? 1440; const height = viewport?.height ?? 900; // Run screenshot first (needed for visual review) const screenshot = await captureScreenshot({ url, width, height, fullPage: true, delay: 1500, deviceScaleFactor: 2, }); // Run remaining audits concurrently (Lighthouse + SEO are optional/safe) const [accessibility, performance, codeAnalysis, lighthouseOutcome, seoResult] = await Promise.all([ runAccessibilityAudit(url), measurePerformance(url), analyzeCode(codeDirectory), runLighthouseSafe(url), runSeoSafe(url), ]); // Count code findings by severity const codeFindings = countCodeFindingsBySeverity(codeAnalysis.findings); // Compute letter grades for each section const grades = computeSectionGrades({ lighthouseScores: lighthouseOutcome ? { performance: lighthouseOutcome.scores.performance, accessibility: lighthouseOutcome.scores.accessibility, bestPractices: lighthouseOutcome.scores.bestPractices, seo: lighthouseOutcome.scores.seo, } : null, accessibilityViolations: accessibility.violations.length, accessibilityPasses: accessibility.passes, performanceMetrics: { fcp: performance.firstContentfulPaint, lcp: performance.largestContentfulPaint, cls: performance.cumulativeLayoutShift, tbt: performance.totalBlockingTime, }, codeFindings, totalFiles: codeAnalysis.totalFiles, }); // If we have a dedicated SEO score, update the SEO grade const seoGrade = seoResult ? { ...grades.seo, score: seoResult.score } : grades.seo; const finalGrades = { ...grades, seo: seoGrade }; return { url, codeDirectory, timestamp: new Date().toISOString(), screenshot, accessibility, performance, codeAnalysis, lighthouse: lighthouseOutcome ?? undefined, seo: seoResult ?? undefined, grades: finalGrades, }; } - src/server.ts:302-306 (schema)Zod schema for the export_report tool: requires url and codeDirectory strings, with an optional outputPath for the generated HTML file.
{ url: z.string().url().describe("URL of the running application (e.g., http://localhost:3000)"), codeDirectory: z.string().describe("Absolute path to the frontend source directory (e.g., /Users/me/project/src)"), outputPath: z.string().optional().describe("Output file path for the HTML report (defaults to ./uimax-report.html)"), },