UNPKG

@danielsogl/lighthouse-mcp

Version:

A comprehensive Model Context Protocol (MCP) server that provides web performance auditing, accessibility testing, SEO analysis, security assessment, and Core Web Vitals monitoring using Google Lighthouse. Enables LLMs and AI agents to perform detailed we

192 lines (191 loc) 7.42 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.launchChrome = launchChrome; exports.getScreenEmulation = getScreenEmulation; exports.buildLighthouseOptions = buildLighthouseOptions; exports.runRawLighthouseAudit = runRawLighthouseAudit; exports.filterAuditsByCategory = filterAuditsByCategory; exports.formatCategoryScores = formatCategoryScores; exports.extractKeyMetrics = extractKeyMetrics; exports.runLighthouseAudit = runLighthouseAudit; exports.getDetailedAuditResults = getDetailedAuditResults; const lighthouse_1 = __importDefault(require("lighthouse")); const chromeLauncher = __importStar(require("chrome-launcher")); const lighthouse_constants_1 = require("./lighthouse-constants"); const chrome_config_1 = require("./chrome-config"); let remoteAuditLock = Promise.resolve(); async function withRemoteDebuggingLock(runAudit) { const previous = remoteAuditLock.catch(() => undefined); let release; const current = new Promise((resolve) => { release = resolve; }); remoteAuditLock = previous.then(() => current); await previous; try { return await runAudit(); } finally { release?.(); } } // Helper function to launch Chrome with standard configuration async function launchChrome() { return chromeLauncher.launch((0, chrome_config_1.getChromeLaunchOptions)()); } // Helper function to get screen emulation settings function getScreenEmulation(device) { const dimensions = lighthouse_constants_1.SCREEN_DIMENSIONS[device]; return { mobile: device !== "desktop", width: dimensions.width, height: dimensions.height, deviceScaleFactor: 1, disabled: false, }; } // Helper function to build Lighthouse options function buildLighthouseOptions(port, device, categories, throttling = false, disableStorageReset = false) { return { logLevel: "info", output: "json", onlyCategories: categories, port, formFactor: device, screenEmulation: getScreenEmulation(device), throttling: throttling ? lighthouse_constants_1.THROTTLING_CONFIG.enabled : lighthouse_constants_1.THROTTLING_CONFIG.disabled, ...(disableStorageReset ? { disableStorageReset: true } : {}), }; } // Helper function to run a raw Lighthouse audit async function runRawLighthouseAudit(url, categories, device = "desktop", throttling = false) { const chromeConfig = (0, chrome_config_1.getChromeLaunchConfig)(); const { remoteDebuggingPort } = chromeConfig; const disableStorageReset = (0, chrome_config_1.isProfileConfig)(chromeConfig); const runAudit = async () => { const chrome = remoteDebuggingPort ? null : await launchChrome(); const port = remoteDebuggingPort ?? chrome?.port; try { if (!port) { throw new Error("Failed to resolve Chrome debugging port"); } const options = buildLighthouseOptions(port, device, categories, throttling, disableStorageReset); const runnerResult = (await (0, lighthouse_1.default)(url, options)); if (!runnerResult) { throw new Error("Failed to run Lighthouse audit"); } return runnerResult; } finally { if (chrome) { await chrome.kill(); } } }; if (remoteDebuggingPort) { return withRemoteDebuggingLock(runAudit); } return runAudit(); } // Helper function to filter audits by category function filterAuditsByCategory(lhr, categoryKey) { return Object.entries(lhr.audits) .filter(([key]) => lhr.categories[categoryKey]?.auditRefs?.some((ref) => ref.id === key)) .map(([key, audit]) => ({ id: key, title: audit.title, description: audit.description, score: audit.score, scoreDisplayMode: audit.scoreDisplayMode, displayValue: audit.displayValue, })); } // Helper function to format category scores from LHR function formatCategoryScores(lhr) { const auditCategories = {}; for (const [key, category] of Object.entries(lhr.categories)) { auditCategories[key] = { title: category.title, score: Math.round((category.score || 0) * 100), description: category.description, }; } return auditCategories; } // Helper function to extract key metrics from LHR function extractKeyMetrics(lhr) { const metrics = {}; if (lhr.audits) { for (const metric of lighthouse_constants_1.KEY_METRICS) { const audit = lhr.audits[metric]; if (audit) { metrics[metric] = { title: audit.title, value: audit.numericValue || 0, displayValue: audit.displayValue || "N/A", score: audit.score !== null ? Math.round((audit.score || 0) * 100) : null, }; } } } return metrics; } // Main function to run Lighthouse audit with formatted results async function runLighthouseAudit(url, categories, device = "desktop", throttling = false) { const runnerResult = await runRawLighthouseAudit(url, categories, device, throttling); const { lhr } = runnerResult; return { url: lhr.finalDisplayedUrl, fetchTime: lhr.fetchTime, version: lhr.lighthouseVersion, userAgent: lhr.userAgent, device, categories: formatCategoryScores(lhr), metrics: extractKeyMetrics(lhr), }; } // Helper function to get detailed audit results for a category async function getDetailedAuditResults(url, category, device) { const runnerResult = await runRawLighthouseAudit(url, [category], device); const { lhr } = runnerResult; return { lhr, audits: filterAuditsByCategory(lhr, category), }; }