Chrome DevTools MCP Performance Analysis
This guide introduces how to use Chrome DevTools MCP to analyze and optimize web application performance.
Overview
Chrome DevTools MCP provides programmatic access to browser performance analysis tools, enabling the AI assistant to:
- Automate performance testing
- Analyze page load performance
- Identify performance bottlenecks
- Generate optimization suggestions
Configuration
1. Install Chrome DevTools MCP
bash
npm install -g chrome-devtools-mcp-server2. Configure ByteBuddy
json
{
"mcpServers": {
"chrome-devtools": {
"command": "node",
"args": ["chrome-devtools-mcp-server"],
"env": {
"CHROME_REMOTE_DEBUGGING_PORT": "9222",
"TARGET_URL": "http://localhost:3000"
}
}
}
}3. Start Chrome Remote Debugging
bash
# Start Chrome with remote debugging enabled
google-chrome --remote-debugging-port=9222 --disable-web-security
# Or use headless mode
google-chrome --headless --remote-debugging-port=9222Use Cases
Scenario 1: Performance Auditing
typescript
// Perform performance audit
const audit = await mcp.call("chrome.runLighthouse", {
url: "http://localhost:3000",
categories: ["performance", "accessibility", "best-practices"],
settings: {
throttling: {
rttMs: 100,
throughputKbps: 10000,
cpuSlowdownMultiplier: 2,
},
},
});
console.log(
`Performance Score: ${audit.lhr.categories.performance.score * 100}`,
);Scenario 2: Network Analysis
typescript
// Analyze network requests
const networkLogs = await mcp.call("chrome.getNetworkLogs", {
timeRange: {
start: Date.now() - 60000,
end: Date.now(),
},
});
// Identify slow requests
const slowRequests = networkLogs.filter((request) => request.duration > 1000);
console.log("Slow requests:", slowRequests);Scenario 3: Memory Analysis
typescript
// Check for memory leaks
const memorySnapshot = await mcp.call("chrome.takeHeapSnapshot", {
includeNodeId: true,
includeRetainedPaths: true,
});
// Analyze memory usage
const memoryAnalysis = await mcp.call("chrome.analyzeMemory", {
snapshot: memorySnapshot,
focusOnLeakedObjects: true,
});Performance Optimization Strategies
1. Automated Performance Monitoring
typescript
class PerformanceMonitor {
async auditPage(url: string) {
const audit = await mcp.call("chrome.runLighthouse", { url });
return {
performance: audit.lhr.categories.performance.score,
firstContentfulPaint:
audit.lhr.audits["first-contentful-paint"].numericValue,
largestContentfulPaint:
audit.lhr.audits["largest-contentful-paint"].numericValue,
cumulativeLayoutShift:
audit.lhr.audits["cumulative-layout-shift"].numericValue,
};
}
async generateReport(baseUrl: string, paths: string[]) {
const results = [];
for (const path of paths) {
const url = `${baseUrl}${path}`;
const metrics = await this.auditPage(url);
results.push({ url, ...metrics });
}
return this.generateOptimizationSuggestions(results);
}
}2. Continuous Performance Monitoring
yaml
# .github/workflows/performance.yml
name: Performance Audit
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
performance-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "18"
- name: Install dependencies
run: npm ci
- name: Build application
run: npm run build
- name: Start application
run: npm run start &
- name: Wait for app to be ready
run: sleep 30
- name: Run performance audit
run: |
bytebuddy --mcp chrome-devtools --audit-performance \
--url http://localhost:3000 \
--output performance-report.json
- name: Check performance threshold
run: |
node scripts/check-performance-threshold.js3. Performance Regression Detection
typescript
// Performance threshold checking
const performanceThresholds = {
performanceScore: 0.9,
firstContentfulPaint: 1500,
largestContentfulPaint: 2500,
cumulativeLayoutShift: 0.1,
};
async function checkPerformanceRegression() {
const currentMetrics = await getCurrentPerformanceMetrics();
const baselineMetrics = await getBaselineMetrics();
const regressions = [];
for (const [metric, threshold] of Object.entries(performanceThresholds)) {
const currentValue = currentMetrics[metric];
const baselineValue = baselineMetrics[metric];
if (currentValue < baselineValue * 0.95) {
regressions.push({
metric,
current: currentValue,
baseline: baselineValue,
regression: baselineValue - currentValue,
});
}
}
return regressions;
}Advanced Analysis
1. Custom Performance Metrics
typescript
// Define custom metrics
const customMetrics = {
timeToInteractive: {
measurement: () => {
return new Promise((resolve) => {
const observer = new PerformanceObserver((list) => {
const entries = list.getEntries();
const tti = entries.find(
(entry) => entry.name === "time-to-interactive",
);
if (tti) {
resolve(tti.startTime);
}
});
observer.observe({ entryTypes: ["measure"] });
});
},
},
renderBlockingTime: {
measurement: async () => {
const navigation = performance.getEntriesByType("navigation")[0];
const domContentLoaded = navigation.domContentLoadedEventStart;
const firstPaint = performance.getEntriesByType("paint")[0].startTime;
return domContentLoaded - firstPaint;
},
},
};2. Core Web Vitals Monitoring
typescript
// Core Web Vitals monitoring
class CoreWebVitalsMonitor {
constructor() {
this.metrics = {};
}
startMonitoring() {
// LCP
new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
this.metrics.largestContentfulPaint = lastEntry.startTime;
}).observe({ entryTypes: ["largest-contentful-paint"] });
// CLS
let clsValue = 0;
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) {
clsValue += entry.value;
}
}
this.metrics.cumulativeLayoutShift = clsValue;
}).observe({ entryTypes: ["layout-shift"] });
// FID (requires user interaction)
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
this.metrics.firstInputDelay = entry.processingStart - entry.startTime;
}
}).observe({ entryTypes: ["first-input"] });
}
getMetrics() {
return this.metrics;
}
}Optimization Suggestion Generation
typescript
// Auto-generate optimization suggestions
class PerformanceOptimizer {
generateOptimizationSuggestions(auditResults) {
const suggestions = [];
// Suggestions based on performance score
if (auditResults.performance < 0.9) {
suggestions.push({
category: "Performance",
issue: "Performance score is below 90%",
suggestions: [
"Optimize image resources",
"Reduce JavaScript bundle size",
"Enable resource compression",
],
});
}
// Suggestions based on specific metrics
if (auditResults.firstContentfulPaint > 1500) {
suggestions.push({
category: "First Contentful Paint",
issue: `FCP is ${auditResults.firstContentfulPaint}ms (threshold: 1500ms)`,
suggestions: [
"Inline critical CSS",
"Preload critical resources",
"Optimize server response time",
],
});
}
// Suggestions based on network requests
if (auditResults.slowRequests.length > 0) {
suggestions.push({
category: "Network",
issue: `${auditResults.slowRequests.length} slow requests detected`,
suggestions: [
"Implement request caching",
"Use CDN",
"Optimize API response time",
],
});
}
return suggestions;
}
}Troubleshooting
Common Issues
Chrome Remote Debugging Cannot Connect
bash
# Check if port is open
netstat -tlnp | grep 9222
# Restart Chrome
pkill chrome
google-chrome --remote-debugging-port=9222Performance Audit Fails
typescript
// Add retry mechanism
async function runAuditWithRetry(url, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await mcp.call("chrome.runLighthouse", { url });
} catch (error) {
if (i === maxRetries - 1) throw error;
await new Promise((resolve) => setTimeout(resolve, 2000));
}
}
}Memory Snapshot Too Large
json
{
"chrome-devtools": {
"env": {
"HEAP_SNAPSHOT_COMPRESSION": "gzip",
"MAX_SNAPSHOT_SIZE": "50MB"
}
}
}With Chrome DevTools MCP, ByteBuddy can provide in-depth performance analysis and optimization suggestions, helping developers build faster web applications.