lighthouse-mcp 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,145 @@
1
+ # Lighthouse MCP Server
2
+
3
+ An MCP server that wraps around Google's Lighthouse tool to help measure various performance metrics for web pages.
4
+
5
+ ## Features
6
+
7
+ - Run comprehensive Lighthouse audits on any URL
8
+ - Get performance scores and metrics
9
+ - Configure device emulation (mobile/desktop)
10
+ - Control network throttling
11
+ - Select specific audit categories
12
+
13
+ ## Installation
14
+
15
+ ### Option 1: Using npx (Recommended)
16
+
17
+ You can run the tool directly using npx without installation:
18
+
19
+ ```bash
20
+ npx lighthouse-mcp
21
+ ```
22
+
23
+ ### Option 2: Global Installation
24
+
25
+ Install the package globally:
26
+
27
+ ```bash
28
+ npm install -g lighthouse-mcp
29
+ ```
30
+
31
+ Then run it:
32
+
33
+ ```bash
34
+ lighthouse-mcp
35
+ ```
36
+
37
+ ### Option 3: Local Development
38
+
39
+ 1. Clone this repository
40
+ 2. Install dependencies:
41
+ ```bash
42
+ npm install
43
+ ```
44
+ 3. Build the project:
45
+ ```bash
46
+ npm run build
47
+ ```
48
+ 4. Run the server:
49
+ ```bash
50
+ npm start
51
+ ```
52
+
53
+ ## MCP Configuration
54
+
55
+ ### When installed via npm (global or npx)
56
+
57
+ Add the following to your MCP settings configuration file:
58
+
59
+ ```json
60
+ {
61
+ "mcpServers": {
62
+ "lighthouse": {
63
+ "command": "npx",
64
+ "args": ["lighthouse-mcp"],
65
+ "disabled": false,
66
+ "autoApprove": []
67
+ }
68
+ }
69
+ }
70
+ ```
71
+
72
+ ### When using local development version
73
+
74
+ Add the following to your MCP settings configuration file:
75
+
76
+ ```json
77
+ {
78
+ "mcpServers": {
79
+ "lighthouse": {
80
+ "command": "node",
81
+ "args": ["/absolute/path/to/lighthouse-mcp/build/index.js"],
82
+ "disabled": false,
83
+ "autoApprove": []
84
+ }
85
+ }
86
+ }
87
+ ```
88
+
89
+ Replace `/absolute/path/to/lighthouse-mcp` with the actual path to this project.
90
+
91
+ ## Available Tools
92
+
93
+ ### run_audit
94
+
95
+ Run a comprehensive Lighthouse audit on a URL.
96
+
97
+ **Parameters:**
98
+ - `url` (required): The URL to audit
99
+ - `categories` (optional): Array of categories to audit (defaults to all)
100
+ - Options: "performance", "accessibility", "best-practices", "seo", "pwa"
101
+ - `device` (optional): Device to emulate (defaults to "mobile")
102
+ - Options: "mobile", "desktop"
103
+ - `throttling` (optional): Whether to apply network throttling (defaults to true)
104
+
105
+ **Example:**
106
+ ```json
107
+ {
108
+ "url": "https://example.com",
109
+ "categories": ["performance", "accessibility"],
110
+ "device": "desktop",
111
+ "throttling": false
112
+ }
113
+ ```
114
+
115
+ ### get_performance_score
116
+
117
+ Get just the performance score for a URL.
118
+
119
+ **Parameters:**
120
+ - `url` (required): The URL to audit
121
+ - `device` (optional): Device to emulate (defaults to "mobile")
122
+ - Options: "mobile", "desktop"
123
+
124
+ **Example:**
125
+ ```json
126
+ {
127
+ "url": "https://example.com",
128
+ "device": "mobile"
129
+ }
130
+ ```
131
+
132
+ ## Example Usage
133
+
134
+ Once the MCP server is configured, you can use it with Claude:
135
+
136
+ ```
137
+ What's the performance score for example.com?
138
+ ```
139
+
140
+ Claude will use the `get_performance_score` tool to analyze the website and return the results.
141
+
142
+ ## Requirements
143
+
144
+ - Node.js 16+
145
+ - Chrome/Chromium browser (for Lighthouse)
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/build/index.js ADDED
@@ -0,0 +1,258 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js';
5
+ import lighthouse from 'lighthouse';
6
+ import * as chromeLauncher from 'chrome-launcher';
7
+ const isValidAuditArgs = (args) => {
8
+ return (typeof args === 'object' &&
9
+ args !== null &&
10
+ typeof args.url === 'string' &&
11
+ (args.categories === undefined ||
12
+ (Array.isArray(args.categories) &&
13
+ args.categories.every((cat) => typeof cat === 'string'))) &&
14
+ (args.device === undefined ||
15
+ args.device === 'mobile' ||
16
+ args.device === 'desktop') &&
17
+ (args.throttling === undefined || typeof args.throttling === 'boolean'));
18
+ };
19
+ class LighthouseServer {
20
+ constructor() {
21
+ this.server = new Server({
22
+ name: 'lighthouse-mcp',
23
+ version: '0.1.0',
24
+ }, {
25
+ capabilities: {
26
+ tools: {},
27
+ },
28
+ });
29
+ this.setupToolHandlers();
30
+ // Error handling
31
+ this.server.onerror = (error) => console.error('[MCP Error]', error);
32
+ process.on('SIGINT', async () => {
33
+ await this.server.close();
34
+ process.exit(0);
35
+ });
36
+ }
37
+ setupToolHandlers() {
38
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
39
+ tools: [
40
+ {
41
+ name: 'run_audit',
42
+ description: 'Run a Lighthouse audit on a URL',
43
+ inputSchema: {
44
+ type: 'object',
45
+ properties: {
46
+ url: {
47
+ type: 'string',
48
+ description: 'URL to audit',
49
+ },
50
+ categories: {
51
+ type: 'array',
52
+ items: {
53
+ type: 'string',
54
+ enum: [
55
+ 'performance',
56
+ 'accessibility',
57
+ 'best-practices',
58
+ 'seo',
59
+ 'pwa',
60
+ ],
61
+ },
62
+ description: 'Categories to audit (defaults to all)',
63
+ },
64
+ device: {
65
+ type: 'string',
66
+ enum: ['mobile', 'desktop'],
67
+ description: 'Device to emulate (defaults to mobile)',
68
+ },
69
+ throttling: {
70
+ type: 'boolean',
71
+ description: 'Whether to apply network throttling (defaults to true)',
72
+ },
73
+ },
74
+ required: ['url'],
75
+ },
76
+ },
77
+ {
78
+ name: 'get_performance_score',
79
+ description: 'Get just the performance score for a URL',
80
+ inputSchema: {
81
+ type: 'object',
82
+ properties: {
83
+ url: {
84
+ type: 'string',
85
+ description: 'URL to audit',
86
+ },
87
+ device: {
88
+ type: 'string',
89
+ enum: ['mobile', 'desktop'],
90
+ description: 'Device to emulate (defaults to mobile)',
91
+ },
92
+ },
93
+ required: ['url'],
94
+ },
95
+ },
96
+ ],
97
+ }));
98
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
99
+ switch (request.params.name) {
100
+ case 'run_audit':
101
+ return this.handleRunAudit(request.params.arguments);
102
+ case 'get_performance_score':
103
+ return this.handleGetPerformanceScore(request.params.arguments);
104
+ default:
105
+ throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
106
+ }
107
+ });
108
+ }
109
+ async handleRunAudit(args) {
110
+ if (!isValidAuditArgs(args)) {
111
+ throw new McpError(ErrorCode.InvalidParams, 'Invalid audit arguments');
112
+ }
113
+ try {
114
+ const chrome = await chromeLauncher.launch({ chromeFlags: ['--headless'] });
115
+ const options = {
116
+ logLevel: 'info',
117
+ output: 'json',
118
+ onlyCategories: args.categories,
119
+ port: chrome.port,
120
+ formFactor: args.device || 'mobile',
121
+ screenEmulation: {
122
+ mobile: args.device !== 'desktop',
123
+ width: args.device === 'desktop' ? 1350 : 360,
124
+ height: args.device === 'desktop' ? 940 : 640,
125
+ deviceScaleFactor: 1,
126
+ disabled: false,
127
+ },
128
+ throttling: args.throttling !== false ? {
129
+ rttMs: 150,
130
+ throughputKbps: 1638.4,
131
+ cpuSlowdownMultiplier: 4,
132
+ } : {
133
+ rttMs: 0,
134
+ throughputKbps: 10 * 1024,
135
+ cpuSlowdownMultiplier: 1,
136
+ },
137
+ };
138
+ const runnerResult = await lighthouse(args.url, options);
139
+ await chrome.kill();
140
+ if (!runnerResult) {
141
+ throw new McpError(ErrorCode.InternalError, 'Failed to run Lighthouse audit');
142
+ }
143
+ const { lhr } = runnerResult;
144
+ // Format the results
145
+ const formattedResults = {
146
+ url: lhr.finalDisplayedUrl,
147
+ fetchTime: lhr.fetchTime,
148
+ version: lhr.lighthouseVersion,
149
+ userAgent: lhr.userAgent,
150
+ scores: {},
151
+ metrics: {},
152
+ };
153
+ // Add category scores
154
+ const scores = {};
155
+ for (const [key, category] of Object.entries(lhr.categories)) {
156
+ scores[key] = {
157
+ title: category.title,
158
+ score: category.score,
159
+ description: category.description,
160
+ };
161
+ }
162
+ formattedResults.scores = scores;
163
+ // Add key metrics
164
+ const metrics = {};
165
+ if (lhr.audits) {
166
+ const keyMetrics = [
167
+ 'first-contentful-paint',
168
+ 'largest-contentful-paint',
169
+ 'total-blocking-time',
170
+ 'cumulative-layout-shift',
171
+ 'speed-index',
172
+ 'interactive',
173
+ ];
174
+ for (const metric of keyMetrics) {
175
+ const audit = lhr.audits[metric];
176
+ if (audit) {
177
+ metrics[metric] = {
178
+ title: audit.title,
179
+ value: audit.numericValue,
180
+ displayValue: audit.displayValue,
181
+ score: audit.score,
182
+ };
183
+ }
184
+ }
185
+ }
186
+ formattedResults.metrics = metrics;
187
+ return {
188
+ content: [
189
+ {
190
+ type: 'text',
191
+ text: JSON.stringify(formattedResults, null, 2),
192
+ },
193
+ ],
194
+ };
195
+ }
196
+ catch (error) {
197
+ console.error('Lighthouse error:', error);
198
+ return {
199
+ content: [
200
+ {
201
+ type: 'text',
202
+ text: `Error running Lighthouse audit: ${error.message || error}`,
203
+ },
204
+ ],
205
+ isError: true,
206
+ };
207
+ }
208
+ }
209
+ async handleGetPerformanceScore(args) {
210
+ if (!isValidAuditArgs(args)) {
211
+ throw new McpError(ErrorCode.InvalidParams, 'Invalid performance score arguments');
212
+ }
213
+ try {
214
+ // Run a focused performance audit
215
+ const auditArgs = {
216
+ url: args.url,
217
+ categories: ['performance'],
218
+ device: args.device || 'mobile',
219
+ throttling: true,
220
+ };
221
+ const result = await this.handleRunAudit(auditArgs);
222
+ // Extract just the performance data
223
+ const resultData = JSON.parse(result.content[0].text);
224
+ const performanceData = {
225
+ url: resultData.url,
226
+ performanceScore: resultData.scores.performance.score,
227
+ metrics: resultData.metrics,
228
+ };
229
+ return {
230
+ content: [
231
+ {
232
+ type: 'text',
233
+ text: JSON.stringify(performanceData, null, 2),
234
+ },
235
+ ],
236
+ };
237
+ }
238
+ catch (error) {
239
+ console.error('Performance score error:', error);
240
+ return {
241
+ content: [
242
+ {
243
+ type: 'text',
244
+ text: `Error getting performance score: ${error.message || error}`,
245
+ },
246
+ ],
247
+ isError: true,
248
+ };
249
+ }
250
+ }
251
+ async run() {
252
+ const transport = new StdioServerTransport();
253
+ await this.server.connect(transport);
254
+ console.error('Lighthouse MCP server running on stdio');
255
+ }
256
+ }
257
+ const server = new LighthouseServer();
258
+ server.run().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "lighthouse-mcp",
3
+ "version": "0.1.1",
4
+ "description": "MCP server for Google Lighthouse performance metrics",
5
+ "type": "module",
6
+ "main": "build/index.js",
7
+ "bin": {
8
+ "lighthouse-mcp": "./build/index.js"
9
+ },
10
+ "files": [
11
+ "build",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc && chmod +x build/index.js",
16
+ "start": "node build/index.js",
17
+ "dev": "tsc -w",
18
+ "prepublishOnly": "npm run build"
19
+ },
20
+ "keywords": [
21
+ "lighthouse",
22
+ "performance",
23
+ "mcp",
24
+ "audit",
25
+ "web",
26
+ "metrics",
27
+ "claude"
28
+ ],
29
+ "author": "",
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": ""
34
+ },
35
+ "dependencies": {
36
+ "@modelcontextprotocol/sdk": "latest",
37
+ "lighthouse": "^11.0.0",
38
+ "chrome-launcher": "^0.15.2"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^20.4.5",
42
+ "typescript": "^5.1.6"
43
+ }
44
+ }