| name | debug-browser |
| description | Debug or reproduce a component issue in a live browser using the Chrome DevTools MCP server. Use to get a live repro, inspect the DOM, watch console errors, analyze network requests, take screenshots, or evaluate scripts against a running grid. Covers launching dev servers and navigating to pages/stories. (For performance traces and hot-path profiling, use the debug-perf skill.) |
| argument-hint | <issue-description> |
Browser Debugging via Chrome DevTools MCP
Guide for debugging grid components in a live browser using the Chrome DevTools MCP server. This enables inspecting DOM, evaluating scripts, capturing screenshots, monitoring console/network, and more — all from within the AI coding assistant.
Performance-specific debugging? See the debug-perf skill for hot path analysis, render scheduler profiling, and performance budget verification. That skill includes a section on live browser profiling via MCP.
Prerequisites
The workspace has Chrome DevTools MCP pre-configured in .vscode/mcp.json:
{
"servers": {
"chrome-devtools": {
"command": "npx",
"args": ["-y", "chrome-devtools-mcp@latest"],
},
},
}
The MCP server launches its own Chromium instance. This is separate from any VS Code debug launch configuration — they are independent workflows:
- MCP browser: For AI-driven inspection, script evaluation, screenshots
- VS Code debugger: For breakpoints, step-through, variable inspection
Troubleshooting MCP server launch / connection failures
If an MCP tool call returns an error such as "server not running", "failed to launch", or "connection refused", work through this checklist before continuing:
Step 1: Reach the Dev Server (assume it's already running)
Do NOT start a dev server first. In a debugging session the user almost always already has the relevant dev server running. Starting another one wastes time and can fail on a port-in-use clash. Check first, start only as a last resort.
about:blank is NOT "no server". list_pages (or a freshly attached MCP browser) reports about:blank because that's the default empty tab — it tells you nothing about whether the dev server is up. Never infer "the server isn't running, I must start one" from an about:blank page. The only way to test the server is to navigate_page to the real URL and see whether it loads. Always navigate first.
Work through these in order and stop at the first that succeeds:
-
Just navigate via Chrome MCP. Point navigate_page straight at the target URL (do not be misled by an about:blank tab — navigate to confirm). If the page loads, you're done — no terminal command needed.
navigate_page → url: http://localhost:4400/grid/plugins/editing/
If it errors with a connection refused / ERR_CONNECTION_REFUSED, the server for that port isn't up — fall through to step 2.
-
Probe the port from the terminal (cheap, non-blocking) to confirm whether something is listening before launching anything:
curl -sSf -o /dev/null http://localhost:4400/ && echo "up" || echo "down"
If it prints up, retry the navigate_page from step 1 (the server is there). If down, proceed to step 3.
-
Only now start the dev server for the port you need, then navigate once it's listening:
bun nx serve docs
bun nx serve demo-vanilla
bun nx serve demo-angular
bun nx serve demo-react
bun nx serve demo-vue
bun run demo
Server reference:
| App | Port | Command | Probe |
|---|
| Docs Site | 4400 | bun nx serve docs | curl -sSf -o /dev/null localhost:4400/ |
| Demo Vanilla | 4000 | bun nx serve demo-vanilla | curl -sSf -o /dev/null localhost:4000/ |
| Demo Angular | 4200 | bun nx serve demo-angular | curl -sSf -o /dev/null localhost:4200/ |
| Demo React | 4300 | bun nx serve demo-react | curl -sSf -o /dev/null localhost:4300/ |
| Demo Vue | 4100 | bun nx serve demo-vue | curl -sSf -o /dev/null localhost:4100/ |
Step 2: Navigate to the Target
Navigate to a demo app
navigate_page → url: http://localhost:4200/
Navigate to a specific docs page
The docs site runs at http://localhost:4400. Navigate to specific pages by path:
navigate_page → url: http://localhost:4400/grid/plugins/editing/
navigate_page → url: http://localhost:4400/grid/guides/getting-started/
Reload a page (after code changes with HMR)
navigate_page → type: reload, ignoreCache: true
List open pages
list_pages
Use select_page to switch between tabs if multiple are open.
Step 3: Inspect and Debug
DOM Inspection
Take a DOM snapshot to see the full HTML structure:
take_snapshot → selector: tbw-grid
This returns a structured DOM tree with element attributes, classes, and text content. Very useful for understanding the current grid state.
Evaluate a script to query the DOM programmatically:
() => {
const grid = document.querySelector('tbw-grid');
return {
rows: grid?._bodyEl?.querySelectorAll('.data-grid-row').length,
editingCells: grid?.querySelectorAll('.cell.editing').length,
columns: grid?._visibleColumns?.length,
};
};
Console Monitoring
List console messages to catch warnings/errors:
list_console_messages
Get a specific console message by index for full details:
get_console_message → index: 0
Useful for catching grid validation warnings (e.g., "EditingPlugin required", config validation errors).
Network Monitoring
List network requests to debug API calls or asset loading:
list_network_requests
Get details of a specific request (headers, response body):
get_network_request → index: 0
Screenshots
Take a screenshot for visual verification:
take_screenshot
Take a screenshot of a specific element:
take_screenshot → selector: tbw-grid
Useful for visual regression debugging — compare before/after states.
Interaction
Click on an element:
click → selector: .cell[data-col="3"][data-row="0"]
Fill an input:
fill → selector: .cell.editing input → value: new text
Press a key:
press_key → key: Enter
press_key → key: Escape
press_key → key: Tab
Hover over an element (e.g., to trigger tooltips):
hover → selector: .cell[data-col="0"][data-row="0"]
Wait for Conditions
Wait for an element to appear:
wait_for → selector: .cell.editing
wait_for → selector: tbw-grid .data-grid-row
Wait for network idle (after navigation or data loading):
wait_for → type: networkIdle
Step 4: Script Evaluation Patterns
The evaluate_script tool is the most powerful debugging tool. It runs arbitrary JavaScript in the page context.
Grid Internals Access
The grid's internal state is accessible through the DOM element:
() => {
const grid = document.querySelector('tbw-grid');
return {
effectiveConfig: Object.keys(grid.effectiveConfig || {}),
columnCount: grid._visibleColumns?.length,
rowCount: grid._rows?.length,
virtStart: grid._virtualization?.start,
virtEnd: grid._virtualization?.end,
rowHeight: grid._virtualization?.rowHeight,
activeEditRow: grid._activeEditRows,
isGridEditMode: grid._isGridEditMode,
editingCells: grid.querySelectorAll('.cell.editing').length,
plugins: grid._pluginManager?.getPlugins().map((p) => p.constructor.name),
};
};
Framework Adapter Inspection
() => {
const grid = document.querySelector('tbw-grid');
const adapter = grid?.__frameworkAdapter;
return {
adapterType: adapter?.constructor.name,
viewRefs: adapter?.viewRefs?.length,
componentRefs: adapter?.componentRefs?.length,
editorViewRefs: adapter?.editorViewRefs?.length,
editorComponentRefs: adapter?.editorComponentRefs?.length,
};
};
Monkey-Patching for Tracing
Inject tracing code to track specific operations:
() => {
const grid = document.querySelector('tbw-grid');
const adapter = grid?.__frameworkAdapter;
if (!adapter?.releaseCell) return { error: 'No adapter or releaseCell' };
const original = adapter.releaseCell.bind(adapter);
window.__releaseLogs = [];
adapter.releaseCell = (cellEl) => {
window.__releaseLogs.push({
col: cellEl.getAttribute('data-col'),
row: cellEl.getAttribute('data-row'),
isEditing: cellEl.classList.contains('editing'),
stack: new Error().stack?.split('\n').slice(1, 4).join('\n'),
});
return original(cellEl);
};
return { patched: true };
};
Then trigger the action and read results:
() => ({
logCount: window.__releaseLogs?.length || 0,
logs: window.__releaseLogs?.slice(0, 10) || [],
});
Async Operations
For operations that need to wait for render cycles:
() => {
const grid = document.querySelector('tbw-grid');
grid.rows = [...grid.rows];
return new Promise((resolve) => {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
resolve({ rendered: true, rowCount: grid._rows?.length });
});
});
});
};
Step 5: Common Debugging Workflows
"Component renders incorrectly"
navigate_page to the page showing the issue
take_screenshot for visual context
take_snapshot on tbw-grid for DOM structure
evaluate_script to read grid state (config, columns, rows)
- Identify the discrepancy between expected and actual state
"Editor is destroyed during editing"
- Navigate to the page with the editor
evaluate_script: Monkey-patch adapter.releaseCell to log destructions
- Enter edit mode via
click + press_key Enter
- Trigger the suspected cause (e.g., rows replacement)
evaluate_script: Read the logs to see if/how destruction happened
"Event not firing or has wrong payload"
evaluate_script: Add event listener with logging
() => {
window.__eventLogs = [];
const grid = document.querySelector('tbw-grid');
grid.on('cell-commit', (detail) => {
window.__eventLogs.push({ type: 'cell-commit', detail });
});
return { listening: true };
};
- Trigger the action
evaluate_script: Read window.__eventLogs
"Styles not applied correctly"
take_screenshot for visual state
evaluate_script: Read computed styles
() => {
const cell = document.querySelector('.cell[data-col="0"]');
const styles = getComputedStyle(cell);
return {
width: styles.width,
color: styles.color,
background: styles.backgroundColor,
display: styles.display,
};
};
take_snapshot with selector for the specific element's DOM
"Docs page fails to render"
navigate_page to http://localhost:4400/grid/plugins/<plugin>/
list_console_messages to catch any errors
take_screenshot for visual state
take_snapshot to see what DOM was actually rendered
MCP Tool Reference
Tools are grouped by category. Pick a category first based on what you are trying to learn, then choose a tool within it.
Navigation & tab management
Use when you need to load a URL, switch between tabs, or open/close pages.
| Tool | Purpose |
|---|
navigate_page | Go to URL, reload, go back/forward |
list_pages | List all open browser tabs |
select_page | Switch to a different tab |
new_page | Open a new tab |
close_page | Close a tab |
Visual debugging (screenshots & DOM snapshots)
Use when you need to see what the page looks like or what its DOM structure is.
| Tool | Purpose |
|---|
take_screenshot | Capture full page or element screenshot |
take_snapshot | Get DOM tree structure |
Script evaluation
Use when you need to read internal state, monkey-patch a method, or run arbitrary JS in the page context.
| Tool | Purpose |
|---|
evaluate_script | Run JavaScript in page context |
User interaction simulation
Use when you need to simulate a user action (click, type, drag, key press) to reproduce or trigger a bug.
| Tool | Purpose |
|---|
click | Click an element by selector |
fill | Type text into an input |
fill_form | Fill multiple form fields at once |
press_key | Send keyboard events |
hover | Hover over an element |
drag | Drag from one element to another |
upload_file | Upload a file to a file input |
handle_dialog | Accept/dismiss browser dialogs |
Synchronization & viewport
Use when you need to wait for the page to settle, or to change the viewport / device emulation.
| Tool | Purpose |
|---|
wait_for | Wait for element, URL, timeout, or network |
emulate | Set viewport size or device emulation |
resize_page | Resize the browser viewport |
Console monitoring
Use when you need to catch warnings, errors, or console.log output emitted by the page.
| Tool | Purpose |
|---|
list_console_messages | Get all console messages |
get_console_message | Get specific console message details |
Network monitoring
Use when you need to debug API calls, asset loading, or response payloads.
| Tool | Purpose |
|---|
list_network_requests | List all network requests |
get_network_request | Get specific request/response details |
Performance tracing
Use when you need to profile rendering, scripting, or layout work. See the debug-perf skill for full workflow.
| Tool | Purpose |
|---|
performance_start_trace | Start a performance trace (see debug-perf) |
performance_stop_trace | Stop trace and get results |
performance_analyze_insight | Get AI-analyzed performance insights |