Skip to main content

Debugging Web Applications

A comprehensive guide to debugging web applications using devtool-mcp's proxy and frontend diagnostics.

Overview

This use case covers the complete workflow for debugging frontend issues:

  1. Set up the debugging environment
  2. Capture and analyze HTTP traffic
  3. Identify JavaScript errors
  4. Debug layout and styling issues
  5. Document and share findings

Setting Up

Start Your Development Server

// Detect project and available scripts
detect {path: "."}
{type: "node", scripts: ["dev", "build", "test"]}

// Start dev server
run {script_name: "dev"}
{process_id: "dev", state: "running"}

// Verify it's ready
proc {action: "output", process_id: "dev", grep: "ready", tail: 5}
"Ready on http://localhost:3000"

Create Debugging Proxy

proxy {action: "start", id: "debug", target_url: "http://localhost:3000", port: 8080}
{id: "debug", listen_addr: ":8080", status: "running"}

Now browse to http://localhost:8080 instead of port 3000.

Debugging Workflows

Investigating a User-Reported Bug

Scenario: User reports "the submit button doesn't work on the checkout page."

Step 1: Navigate to the Problem Page

Have the user (or navigate yourself) to the checkout page via the proxy.

Step 2: Check for JavaScript Errors

proxylog {proxy_id: "debug", types: ["error"]}
{
entries: [{
message: "Cannot read property 'submit' of undefined",
source: "/static/js/checkout.js",
line: 234
}]
}

Step 3: Check API Calls

proxylog {proxy_id: "debug", types: ["http"], url_pattern: "/api/checkout"}
{
entries: [{
method: "POST",
url: "/api/checkout",
status: 401,
response_body: "{\"error\": \"Session expired\"}"
}]
}

Step 4: Inspect the Button

proxy {action: "exec", id: "debug", code: "window.__devtool.inspect('#submit-btn')"}
{
visibility: {visible: true},
accessibility: {role: "button", accessibleName: "Submit Order"},
// Element exists and is visible
}

Conclusion: The API returns 401 (session expired), causing the JavaScript error. The button itself is fine.

Debugging Layout Issues

Scenario: Content is getting cut off on mobile.

Step 1: Find Overflow Issues

proxy {action: "exec", id: "debug", code: "window.__devtool.findOverflows()"}
[
{selector: ".product-grid", overflow: "horizontal", excess: 200}
]

Step 2: Get Details

proxy {action: "exec", id: "debug", code: "window.__devtool.getOverflow('.product-grid')"}
{
scrollWidth: 520,
clientWidth: 320,
hasHorizontalOverflow: true
}

Step 3: Highlight the Issue

proxy {action: "exec", id: "debug", code: "window.__devtool.highlight('.product-grid', {color: 'rgba(255,0,0,0.3)', duration: 0})"}

Step 4: Take Screenshot

proxy {action: "exec", id: "debug", code: "window.__devtool.screenshot('overflow-issue')"}

Step 5: Examine the CSS

proxy {action: "exec", id: "debug", code: "window.__devtool.getComputed('.product-grid', ['display', 'grid-template-columns', 'gap'])"}
{
display: "grid",
"grid-template-columns": "repeat(3, 200px)", // Fixed width - problem!
gap: "16px"
}

Solution: Change repeat(3, 200px) to repeat(auto-fit, minmax(200px, 1fr)).

Debugging Z-Index Problems

Scenario: Dropdown menu appears behind a modal.

Step 1: Find Stacking Contexts

proxy {action: "exec", id: "debug", code: "window.__devtool.findStackingContexts()"}
[
{selector: ".modal", zIndex: 1000, reason: "position: fixed"},
{selector: ".dropdown", zIndex: 100, parentContext: ".header"}
]

Step 2: Check Dropdown's Context

proxy {action: "exec", id: "debug", code: "window.__devtool.getStacking('.dropdown')"}
{
zIndex: 100,
createsContext: true,
parentContext: ".header", // Constrained by header!
reason: "z-index with position: absolute"
}

Step 3: Check Header's Z-Index

proxy {action: "exec", id: "debug", code: "window.__devtool.getStacking('.header')"}
{
zIndex: 50, // Lower than modal's 1000
createsContext: true
}

Problem: The dropdown's z-index (100) is relative to .header (50), which is lower than the modal (1000).

Solution: Either increase header's z-index above 1000, or move the dropdown outside the header's stacking context.

Performance Investigation

Scenario: Page loads slowly.

Step 1: Check Performance Metrics

proxylog {proxy_id: "debug", types: ["performance"]}
{
entries: [{
navigation: {dom_content_loaded: 2500, load_event: 4500},
paint: {first_paint: 1800, first_contentful_paint: 2200}
}]
}

Step 2: Analyze Resources

proxy {action: "exec", id: "debug", code: "window.__devtool.captureNetwork()"}
{
summary: {
totalResources: 45,
totalTransferSize: 2500000,
byType: {
script: {count: 12, size: 1800000} // 1.8MB of JS!
}
},
entries: [
{name: "vendor.js", duration: 2100, size: 1200000}
]
}

Step 3: Check for Slow API Calls

proxylog {proxy_id: "debug", types: ["http"], url_pattern: "/api"}
→ Find any API calls with high duration_ms

Step 4: Get Page Session Overview

currentpage {proxy_id: "debug", action: "get", session_id: "page-1"}
→ Full breakdown of resources, errors, and timing

Interactive Debugging

Let User Show You the Problem

proxy {action: "exec", id: "debug", code: "window.__devtool.selectElement()"}

Ask the user to click on the problematic element. The response includes the selector and element details.

Ask User Questions

proxy {action: "exec", id: "debug", code: "window.__devtool.ask('Does this look correct?', ['Yes', 'No', 'Partially'])"}

Wait for Dynamic Content

proxy {action: "exec", id: "debug", code: "window.__devtool.waitForElement('.results-loaded', 10000)"}

Documentation Workflow

Capture State for Bug Report

// Screenshot
proxy {action: "exec", id: "debug", code: "window.__devtool.screenshot('bug-state')"}

// DOM snapshot
proxy {action: "exec", id: "debug", code: "window.__devtool.captureDOM()"}

// Element details
proxy {action: "exec", id: "debug", code: "window.__devtool.inspect('.problem-element')"}

// Recent errors
proxylog {proxy_id: "debug", types: ["error"], since: "5m"}

// Recent traffic
proxylog {proxy_id: "debug", types: ["http"], url_pattern: "/api", since: "5m"}

Create Visual Guide

// Highlight relevant elements
proxy {action: "exec", id: "debug", code: "window.__devtool.highlight('.step-1', {label: 'Step 1', duration: 0})"}
proxy {action: "exec", id: "debug", code: "window.__devtool.highlight('.step-2', {label: 'Step 2', duration: 0})"}

// Screenshot with highlights
proxy {action: "exec", id: "debug", code: "window.__devtool.screenshot('annotated-steps')"}

// Clean up
proxy {action: "exec", id: "debug", code: "window.__devtool.clearAllOverlays()"}

Complete Debugging Session Example

User: "The product page is broken"

AI: Let me investigate. First, I'll set up debugging.

[run {script_name: "dev"}]
[proxy {action: "start", id: "debug", target_url: "http://localhost:3000"}]

AI: Please navigate to http://localhost:8080/products/123

[User navigates]

AI: Let me check for errors.

[proxylog {proxy_id: "debug", types: ["error"]}]
→ "TypeError: products.map is not a function"

AI: Found a JavaScript error. Let me check the API.

[proxylog {proxy_id: "debug", types: ["http"], url_pattern: "/api/products"}]
→ {status: 200, response_body: "{\"product\": {...}}"}

AI: The API returned a single product object, not an array.
The code expects an array (products.map).

Let me show you exactly where:

[proxy {action: "exec", id: "debug", code: "window.__devtool.highlight('.products-list', {color: 'red'})"}]

AI: The products-list container is highlighted. The component expects
an array but receives a single object.

Fix: Change the API endpoint to return [{...}] or update the
component to handle single products.

Best Practices

  1. Start with errors - Check proxylog for errors first
  2. Check API responses - Many frontend bugs are caused by unexpected API data
  3. Use page sessions - currentpage gives a unified view
  4. Screenshot liberally - Visual evidence helps communication
  5. Clean up highlights - Use clearAllOverlays() when done
  6. Document findings - Capture state for sharing

See Also