Skip to main content
Glama

Lighthouse MCP

by mizchi
cli.tsโ€ข6.37 kB
#!/usr/bin/env node import { parseArgs } from "node:util"; import { runLighthouse } from "./core/lighthouse.js"; import { performDeepAnalysis } from "./analyzers/deepAnalysis.js"; import { createDeepAnalysisTool } from "./mcp/deepAnalysisTool.js"; const helpText = ` Lighthouse MCP Usage: lhmcp <url> [options] lhmcp --mcp Start MCP server Options: -d, --device <device> Device type: mobile (default) or desktop -c, --categories <list> Categories to test (comma-separated) Default: performance,accessibility,best-practices,seo --chains Include critical chain analysis --unused Include unused code analysis --json Output raw JSON instead of formatted text --mcp Start as MCP server -h, --help Show this help message Examples: lhmcp https://example.com lhmcp https://example.com --device desktop lhmcp https://example.com --chains --unused lhmcp https://example.com --json > report.json lhmcp --mcp Start MCP server `; interface AnalysisOptions { format?: 'json' | 'text'; output?: string; deep?: boolean; device?: string; categories?: string[]; json?: boolean; chains?: boolean; unused?: boolean; } async function runAnalysis(url: string, options: AnalysisOptions) { console.log(`\n๐Ÿ” Analyzing ${url}...`); console.log(` Device: ${options.device || 'mobile'}`); console.log(` Categories: ${options.categories?.join(", ") || 'performance'}\n`); try { // Run Lighthouse const startTime = Date.now(); const result = await runLighthouse(url, { device: options.device as "mobile" | "desktop", categories: options.categories, userDataDir: ".lhdata/cli", timeout: 120000, // 2 minutes timeout for heavy sites }); if (!result.isOk()) { console.error(`โŒ Error: ${result.error.message}`); process.exit(1); } const report = result.value; const duration = Date.now() - startTime; console.log(`โœ… Analysis completed in ${(duration / 1000).toFixed(1)}s\n`); if (options.json) { // Output raw JSON const analysis = performDeepAnalysis(report); console.log(JSON.stringify(analysis, null, 2)); } else { // Use the deep analysis tool for formatted output const tool = await createDeepAnalysisTool(); const analysisResult = await tool.execute({ reportData: report, includeChains: options.chains, includeUnusedCode: options.unused, maxRecommendations: 10, }); // Extract text from the result let output = ""; if (Array.isArray(analysisResult.content)) { output = analysisResult.content .filter((item: any) => item.type === "text") .map((item: any) => item.text) .join("\n"); } else if (typeof analysisResult.content === "string") { output = analysisResult.content; } console.log(output); } // Summary if (!options.json) { console.log("\n" + "=".repeat(60)); console.log("๐Ÿ“Š Summary:"); console.log(` URL: ${report.finalUrl || report.requestedUrl}`); console.log( ` Performance Score: ${Math.round( (report.categories?.performance?.score || 0) * 100 )}/100` ); const audits = report.audits || {}; if (audits["largest-contentful-paint"]?.numericValue) { console.log( ` LCP: ${Math.round( audits["largest-contentful-paint"].numericValue )}ms` ); } if (audits["first-contentful-paint"]?.numericValue) { console.log( ` FCP: ${Math.round( audits["first-contentful-paint"].numericValue )}ms` ); } if (audits["cumulative-layout-shift"]?.numericValue !== undefined) { console.log( ` CLS: ${audits["cumulative-layout-shift"].numericValue.toFixed( 3 )}` ); } if (audits["total-blocking-time"]?.numericValue) { console.log( ` TBT: ${Math.round( audits["total-blocking-time"].numericValue )}ms` ); } } } catch (error) { console.error(`\nโŒ Unexpected error: ${error}`); process.exit(1); } } async function startMCPServer() { const { createMCPServer } = await import("./mcp/server.js"); console.log("๐Ÿš€ Starting MCP server..."); await createMCPServer(); } async function main() { // Parse command line arguments const { values, positionals } = parseArgs({ options: { device: { type: "string", short: "d", default: "mobile", }, categories: { type: "string", short: "c", default: "performance,accessibility,best-practices,seo", }, chains: { type: "boolean", default: false, }, unused: { type: "boolean", default: false, }, json: { type: "boolean", default: false, }, mcp: { type: "boolean", default: false, }, help: { type: "boolean", short: "h", default: false, }, }, allowPositionals: true, }); // Show help if (values.help || (positionals.length === 0 && !values.mcp)) { console.log(helpText); process.exit(0); } // Start MCP server if requested if (values.mcp) { await startMCPServer(); return; } // Get URL from positional argument const url = positionals[0]; if (!url) { console.error("Error: URL is required"); console.log(helpText); process.exit(1); } if (!url.startsWith("http://") && !url.startsWith("https://")) { console.error("Error: URL must start with http:// or https://"); process.exit(1); } // Process categories const categories = typeof values.categories === 'string' ? values.categories.split(",").filter(Boolean) : ["performance", "accessibility", "best-practices", "seo"]; // Run analysis await runAnalysis(url, { device: values.device || "mobile", categories, chains: values.chains, unused: values.unused, json: values.json, }); } // Run the CLI main().catch((error) => { console.error(error); process.exit(1); });

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/mizchi/lighthouse-mcp'

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