Skip to main content
Glama

Lighthouse MCP

performance.ts10.6 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { basicAuditSchema, coreWebVitalsSchema, compareDevicesSchema, performanceBudgetSchema, lcpOpportunitiesSchema, } from "../schemas"; import { getPerformanceScore, getCoreWebVitals, compareMobileDesktop, checkPerformanceBudget, getLcpOpportunities, } from "../lighthouse-performance"; interface StructuredResponse { summary: string; data: Record<string, unknown>; recommendations?: string[]; } function createStructuredPerformance( type: string, url: string, device: string, data: Record<string, unknown>, recommendations?: string[], ): StructuredResponse { return { summary: `${type} analysis for ${url} on ${device}`, data, ...(recommendations && { recommendations }), }; } export function registerPerformanceTools(server: McpServer) { server.tool( "get_performance_score", "Get the performance score for a website", basicAuditSchema, async ({ url, device }) => { try { const result = await getPerformanceScore(url, device); const structuredResult = createStructuredPerformance( "Performance Score", result.url, result.device, { performanceScore: result.performanceScore, metrics: Object.fromEntries( Object.entries(result.metrics).map(([key, metric]) => [ key, { title: metric.title, value: metric.displayValue, score: metric.score, }, ]), ), fetchTime: result.fetchTime, }, [ "Focus on Core Web Vitals improvements", "Optimize largest contentful paint for better user experience", "Reduce total blocking time to improve interactivity", ], ); return { content: [ { type: "text" as const, text: JSON.stringify(structuredResult, null, 2), }, ], }; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : String(error); return { content: [ { type: "text" as const, text: JSON.stringify( { error: "Performance analysis failed", url, device: device || "desktop", message: errorMessage, }, null, 2, ), }, ], isError: true, }; } }, ); server.tool( "get_core_web_vitals", "Get Core Web Vitals metrics for a website", coreWebVitalsSchema, async ({ url, device, includeDetails, threshold }) => { try { const result = await getCoreWebVitals(url, device, threshold); const structuredResult = createStructuredPerformance( "Core Web Vitals", result.url, result.device, { coreWebVitals: Object.fromEntries( Object.entries(result.coreWebVitals).map(([key, metric]) => [ key, { title: metric?.title || key.toUpperCase(), value: metric?.displayValue || "N/A", score: metric?.score, }, ]), ), thresholdResults: result.thresholdResults || {}, fetchTime: result.fetchTime, includeDetails, }, [ "Optimize Largest Contentful Paint (LCP) < 2.5s", "Minimize First Input Delay (FID) < 100ms", "Reduce Cumulative Layout Shift (CLS) < 0.1", ], ); return { content: [ { type: "text" as const, text: JSON.stringify(structuredResult, null, 2), }, ], }; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : String(error); return { content: [ { type: "text" as const, text: JSON.stringify( { error: "Core Web Vitals analysis failed", url, device: device || "desktop", message: errorMessage, }, null, 2, ), }, ], isError: true, }; } }, ); server.tool( "compare_mobile_desktop", "Compare website performance between mobile and desktop devices", compareDevicesSchema, async ({ url, categories, throttling, includeDetails }) => { try { const result = await compareMobileDesktop(url, categories, throttling); const structuredResult = createStructuredPerformance( "Mobile vs Desktop Comparison", result.url, "mobile + desktop", { differences: Object.fromEntries( Object.entries(result.differences).map(([category, diff]) => [ category, { mobile: diff.mobile, desktop: diff.desktop, difference: diff.difference, better: diff.difference > 0 ? "desktop" : "mobile", }, ]), ), includeDetails, }, [ "Mobile performance typically requires more optimization", "Focus on image optimization for mobile devices", "Consider implementing responsive design best practices", ], ); return { content: [ { type: "text" as const, text: JSON.stringify(structuredResult, null, 2), }, ], }; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : String(error); return { content: [ { type: "text" as const, text: JSON.stringify( { error: "Mobile vs Desktop comparison failed", url, message: errorMessage, }, null, 2, ), }, ], isError: true, }; } }, ); server.tool( "check_performance_budget", "Check if website performance meets specified budget thresholds", performanceBudgetSchema, async ({ url, device, budget }) => { try { const result = await checkPerformanceBudget(url, device, budget); const structuredResult = createStructuredPerformance( "Performance Budget Check", result.url, result.device, { overallPassed: result.overallPassed, results: Object.fromEntries( Object.entries(result.results).map(([metric, data]) => [ metric, { actual: data.actual, budget: data.budget, unit: data.unit, passed: data.passed, difference: typeof data.actual === "number" && typeof data.budget === "number" ? data.actual - data.budget : null, }, ]), ), fetchTime: result.fetchTime, }, result.overallPassed ? ["Performance budget requirements met"] : [ "Review failing metrics and optimize accordingly", "Consider adjusting budget thresholds if realistic", "Focus on the metrics with largest budget overruns", ], ); return { content: [ { type: "text" as const, text: JSON.stringify(structuredResult, null, 2), }, ], }; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : String(error); return { content: [ { type: "text" as const, text: JSON.stringify( { error: "Performance budget check failed", url, device: device || "desktop", message: errorMessage, }, null, 2, ), }, ], isError: true, }; } }, ); server.tool( "get_lcp_opportunities", "Get LCP optimization opportunities for a website", lcpOpportunitiesSchema, async ({ url, device, threshold, includeDetails }) => { try { const result = await getLcpOpportunities(url, device, threshold); const structuredResult = createStructuredPerformance( "LCP Optimization Opportunities", result.url, result.device, { lcpValue: result.lcpValue, threshold: result.threshold, needsImprovement: result.needsImprovement, opportunities: result.opportunities || [], fetchTime: result.fetchTime, includeDetails, }, !result.needsImprovement ? ["LCP performance is within acceptable range"] : [ "Optimize image loading and compression", "Implement resource hints (preload, prefetch)", "Reduce server response times", "Minimize render-blocking resources", ], ); return { content: [ { type: "text" as const, text: JSON.stringify(structuredResult, null, 2), }, ], }; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : String(error); return { content: [ { type: "text" as const, text: JSON.stringify( { error: "LCP opportunities analysis failed", url, device: device || "desktop", message: errorMessage, }, null, 2, ), }, ], isError: true, }; } }, ); }

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

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