@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
161 lines (160 loc) • 6.2 kB
JavaScript
;
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");
// Helper function to launch Chrome with standard configuration
async function launchChrome() {
return chromeLauncher.launch({
chromeFlags: lighthouse_constants_1.CHROME_FLAGS,
});
}
// 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) {
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,
};
}
// Helper function to run a raw Lighthouse audit
async function runRawLighthouseAudit(url, categories, device = "desktop", throttling = false) {
const chrome = await launchChrome();
try {
const options = buildLighthouseOptions(chrome.port, device, categories, throttling);
const runnerResult = (await (0, lighthouse_1.default)(url, options));
if (!runnerResult) {
throw new Error("Failed to run Lighthouse audit");
}
return runnerResult;
}
finally {
await chrome.kill();
}
}
// 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),
};
}