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 +145 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +258 -0
- package/package.json +44 -0
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)
|
package/build/index.d.ts
ADDED
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
|
+
}
|