541 lines
19 KiB
Markdown
541 lines
19 KiB
Markdown
---
|
|
name: chrome-devtools-mcp
|
|
description: Use when browsing web pages, extracting content from restricted sites (login walls, paywalls), debugging JS errors, analyzing network requests, or running performance audits via browser DevTools.
|
|
---
|
|
|
|
# Chrome DevTools MCP — Web Browsing & Debugging Skill
|
|
|
|
Operation guide for the `chrome-devtools-mcp` toolset covering web browsing, interactive debugging, content extraction, and performance analysis.
|
|
|
|
## When to Use
|
|
|
|
Use this skill when **any** of the following apply:
|
|
1. **Browsing** — need to navigate web pages, extract content, bypass login walls/paywalls
|
|
2. **Debugging** — need to inspect console errors, network requests, DOM elements, or page performance
|
|
3. **Content extraction** — need to extract article text from restricted pages (Zhihu, CSDN, etc.)
|
|
4. **Interaction** — need to fill forms, click elements, handle dialogs on web pages
|
|
5. **Performance** — need to run Lighthouse audits, trace performance, or capture heap snapshots
|
|
|
|
## Core Workflow
|
|
|
|
```
|
|
1. new_page(url) / navigate_page(url) → Open/navigate to page
|
|
2. wait_for(["keyword"]) → Wait for content to load
|
|
3. take_snapshot() → Get element structure (uid)
|
|
4. take_screenshot() → Confirm visual state
|
|
5. evaluate_script(() => ...) → Execute JS / extract data
|
|
6. list_console_messages() → Check console errors
|
|
```
|
|
|
|
## Key Capabilities
|
|
|
|
- **Bypass restrictions**: Remove login/paywall overlays, unlock copy restrictions, expand truncated articles
|
|
- **Debug JS errors**: List and inspect console messages, identify uncaught exceptions
|
|
- **Network analysis**: List network requests, inspect request/response bodies
|
|
- **DOM interaction**: Click, fill, type, hover, drag — all via accessibility tree (uid)
|
|
- **Performance**: Lighthouse audits, performance traces, memory heap snapshots
|
|
- **Device emulation**: Mobile viewport, user agent switching
|
|
|
|
---
|
|
|
|
# Part 1 — Browsing & Restriction Bypass
|
|
|
|
Based on `chrome-devtools-mcp` toolset for bypassing login walls, copy restrictions, and paywall overlays on sites like Zhihu, CSDN.
|
|
|
|
## Standard Browsing Flow
|
|
|
|
```
|
|
Step 1: new_page(url) → Open page
|
|
Step 2: wait_for(["keyword"]) → Wait for content load
|
|
Step 3: take_snapshot() → Get accessibility tree (text structure)
|
|
Step 4: take_screenshot() → Confirm visual state (optional)
|
|
Step 5: evaluate_script() → Extract specific data
|
|
```
|
|
|
|
## Restriction Bypass Guide
|
|
|
|
### 0. Standard Detect-Remove-Extract Pattern
|
|
|
|
```javascript
|
|
// Step 1: Detect
|
|
evaluate_script(() => {
|
|
JSON.stringify({
|
|
hasMask: !!document.querySelector('[class*="mask"], [class*="overlay"], [class*="passport"]'),
|
|
hasReadMore: !!document.querySelector('.btn-readmore, [class*="readmore"], [class*="expand"]'),
|
|
articleLen: document.querySelector('article')?.innerText.length || 0,
|
|
title: document.title
|
|
})
|
|
})
|
|
|
|
// Step 2: Remove mask
|
|
evaluate_script(() => {
|
|
document.querySelectorAll('[class*="mask"], [class*="overlay"], [class*="passport"], [class*="login"], [class*="modal"], .hide-article-box')
|
|
.forEach(el => el.remove());
|
|
document.body.style.overflow = 'auto';
|
|
document.body.style.position = '';
|
|
const a = document.querySelector('article');
|
|
if (a) { a.style.height = 'auto'; a.style.maxHeight = 'none'; }
|
|
})
|
|
|
|
// Step 3: Extract content
|
|
evaluate_script(() => {
|
|
const a = document.querySelector('article') || document.querySelector('[class*="content"]') || document.querySelector('[class*="article"]');
|
|
return a?.innerText || 'not found';
|
|
})
|
|
```
|
|
|
|
### 1. Bypass Login Wall / Paywall Overlay
|
|
|
|
```javascript
|
|
// Remove overlay elements
|
|
evaluate_script(() => {
|
|
document.querySelectorAll('.login-guard, .pay-wall, .modal-mask, [class*="mask"], [class*="overlay"]')
|
|
.forEach(el => el.remove());
|
|
})
|
|
```
|
|
|
|
```javascript
|
|
// Remove body scroll lock and show content
|
|
evaluate_script(() => {
|
|
document.body.style.overflow = 'auto';
|
|
document.querySelectorAll('.login-guard, .pay-wall, .sign-in, .modal, .overlay')
|
|
.forEach(el => el.remove());
|
|
// Restore hidden content
|
|
document.querySelectorAll('[class*="content"], [class*="article"], [class*="main"]')
|
|
.forEach(el => el.style.display = 'block');
|
|
})
|
|
```
|
|
|
|
### 2. Unlock Copy Restrictions
|
|
|
|
```javascript
|
|
evaluate_script(() => {
|
|
document.addEventListener('copy', e => e.stopPropagation(), true);
|
|
document.addEventListener('selectstart', e => e.stopPropagation(), true);
|
|
document.body.style.userSelect = 'auto';
|
|
document.querySelectorAll('*').forEach(el => el.style.userSelect = 'auto');
|
|
})
|
|
```
|
|
|
|
### 3. Extract Truncated Full Text
|
|
|
|
```javascript
|
|
// Standard flow: detect → remove mask → extract
|
|
evaluate_script(() => {
|
|
const hasMask = !!document.querySelector('[class*="mask"], [class*="overlay"], [class*="passport"]');
|
|
const hasReadMore = !!document.querySelector('.btn-readmore, [class*="readmore"], [class*="expand"]');
|
|
return JSON.stringify({hasMask, hasReadMore, articleLen: document.querySelector('article')?.innerText.length || 0});
|
|
})
|
|
|
|
// If read-more button exists, click it first
|
|
evaluate_script(() => {
|
|
const btn = [...document.querySelectorAll('button, a, span, div')]
|
|
.find(el => el.textContent.includes('展开阅读全文') || el.textContent.includes('全文'));
|
|
btn?.click();
|
|
})
|
|
```
|
|
|
|
```javascript
|
|
// Zhihu — expand full text
|
|
evaluate_script(() => {
|
|
const btn = [...document.querySelectorAll('button, a, span')]
|
|
.find(el => el.textContent.includes('展开阅读全文') || el.textContent.includes('全文'));
|
|
if (btn) btn.click();
|
|
})
|
|
```
|
|
|
|
```javascript
|
|
// CSDN — remove login overlay + extract full text (verified 2026)
|
|
evaluate_script(() => {
|
|
document.querySelectorAll('.mask, .mask-dark, .passport-login-tip-container, .passport-login-container, .passport-login-box, .passport-login-mark, .hide-article-box')
|
|
.forEach(el => el.remove());
|
|
document.body.style.overflow = 'auto';
|
|
document.body.style.position = '';
|
|
const article = document.querySelector('article') || document.querySelector('.article_content');
|
|
if (article) {
|
|
article.style.setProperty('height', 'auto', 'important');
|
|
article.style.setProperty('max-height', 'none', 'important');
|
|
}
|
|
})
|
|
|
|
// Extract content
|
|
evaluate_script(() => {
|
|
const art = document.querySelector('article') || document.querySelector('.article_content') || document.querySelector('#article_content');
|
|
return 'Title: ' + document.title + '\n\n' + art.innerText;
|
|
})
|
|
```
|
|
|
|
### 4. Extract Page Text
|
|
|
|
```javascript
|
|
// Get article plain text
|
|
evaluate_script(() => {
|
|
const article = document.querySelector('article') ||
|
|
document.querySelector('[class*="content"]') ||
|
|
document.querySelector('[class*="article"]') ||
|
|
document.querySelector('main');
|
|
return article ? article.innerText : document.body.innerText;
|
|
})
|
|
```
|
|
|
|
```javascript
|
|
// Get all page text (preserving structure)
|
|
evaluate_script(() => {
|
|
return [...document.querySelectorAll('h1, h2, h3, p, li, pre, code')]
|
|
.map(el => el.tagName + ': ' + el.innerText.trim())
|
|
.filter(s => s.length > 3)
|
|
.join('\n---\n');
|
|
})
|
|
```
|
|
|
|
### 5. Zhihu-Specific Bypass
|
|
|
|
```javascript
|
|
evaluate_script(() => {
|
|
// Close dialog
|
|
document.querySelector('.Modal-closeButton, button[class*="close"]')?.click();
|
|
document.querySelector('[class*="signIn"], [class*="Modal"]')?.remove();
|
|
// Expand all collapsed answers
|
|
document.querySelectorAll('.RichContent.is-collapsed').forEach(el => {
|
|
el.classList.remove('is-collapsed');
|
|
el.style.height = 'auto';
|
|
el.style.maxHeight = 'none';
|
|
el.style.overflow = 'visible';
|
|
});
|
|
document.body.style.overflow = 'auto';
|
|
})
|
|
```
|
|
|
|
### 6. WeChat Public Account Articles (Sogou Gateway)
|
|
|
|
WeChat public account articles are normally login-gated in browsers, but Sogou WeChat Search (the official content index) allows direct access.
|
|
|
|
```javascript
|
|
// Step 1: Search for articles
|
|
navigate_page('https://weixin.sogou.com/weixin?type=2&s_from=input&query=' + encodeURIComponent('search keyword'))
|
|
|
|
// Step 2: Get result list
|
|
evaluate_script(() => {
|
|
const items = [...document.querySelectorAll('.news-list2 .wx-rb, .news-list2 li')].filter(el => el.querySelector('h3 a'));
|
|
return items.slice(0, 10).map(el => ({
|
|
title: el.querySelector('h3 a')?.textContent?.trim(),
|
|
link: el.querySelector('h3 a')?.href,
|
|
source: el.querySelector('.account')?.textContent?.trim(),
|
|
date: el.querySelector('.time')?.textContent?.trim(),
|
|
summary: el.querySelector('.txt-info')?.textContent?.trim()?.slice(0, 80)
|
|
}));
|
|
})
|
|
|
|
// Step 3: Open article link (no login required)
|
|
navigate_page('result-link')
|
|
|
|
// Step 4: Extract content
|
|
evaluate_script(() => document.body.innerText)
|
|
```
|
|
|
|
**Verified (2026):** Sogou WeChat Search for `chrome devtools` returns 634 results. Opening the link gives full 2856-character article with no restrictions.
|
|
|
|
### 7. Mobile Emulation (some sites have fewer restrictions on mobile)
|
|
|
|
```javascript
|
|
emulate({
|
|
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1',
|
|
viewport: '375x667x2,mobile,touch'
|
|
})
|
|
```
|
|
|
|
## Quick Command Reference
|
|
|
|
| Operation | Tool | Description |
|
|
|-----------|------|-------------|
|
|
| Open page | `new_page(url)` | Open in new tab |
|
|
| Navigate | `navigate_page(url)` | Navigate current tab |
|
|
| Wait for content | `wait_for(["text"])` | Wait for text to appear |
|
|
| Screenshot | `take_screenshot()` | Full-page screenshot |
|
|
| DOM snapshot | `take_snapshot()` | Accessibility tree text structure |
|
|
| Execute JS | `evaluate_script(fn)` | Arbitrary JS operations |
|
|
| JS with args | `evaluate_script(fn, args)` | Execute with parameters |
|
|
| Extract content | `evaluate_script(() => document.body.innerText)` | Plain text extraction |
|
|
| Remove element | `evaluate_script(() => el.remove())` | Remove overlay/popup |
|
|
| Click element | `click(uid)` | Click by snapshot uid |
|
|
| Emulate device | `emulate({userAgent, viewport})` | Switch UA/viewport |
|
|
| Scroll | `press_key({key: "Space"})` | Simulate key press |
|
|
|
|
## FAQ (Practical Experience)
|
|
|
|
### 1. Popup class names don't match?
|
|
|
|
First inspect the actual overlay elements:
|
|
```javascript
|
|
evaluate_script(() => {
|
|
[...document.querySelectorAll('div[style*="fixed"], div[style*="absolute"], [class*="overlay"], [class*="modal"], [class*="mask"], [class*="popup"]')]
|
|
.map(el => ({tag: el.tagName, cls: el.className.slice(0,80), visible: el.offsetParent !== null}))
|
|
})
|
|
```
|
|
|
|
### 2. How to tell if content is complete or truncated?
|
|
|
|
```javascript
|
|
evaluate_script(() => {
|
|
const a = document.querySelector('article') || document.querySelector('.Post-RichText');
|
|
const ratio = a.scrollHeight / a.clientHeight;
|
|
JSON.stringify({
|
|
textLen: a.innerText.length,
|
|
scrollH: a.scrollHeight, clientH: a.clientHeight,
|
|
ratio: ratio.toFixed(2), // > 1.2 means overflow hidden
|
|
endText: a.innerText.slice(-100)
|
|
})
|
|
})
|
|
```
|
|
|
|
If it ends with `-- The End --`, copyright notice, or a natural ending, it's complete.
|
|
|
|
### 3. CSDN overlay class names (verified 2026)
|
|
|
|
| CSDN Class | Description |
|
|
|------------|-------------|
|
|
| `.mask` + `.mask-dark` | Background overlay |
|
|
| `.passport-login-tip-container` | Login prompt bar |
|
|
| `.passport-login-container` | Login dialog container |
|
|
| `.passport-login-box` / `.passport-login-mark` | Login box and overlay |
|
|
| `.hide-article-box` | Article collapse bar |
|
|
|
|
### 4. Zhihu overlay class names (verified 2026)
|
|
|
|
| Zhihu Class | Description |
|
|
|-------------|-------------|
|
|
| `.Modal.Modal--default.signFlowModal` | Login dialog |
|
|
| `.signFlowModal-container` | Login container |
|
|
| Content selector: `.Post-RichText` or `.RichText` | |
|
|
|
|
### 5. Short article vs truncated article
|
|
|
|
- Some articles are genuinely short (many images/code, few words) — e.g., 2081 chars but scrollHeight = 8550px
|
|
- Verification: check end for natural termination, or confirm via `document.title`
|
|
- Zhihu columns without login may redirect to search page — check `location.href`
|
|
|
|
### 6. What can vs cannot be bypassed
|
|
|
|
| Type | Principle | Bypassable? | Example |
|
|
|------|-----------|-------------|---------|
|
|
| DOM overlay | Content in DOM, hidden behind a div | Yes — just remove it | CSDN, Zhihu columns |
|
|
| Lazy load | Content loaded on scroll | Yes — trigger scroll | Most comment sections |
|
|
| API auth | Content fetched via cookie-authenticated API | No — no cookie = no data | Bilibili comments, Weibo |
|
|
| SSR hidden | Server-rendered but hidden via class | Yes — change style | Juejin paid articles |
|
|
|
|
### 7. Chrome restart / disconnect handling
|
|
|
|
MCP mode manages browser lifecycle automatically. CLI mode:
|
|
```bash
|
|
chrome-devtools stop # Stop background process
|
|
chrome-devtools status # Check status
|
|
```
|
|
|
|
---
|
|
|
|
# Part 2 — Debugging Guide
|
|
|
|
Based on `chrome-devtools-mcp` toolset for debugging web pages, inspecting errors, and analyzing performance.
|
|
|
|
## Tool Overview
|
|
|
|
```
|
|
Category Tool Purpose
|
|
────── ─── ───
|
|
Navigation new_page / navigate_page Open/navigate pages
|
|
close_page / select_page Close/switch tabs
|
|
list_pages List all tabs
|
|
wait_for Wait for text
|
|
|
|
Debugging evaluate_script Execute JS in page
|
|
take_snapshot Get accessibility tree (uid)
|
|
take_screenshot Screenshot
|
|
list_console_messages List console logs
|
|
get_console_message(msgid) View specific log details
|
|
lighthouse_audit Lighthouse audit
|
|
|
|
Interaction click(uid) Click element
|
|
fill(uid, value) Fill input field
|
|
fill_form([{uid,value}]) Batch form fill
|
|
type_text(text) Keyboard input
|
|
press_key(key) Key press (Enter/Tab/Ctrl+A)
|
|
hover(uid) Hover
|
|
drag(from_uid, to_uid) Drag
|
|
handle_dialog(action) Handle browser dialogs
|
|
upload_file(path, uid) Upload file
|
|
|
|
Network list_network_requests List network requests
|
|
get_network_request(reqid) View request details/response
|
|
|
|
Performance performance_start_trace Start performance recording
|
|
performance_stop_trace Stop + analyze
|
|
performance_analyze_insight Analyze specific metric
|
|
take_memory_snapshot Heap snapshot
|
|
|
|
Emulation emulate({userAgent, viewport}) Simulate device
|
|
resize_page(width, height) Resize window
|
|
```
|
|
|
|
## Standard Debugging Flows
|
|
|
|
### Flow 1: JS Error Investigation
|
|
|
|
```
|
|
1. navigate_page(url) → Enter page
|
|
2. list_console_messages() → View errors
|
|
3. get_console_message(msgid) → View error details
|
|
4. evaluate_script(() => { /* fix */ }) → Fix the issue
|
|
5. verify
|
|
```
|
|
|
|
### Flow 2: Network Request Analysis
|
|
|
|
```
|
|
1. navigate_page(url) → Load page
|
|
2. list_network_requests() → List all requests
|
|
3. get_network_request(reqid) → View request/response body
|
|
4. Identify 404s, CORS errors, slow requests
|
|
```
|
|
|
|
### Flow 3: DOM / Style Debugging
|
|
|
|
```
|
|
1. take_snapshot() → Get element structure (with uid)
|
|
2. click(uid) / fill(uid, value) → Interact
|
|
3. evaluate_script(() => getComputedStyle(el)) → Check styles
|
|
4. evaluate_script(() => { el.style.color = 'red' }) → Temporary modification
|
|
5. take_screenshot() → Confirm visually
|
|
```
|
|
|
|
### Flow 4: Performance Analysis
|
|
|
|
```
|
|
1. performance_start_trace({reload: true}) → Start recording + reload
|
|
2. (wait for page to load)
|
|
3. performance_stop_trace() → Stop and analyze
|
|
4. performance_analyze_insight({insightName, insightSetId}) → Deep dive
|
|
```
|
|
|
|
## Debugging Quick Reference
|
|
|
|
### Console
|
|
|
|
```javascript
|
|
// View all console messages
|
|
list_console_messages({includePreservedMessages: true})
|
|
|
|
// View specific message
|
|
get_console_message({msgid: 0})
|
|
```
|
|
|
|
### Element Inspection
|
|
|
|
```javascript
|
|
// Get interactive elements list (with uid)
|
|
take_snapshot()
|
|
|
|
// Verbose version (more properties)
|
|
take_snapshot({verbose: true})
|
|
|
|
// Inspect element styles
|
|
evaluate_script(() => {
|
|
const el = document.querySelector('h1');
|
|
return getComputedStyle(el);
|
|
})
|
|
|
|
// Get element dimensions / position
|
|
evaluate_script(() => {
|
|
const el = document.querySelector('h1');
|
|
return el.getBoundingClientRect();
|
|
})
|
|
```
|
|
|
|
### Page Interaction
|
|
|
|
```javascript
|
|
// Click (get uid via take_snapshot first)
|
|
click({uid: "element-123"})
|
|
|
|
// Fill input
|
|
fill({uid: "input-456", value: "search text"})
|
|
|
|
// Fill + Enter
|
|
fill({uid: "input-456", value: "search text"})
|
|
press_key({key: "Enter"})
|
|
|
|
// Keyboard shortcuts
|
|
press_key({key: "Control+A"})
|
|
press_key({key: "Control+C"})
|
|
|
|
// Handle browser dialogs (alert/confirm)
|
|
handle_dialog({action: "accept"})
|
|
handle_dialog({action: "dismiss"})
|
|
```
|
|
|
|
### Network
|
|
|
|
```javascript
|
|
// View all network requests
|
|
list_network_requests({pageSize: 50, resourceTypes: ["XHR", "Fetch", "Document"]})
|
|
|
|
// View request details
|
|
get_network_request({reqid: 0})
|
|
|
|
// Save response body to file
|
|
get_network_request({reqid: 0, responseFilePath: "response.json"})
|
|
```
|
|
|
|
### Memory Debugging
|
|
|
|
```javascript
|
|
// Capture heap snapshot (for memory leak analysis)
|
|
take_memory_snapshot({filePath: "heap.heapsnapshot"})
|
|
```
|
|
|
|
### Lighthouse Audit
|
|
|
|
```javascript
|
|
// Accessibility + SEO + Best Practices
|
|
lighthouse_audit({device: "desktop"})
|
|
lighthouse_audit({device: "mobile"})
|
|
lighthouse_audit({mode: "snapshot"}) // No reload, analyze current state
|
|
```
|
|
|
|
## Typical Scenarios
|
|
|
|
### Scenario A: White Screen / JS Error Fix
|
|
|
|
```
|
|
1. list_console_messages() → Check for JS errors
|
|
2. get_console_message(0) → View first error details
|
|
3. evaluate_script(() => { ... }) → Temporary fix in page
|
|
4. Fix in source code, reload, verify
|
|
```
|
|
|
|
### Scenario B: API Endpoint Debugging
|
|
|
|
```
|
|
1. navigate_page('https://example.com')
|
|
2. list_network_requests({resourceTypes: ["XHR", "Fetch"]}) → Filter API calls
|
|
3. get_network_request(0) → View request params + response data
|
|
```
|
|
|
|
### Scenario C: Form Submission Verification
|
|
|
|
```
|
|
1. take_snapshot() → Get form element uids
|
|
2. fill({uid, value}) → Fill each field
|
|
3. click({uid}) → Click submit button
|
|
4. list_network_requests() → Check if request was sent
|
|
5. list_console_messages() → Check for errors
|
|
```
|
|
|
|
### Scenario D: Responsive Layout Debugging
|
|
|
|
```
|
|
1. emulate({viewport: '375x667x2,mobile,touch'}) → Switch to mobile
|
|
2. take_screenshot() → Screenshot for review
|
|
3. emulate({viewport: '1280x720'}) → Switch back to desktop
|
|
4. take_screenshot() → Compare results
|
|
```
|