Debugging in the Agentic Era
---
title: 'Debugging in the Agentic Era'
date: '2026-10-31'
excerpt: "Agents write the code but can't see it run. Chrome DevTools MCP and Playwright MCP let them test every scenario in a real browser: success, slow, error, performance, and accessibility. You keep the judgment."
---
Coding agents write frontend code fast, but they can't see it run. This is the flow I use to fix that, with a signup form that fails on submit as the example.
The Old Way
1. The agent changes the form.
2. You open the page, click submit, and nothing happens.
3. You open DevTools, find a 422 in the Network tab, and copy the response.
4. You paste it into the chat. The agent guesses a fix.
5. You reload. Now the console shows a TypeError. You copy and paste again.
You're the agent's eyes, and most of your time goes to copying, not thinking.
The New Way
1. You ask: "Submit the signup form on localhost:3000 and tell me why it fails."
2. The agent clicks submit, reads the 422 response and the console, and matches them to the code.
3. It explains the cause and proposes a fix.
4. You check that explanation against what you see in the browser, then approve or push back.
flowchart TB
accTitle: The old way and the new way
accDescr: In the old way, the agent writes code, the browser shows an error, and you copy that error back to the agent. In the new way, the agent reads the browser through MCP and reports its findings to you, and you validate them before it continues.
subgraph Old
direction TB
a1[Agent] -- writes code --> b1[Browser]
b1 -- error --> y1[You]
y1 -- paste --> a1
end
subgraph New
direction TB
a2[Agent] -- writes code --> b2[Browser]
b2 -- MCP --> a2
a2 -- findings --> y2[You]
y2 -- validate --> a2
end
Old ~~~ New
The copy-paste is gone. You're still there, in a different role.
This is human in the loop (HITL): the agent gathers evidence, and you validate it. Don't trust it 100%. It can misread a trace, or silence an error instead of fixing it.
The HITL notes in this post mark where to look yourself.
Cover Every Scenario
Browser access lets the agent put a page through every scenario your customers hit, not only the one where everything works:
| Scenario | What the customer should get |
| ------------------------------------------- | ------------------------------------------ |
| [Success](#the-debug-loop) | The flow works end to end |
| [Slow](#testing-slow-and-failing-requests) | A loading state, no double submits |
| [Error](#testing-slow-and-failing-requests) | A clear message, their input kept, a retry |
| [Performance](#improving-core-web-vitals) | Fast loading, no layout shifts |
| [Accessibility](#checking-accessibility) | Works with a keyboard and a screen reader |
The rest of this post shows how to set it up, then walks through each one.
The Tools
Two MCP servers give an agent a browser. MCP is an open standard, so neither is tied to Claude Code. Both work in Cursor, VS Code with Copilot, Codex, and Gemini CLI.
Chrome DevTools MCP
Chrome DevTools MCP is Google's MCP server for Chrome. It lets the agent open pages, click, and read what you see in DevTools:
- Console: errors, warnings, and logs
- Network: requests, status codes, and payloads
- Performance: traces with Core Web Vitals like LCP and CLS
- Accessibility: Lighthouse audits and the accessibility tree
- Emulation: slow networks, offline mode, CPU throttling, dark mode, reduced motion, and forced colors
Playwright MCP
Playwright MCP is Microsoft's MCP server for browser automation. It drives Chromium, Firefox, and WebKit, can make a single request fail, and helps the agent write end-to-end tests you can rerun.
Installing Them
Most agents read the same config:
{
"mcpServers": {
"chrome-devtools": {
"command": "npx",
"args": ["-y", "chrome-devtools-mcp@latest"]
},
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest", "--caps=network"]
}
}
}
The --caps=network flag turns on Playwright MCP's request mocking. In Cursor, add the config under Settings > MCP. In VS Code, both READMEs have one-click install buttons.
In Claude Code, two commands add both:
claude mcp add chrome-devtools --scope user npx chrome-devtools-mcp@latest
claude mcp add playwright -- npx @playwright/mcp@latest --caps=network
Run /mcp to confirm they're connected. Then ask the agent to open your local app and list the console messages.
By default, Chrome DevTools MCP starts its own Chrome. To use the one you already have open, add --autoConnect. It needs Chrome 144 or later, with remote debugging allowed at chrome://inspect/#remote-debugging.
Which One When
Use both, for different jobs. Chrome DevTools MCP looks inside one page: debugging, comparing, and measuring. Playwright MCP fails requests on purpose and writes tests you can rerun in any browser.
flowchart TD
accTitle: Choosing a browser MCP server
accDescr: To debug, compare pages, or measure performance in Chrome, use Chrome DevTools MCP. To write end-to-end tests, mock failed requests, or check Firefox and Safari, use Playwright MCP.
need{What do you need?}
need -- "debug, compare,<br>measure" --> devtools[Chrome DevTools MCP]
need -- "e2e tests, mocks,<br>other browsers" --> playwright[Playwright MCP]
The Debug Loop
Start with the success path: the flow working end to end. With browser access, getting there follows the same loop every time.
The agent changes the code, reloads the page, and reads the signals. You review what it found and steer it when it chases the wrong cause.
flowchart TD
accTitle: The debug loop
accDescr: The agent edits the code, reloads the page, and reads the console, network, and performance trace. You review what it found. If the issue isn't fixed, you steer the agent and it edits again. When it's fixed, you ship.
edit[Agent edits code] --> reload[Reload page] --> read[Agent reads signals]
read --> review[You review findings]
review --> fixed{Fixed?}
fixed -- no, you steer --> edit
fixed -- yes --> ship[Ship]
> HITL: Keep the browser window visible while the agent works. When it says the bug is fixed, reproduce it yourself before you believe it.
The two signals you'll read most are console errors and network requests.
Console Errors
My prompt: "Open /signup, submit the form, and list the console errors. Explain the cause before changing anything."
The agent reads the error and its stack trace, opens the file it points to, and tells you what it thinks went wrong. You read that explanation before any code changes.
> HITL: An error that disappears isn't always fixed. Check the diff: the agent may have wrapped it in a try/catch or removed the code that logged it.
Network Requests
My prompt: "Submit the form and show me the request and response for /api/signup. Compare the payload with what the backend expects."
The agent lists the requests, opens the failing one, and compares its body with the code that builds it. A misnamed field or a missing header shows up right there.
> HITL: Check the request against the API spec, not the agent's reading of it. Changing the frontend to accept a broken response hides a backend bug.
Testing Slow and Failing Requests
Customers rarely see a crash. They see a failure handled badly: a spinner that never stops, a blank page, a form that loses what they typed. The agent can slow things down or break them on purpose and show you what customers see.
Each server does this differently:
- Playwright MCP fails one request: browser_route makes an endpoint return a 500, a 404, or a malformed body.
- Chrome DevTools MCP degrades the whole page: emulate sets Slow 3G, offline mode, or CPU throttling. It can't mock a single request.
My prompt, combining both: "Make POST /api/signup return a 500, submit the form, and screenshot what the user sees. Then try it on Slow 3G."
Slow
On Slow 3G or with the CPU throttled, check what the customer gets:
- A loading state that shows up right away and ends, with an error if it takes too long
- A submit button they can't press twice
- Content that doesn't jump around when it arrives
Error
With a request failing, check what the customer gets:
- A message in plain words that says what to do next, not a stack trace or raw JSON
- Their input still in the form
- A retry that works
- Focus moved to the error, and the error announced to screen readers
Once a state looks right, lock it in with Playwright's page.route() so it stays that way:
test('signup keeps the input and offers a retry when the API fails', async ({
page,
}) => {
await page.route('**/api/signup', (route) => route.fulfill({ status: 500 }));
await page.goto('/signup');
await page.getByLabel('Email').fill('ada@example.com');
await page.getByRole('button', { name: 'Sign up' }).click();
await expect(page.getByRole('alert')).toContainText('Try again');
await expect(page.getByLabel('Email')).toHaveValue('ada@example.com');
});
> HITL: The agent can confirm an error message appears. Only you can judge whether it helps. Read each error state as a customer would: is it clear, kind, and does it say what to do next?
Improving Core Web Vitals
Slow requests are one side of speed. The other is how fast the page loads and settles, and that's where browser access helps most.
Without it, the agent guesses from the code. With it, the agent records a trace, sees which element is the LCP and what shifts the layout, and measures again after each change.
My prompt: "Record a performance trace of the home page with the CPU throttled 4x. Tell me the LCP element and what shifts the layout, then suggest one change at a time."
That turns "this might be faster" into numbers. The agent proposes a change, reruns the trace, and keeps it only if LCP or CLS improves.
> HITL: Read the trace yourself before accepting a change. One run is noise, so ask for several. And the trade-offs are yours: preloading an image or inlining CSS can win a metric and cost something else.
Checking Accessibility
An accessible page works for every customer: people on a keyboard, on a screen reader, or who need more contrast or less motion. The agent can check part of this in the browser.
Chrome DevTools MCP runs a Lighthouse audit and reads the accessibility tree, the names and roles a screen reader announces. It also turns on the settings some customers rely on: forced colors, higher contrast, and reduced motion.
My prompt: "Run a Lighthouse accessibility audit on /signup, then tab through the form and tell me where the focus goes."
Lock the fixes in with axe in your Playwright tests:
import AxeBuilder from '@axe-core/playwright';
test('signup has no detectable accessibility violations', async ({ page }) => {
await page.goto('/signup');
const results = await new AxeBuilder({ page }).analyze();
expect(results.violations).toEqual([]);
});
> HITL: Automated checks catch only some accessibility issues. A clean audit doesn't mean the page works with a screen reader. Tab through it yourself, and try VoiceOver or NVDA on the flows that matter.
Migrating Legacy Code Without Regressions
A migration has to keep every scenario working. The worst migration bug is a new page that looks almost like the old one, so capture how the legacy page behaves before you change anything.
Start with a Contract
Write down what must stay the same. This is the contract, and every test after it checks against it.
## Contract: /checkout
- Same visible text and layout at 390px and 1280px
- Same API requests, in the same order, with the same payloads
- No new console errors or warnings
- LCP and CLS no worse than the legacy page
- Every action reachable with the keyboard
The idea is the same as in [MigFlow](/posts/migflow-contracts-for-ai-migrations): agents need a contract, not a tutorial.
> HITL: You write or approve the contract. The agent can draft it from the legacy page, but it can't know which behavior your users depend on.
Cover the Legacy Page with Tests
Many legacy projects have no end-to-end tests. With Playwright MCP, the agent walks through the legacy page in a real browser and writes a Playwright test for each line of the contract.
Run them against the legacy page first. They must pass there, so they describe what the page does today, quirks included.
Playwright's toHaveScreenshot() saves screenshots of the legacy page as the baseline. Visual changes then show up as a pixel diff, not a judgment call:
test('checkout looks the same as the legacy page', async ({ page }) => {
await page.goto('/checkout');
await expect(page).toHaveScreenshot('checkout.png', { fullPage: true });
});
Create the baseline from the legacy page with npx playwright test --update-snapshots. After that, every run compares against it.
> HITL: Read every test. A test that passes no matter what protects nothing. Some quirks it captures are bugs you'll want to fix, not keep.
Migrate and Rerun the Same Tests
Now migrate, and run the same tests against the new page. A failing test is a regression. When one fails, the agent uses Chrome DevTools MCP to compare both pages and find out why.
The tests stay in CI after the migration, so the next change is covered too.
flowchart TD
accTitle: Migrating without regressions
accDescr: Write the contract, then cover the legacy page with Playwright tests. Migrate the code and run the same tests. If they fail, debug with Chrome DevTools MCP and migrate again. When they pass, you review and ship.
contract[Write the contract] --> cover[Test the legacy page]
cover --> migrate[Migrate the code]
migrate --> pass{Same tests pass?}
pass -- no --> debug[Debug with DevTools MCP]
debug --> migrate
pass -- yes --> review[You review and ship]
> HITL: When a test fails, you decide whether the page or the test is wrong. Don't let the agent update a screenshot baseline or loosen an assertion to go green without your OK.
Limits
- The agent can be confidently wrong. It will explain a wrong cause as clearly as a right one.
- It's slower than reading the code when the bug is obvious.
- Traces and logs fill the context window, so ask for the specific signal you need.
- The agent can read cookies and local storage. Add --isolated for a temporary profile, and be careful with --autoConnect, which uses the Chrome you're signed in to.
- Performance traces may send page URLs to Google's CrUX API. Add --no-performance-crux when you debug internal URLs.
Try It
Start with one prompt in any agent: "Open localhost:3000, list the console errors, and explain the cause before fixing anything."
Then try the other scenarios on one page: "Load the checkout page on Slow 3G, then with the payment request failing, and screenshot what the customer sees in each case."
Migrating a page? Write the contract, then ask: "Write Playwright tests for this contract and run them against the legacy page." Run the same tests after the migration.
A Tool in the Engineer's Hands
Success, slow, error, performance, accessibility: the agent can now put a page through every scenario and bring you the evidence. That's a powerful tool in the engineer's hands.
It doesn't decide what the evidence means. Every HITL note above comes down to the same habit: keep your eyes on the browser, and treat the agent's conclusions as claims to check, not facts.
As I wrote in AI Writes Code. You Own Quality., speed without judgment means shipping bugs faster. Browser access doesn't change who owns the fix. It gives you better evidence to own it with.
The agent gets eyes on the browser. You keep the judgment.
3 reactions · 4 comments
Chrome DevTools MCP in Claude Code (setup, attach mode, vs Playwright MCP)
TL;DR: Chrome DevTools MCP is the Chrome DevTools team's open-source MCP server. It lets Claude Code, Cursor, Codex or Gemini CLI drive a real Chrome and use DevTools features: network requests, console, screenshots, performance traces, Lighthouse and heap snapshots. Install it with claude mcp add chrome-devtools --scope user -- npx chrome-devtools-mcp@latest. Add --autoConnect (Chrome 144+) to let it attach to the Chrome you're already signed in to. It's great for debugging the page in front of it. It's a poor fit for "map this app's whole API".
Why I wanted it
My agent kept writing frontend fixes it couldn't check. With a browser MCP server it opens the page, reads the console, looks at the failing request and tells me what broke. The Chrome team shipped this as a public preview in September 2025, and it now has around 60 tools (some behind opt-in flags).
Setup
You need Node.js LTS and current stable Chrome.
Claude Code
claude mcp add chrome-devtools --scope user -- npx chrome-devtools-mcp@latest
Or the plugin, which also installs skills for a11y, cookies, LCP and memory leaks:
/plugin marketplace add ChromeDevTools/chrome-devtools-mcp
/plugin install chrome-devtools-mcp@chrome-devtools-plugins
Cursor (Settings → MCP → New MCP Server) and most other clients:
{
"mcpServers": {
"chrome-devtools": {
"command": "npx",
"args": ["-y", "chrome-devtools-mcp@latest"]
}
}
}
Codex / Gemini CLI
codex mcp add chrome-devtools -- npx chrome-devtools-mcp@latest
gemini mcp add chrome-devtools npx chrome-devtools-mcp@latest
First prompt to try: Check the performance of https://developer.chrome.com. You'll see a Chrome window open and a trace get recorded.
The network tools
There are two:
- list_network_requests: requests for a page since the last navigation. Filter by resourceTypes, paginate with pageSize/pageIdx, and set includePreservedRequests to reach back 3 navigations.
- get_network_request: one request with headers (including Cookie and Set-Cookie) and bodies. responseFilePath writes a big body to disk instead of into the context window.
The trick I like most: call get_network_request with no reqid and it returns whatever request you have selected in the DevTools Network panel. I click the broken call, then type "why did this 403?".
If headers carry tokens you'd rather not send to a model, start the server with --redactNetworkHeaders.
Attach mode (your signed-in browser)
By default the server launches Chrome with its own profile in ~/.cache/chrome-devtools-mcp/chrome-profile. --isolated uses a throwaway profile instead. To debug something behind your real login:
1. Open chrome://inspect/#remote-debugging in Chrome 144+ and allow incoming connections.
2. Add the flag:
"args": ["-y", "chrome-devtools-mcp@latest", "--autoConnect"]
3. Approve the permission dialog Chrome shows each time the server connects. A "Chrome is being controlled by automated test software" banner stays up while it's attached.
No --autoConnect (sandboxes, older Chrome)? Start Chrome yourself and point the server at it:
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
--remote-debugging-port=9222 --user-data-dir=/tmp/chrome-profile-stable
"args": ["chrome-devtools-mcp@latest", "--browser-url=http://127.0.0.1:9222"]
Heads up: attach mode gives the agent your cookies and signed-in accounts. Google's own docs say to only use it with agents you trust. Also, usage statistics are on by default (--no-usage-statistics), and performance tools can send trace URLs to CrUX (--no-performance-crux).
Chrome DevTools MCP vs Playwright MCP
Playwright MCP (claude mcp add playwright npx @playwright/mcp@latest) overlaps a lot. How I pick:
| | Chrome DevTools MCP | Playwright MCP |
|---|---|---|
| Browsers | Chrome, Chrome for Testing | Chrome, Firefox, WebKit, Edge |
| Page model | screenshots + text snapshot | accessibility tree, no vision needed |
| Perf insights / Lighthouse / heap | yes | Playwright traces via --caps=devtools, no Lighthouse or heap tools listed |
| Network | list + get (headers, bodies) | list (URL regex) + get, mocking via --caps=network |
| Existing browser | --autoConnect, --browser-url | --extension, --cdp-endpoint |
User flows and cross-browser checks: Playwright. "Why is this page slow or erroring in Chrome": DevTools MCP. Playwright's README also notes that coding agents may get on better with its CLI + skills, since those calls cost fewer tokens than MCP.
Where it stops for API work
Both servers only see what the browser loads while the agent is connected. When I want the agent to understand the whole API of an app, that hurts:
1. The request list resets per navigation (3 back at most), so the agent has to click through every screen.
2. Each screen costs tool calls and context.
3. /orders/1042 and /orders/1043 come back as separate URLs, so the agent has to figure out they're one endpoint.
4. Real logged-in traffic means attach mode and handing over my session.
5. Close the browser and the traffic is gone.
For that job I use Netraptor, a Chrome extension I work on. It records the app's fetch/XHR calls while I browse normally (or crawls same-site pages), groups them into endpoints like /orders/{id}, and its Pro plan has a local, read-only MCP server so the agent can ask "what does GET /orders/{id} return?" from real recorded responses. It has its own gap: it records from inside the page, so browser-added headers like Cookie aren't in its copy. DevTools MCP shows those. So I run both: Netraptor for "what does the API look like", DevTools MCP for "go reproduce this".
The full guide, with links to every doc above, is at netraptor.dev.
1 comment
Mentions
🔗 microsoft/playwright-mcp ⚠️ 官方說它不是安全邊界,登入中的帳號別亂交給它
Debugging in the Agentic Era --- title: 'Debugging in the Agentic Era' date: '2026-10-31' excerpt: "Agents write the code but can't see it run. Chrome DevTools MCP and Playwright MCP let them test every scenario in a real browser: success, slow, error, performance, and accessibility. You keep the judgment." --- Coding agents write frontend code fast, but they can't see it run. This is the flow I use to fix that, with a signup form that fails on submit as the example. The Old Way 1. The agent changes the form. 2. You open the page, click submit, and nothing happens. 3. You open DevTools, find a 422 in the Network tab, and copy the response. 4. You paste it into the chat. The agent guesses a fix. 5. You reload. Now the console shows a TypeError. You copy and paste again. You're the agent's eyes, and most of your time goes to copying, not thinking. The New Way 1. You ask: "Submit the signup form on localhost:3000 and tell me why it fails." 2. The agent clicks submit, reads the 422 response and the console, and matches them to the code. 3. It explains the cause and proposes a fix. 4. You check that explanation against what you see in the browser, then approve or push back. flowchart TB accTitle: The old way and the new way accDescr: In the old way, the agent writes code, the browser shows an error, and you copy that error back to the agent. In the new way, the agent reads the browser through MCP and reports its findings to you, and you validate them before it continues. subgraph Old direction TB a1[Agent] -- writes code --> b1[Browser] b1 -- error --> y1[You] y1 -- paste --> a1 end subgraph New direction TB a2[Agent] -- writes code --> b2[Browser] b2 -- MCP --> a2 a2 -- findings --> y2[You] y2 -- validate --> a2 end Old ~~~ New The copy-paste is gone. You're still there, in a different role. This is human in the loop (HITL): the agent gathers evidence, and you validate it. Don't trust it 100%. It can misread a trace, or silence an error instead of fixing it. The HITL notes in this post mark where to look yourself. Cover Every Scenario Browser access lets the agent put a page through every scenario your customers hit, not only the one where everything works: | Scenario | What the customer should get | | ------------------------------------------- | ------------------------------------------ | | [Success](#the-debug-loop) | The flow works end to end | | [Slow](#testing-slow-and-failing-requests) | A loading state, no double submits | | [Error](#testing-slow-and-failing-requests) | A clear message, their input kept, a retry | | [Performance](#improving-core-web-vitals) | Fast loading, no layout shifts | | [Accessibility](#checking-accessibility) | Works with a keyboard and a screen reader | The rest of this post shows how to set it up, then walks through each one. The Tools Two MCP servers give an agent a browser. MCP is an open standard, so neither is tied to Claude Code. Both work in Cursor, VS Code with Copilot, Codex, and Gemini CLI. Chrome DevTools MCP Chrome DevTools MCP is Google's MCP server for Chrome. It lets the agent open pages, click, and read what you see in DevTools: - Console: errors, warnings, and logs - Network: requests, status codes, and payloads - Performance: traces with Core Web Vitals like LCP and CLS - Accessibility: Lighthouse audits and the accessibility tree - Emulation: slow networks, offline mode, CPU throttling, dark mode, reduced motion, and forced colors Playwright MCP Playwright MCP is Microsoft's MCP server for browser automation. It drives Chromium, Firefox, and WebKit, can make a single request fail, and helps the agent write end-to-end tests you can rerun. Installing Them Most agents read the same config: { "mcpServers": { "chrome-devtools": { "command": "npx", "args": ["-y", "chrome-devtools-mcp@latest"] }, "playwright": { "command": "npx", "args": ["@playwright/mcp@latest", "--caps=network"] } } } The --caps=network flag turns on Playwright MCP's request mocking. In Cursor, add the config under Settings > MCP. In VS Code, both READMEs have one-click install buttons. In Claude Code, two commands add both: claude mcp add chrome-devtools --scope user npx chrome-devtools-mcp@latest claude mcp add playwright -- npx @playwright/mcp@latest --caps=network Run /mcp to confirm they're connected. Then ask the agent to open your local app and list the console messages. By default, Chrome DevTools MCP starts its own Chrome. To use the one you already have open, add --autoConnect. It needs Chrome 144 or later, with remote debugging allowed at chrome://inspect/#remote-debugging. Which One When Use both, for different jobs. Chrome DevTools MCP looks inside one page: debugging, comparing, and measuring. Playwright MCP fails requests on purpose and writes tests you can rerun in any browser. flowchart TD accTitle: Choosing a browser MCP server accDescr: To debug, compare pages, or measure performance in Chrome, use Chrome DevTools MCP. To write end-to-end tests, mock failed requests, or check Firefox and Safari, use Playwright MCP. need{What do you need?} need -- "debug, compare,<br>measure" --> devtools[Chrome DevTools MCP] need -- "e2e tests, mocks,<br>other browsers" --> playwright[Playwright MCP] The Debug Loop Start with the success path: the flow working end to end. With browser access, getting there follows the same loop every time. The agent changes the code, reloads the page, and reads the signals. You review what it found and steer it when it chases the wrong cause. flowchart TD accTitle: The debug loop accDescr: The agent edits the code, reloads the page, and reads the console, network, and performance trace. You review what it found. If the issue isn't fixed, you steer the agent and it edits again. When it's fixed, you ship. edit[Agent edits code] --> reload[Reload page] --> read[Agent reads signals] read --> review[You review findings] review --> fixed{Fixed?} fixed -- no, you steer --> edit fixed -- yes --> ship[Ship] > HITL: Keep the browser window visible while the agent works. When it says the bug is fixed, reproduce it yourself before you believe it. The two signals you'll read most are console errors and network requests. Console Errors My prompt: "Open /signup, submit the form, and list the console errors. Explain the cause before changing anything." The agent reads the error and its stack trace, opens the file it points to, and tells you what it thinks went wrong. You read that explanation before any code changes. > HITL: An error that disappears isn't always fixed. Check the diff: the agent may have wrapped it in a try/catch or removed the code that logged it. Network Requests My prompt: "Submit the form and show me the request and response for /api/signup. Compare the payload with what the backend expects." The agent lists the requests, opens the failing one, and compares its body with the code that builds it. A misnamed field or a missing header shows up right there. > HITL: Check the request against the API spec, not the agent's reading of it. Changing the frontend to accept a broken response hides a backend bug. Testing Slow and Failing Requests Customers rarely see a crash. They see a failure handled badly: a spinner that never stops, a blank page, a form that loses what they typed. The agent can slow things down or break them on purpose and show you what customers see. Each server does this differently: - Playwright MCP fails one request: browser_route makes an endpoint return a 500, a 404, or a malformed body. - Chrome DevTools MCP degrades the whole page: emulate sets Slow 3G, offline mode, or CPU throttling. It can't mock a single request. My prompt, combining both: "Make POST /api/signup return a 500, submit the form, and screenshot what the user sees. Then try it on Slow 3G." Slow On Slow 3G or with the CPU throttled, check what the customer gets: - A loading state that shows up right away and ends, with an error if it takes too long - A submit button they can't press twice - Content that doesn't jump around when it arrives Error With a request failing, check what the customer gets: - A message in plain words that says what to do next, not a stack trace or raw JSON - Their input still in the form - A retry that works - Focus moved to the error, and the error announced to screen readers Once a state looks right, lock it in with Playwright's page.route() so it stays that way: test('signup keeps the input and offers a retry when the API fails', async ({ page, }) => { await page.route('**/api/signup', (route) => route.fulfill({ status: 500 })); await page.goto('/signup'); await page.getByLabel('Email').fill('ada@example.com'); await page.getByRole('button', { name: 'Sign up' }).click(); await expect(page.getByRole('alert')).toContainText('Try again'); await expect(page.getByLabel('Email')).toHaveValue('ada@example.com'); }); > HITL: The agent can confirm an error message appears. Only you can judge whether it helps. Read each error state as a customer would: is it clear, kind, and does it say what to do next? Improving Core Web Vitals Slow requests are one side of speed. The other is how fast the page loads and settles, and that's where browser access helps most. Without it, the agent guesses from the code. With it, the agent records a trace, sees which element is the LCP and what shifts the layout, and measures again after each change. My prompt: "Record a performance trace of the home page with the CPU throttled 4x. Tell me the LCP element and what shifts the layout, then suggest one change at a time." That turns "this might be faster" into numbers. The agent proposes a change, reruns the trace, and keeps it only if LCP or CLS improves. > HITL: Read the trace yourself before accepting a change. One run is noise, so ask for several. And the trade-offs are yours: preloading an image or inlining CSS can win a metric and cost something else. Checking Accessibility An accessible page works for every customer: people on a keyboard, on a screen reader, or who need more contrast or less motion. The agent can check part of this in the browser. Chrome DevTools MCP runs a Lighthouse audit and reads the accessibility tree, the names and roles a screen reader announces. It also turns on the settings some customers rely on: forced colors, higher contrast, and reduced motion. My prompt: "Run a Lighthouse accessibility audit on /signup, then tab through the form and tell me where the focus goes." Lock the fixes in with axe in your Playwright tests: import AxeBuilder from '@axe-core/playwright'; test('signup has no detectable accessibility violations', async ({ page }) => { await page.goto('/signup'); const results = await new AxeBuilder({ page }).analyze(); expect(results.violations).toEqual([]); }); > HITL: Automated checks catch only some accessibility issues. A clean audit doesn't mean the page works with a screen reader. Tab through it yourself, and try VoiceOver or NVDA on the flows that matter. Migrating Legacy Code Without Regressions A migration has to keep every scenario working. The worst migration bug is a new page that looks almost like the old one, so capture how the legacy page behaves before you change anything. Start with a Contract Write down what must stay the same. This is the contract, and every test after it checks against it. ## Contract: /checkout - Same visible text and layout at 390px and 1280px - Same API requests, in the same order, with the same payloads - No new console errors or warnings - LCP and CLS no worse than the legacy page - Every action reachable with the keyboard The idea is the same as in [MigFlow](/posts/migflow-contracts-for-ai-migrations): agents need a contract, not a tutorial. > HITL: You write or approve the contract. The agent can draft it from the legacy page, but it can't know which behavior your users depend on. Cover the Legacy Page with Tests Many legacy projects have no end-to-end tests. With Playwright MCP, the agent walks through the legacy page in a real browser and writes a Playwright test for each line of the contract. Run them against the legacy page first. They must pass there, so they describe what the page does today, quirks included. Playwright's toHaveScreenshot() saves screenshots of the legacy page as the baseline. Visual changes then show up as a pixel diff, not a judgment call: test('checkout looks the same as the legacy page', async ({ page }) => { await page.goto('/checkout'); await expect(page).toHaveScreenshot('checkout.png', { fullPage: true }); }); Create the baseline from the legacy page with npx playwright test --update-snapshots. After that, every run compares against it. > HITL: Read every test. A test that passes no matter what protects nothing. Some quirks it captures are bugs you'll want to fix, not keep. Migrate and Rerun the Same Tests Now migrate, and run the same tests against the new page. A failing test is a regression. When one fails, the agent uses Chrome DevTools MCP to compare both pages and find out why. The tests stay in CI after the migration, so the next change is covered too. flowchart TD accTitle: Migrating without regressions accDescr: Write the contract, then cover the legacy page with Playwright tests. Migrate the code and run the same tests. If they fail, debug with Chrome DevTools MCP and migrate again. When they pass, you review and ship. contract[Write the contract] --> cover[Test the legacy page] cover --> migrate[Migrate the code] migrate --> pass{Same tests pass?} pass -- no --> debug[Debug with DevTools MCP] debug --> migrate pass -- yes --> review[You review and ship] > HITL: When a test fails, you decide whether the page or the test is wrong. Don't let the agent update a screenshot baseline or loosen an assertion to go green without your OK. Limits - The agent can be confidently wrong. It will explain a wrong cause as clearly as a right one. - It's slower than reading the code when the bug is obvious. - Traces and logs fill the context window, so ask for the specific signal you need. - The agent can read cookies and local storage. Add --isolated for a temporary profile, and be careful with --autoConnect, which uses the Chrome you're signed in to. - Performance traces may send page URLs to Google's CrUX API. Add --no-performance-crux when you debug internal URLs. Try It Start with one prompt in any agent: "Open localhost:3000, list the console errors, and explain the cause before fixing anything." Then try the other scenarios on one page: "Load the checkout page on Slow 3G, then with the payment request failing, and screenshot what the customer sees in each case." Migrating a page? Write the contract, then ask: "Write Playwright tests for this contract and run them against the legacy page." Run the same tests after the migration. A Tool in the Engineer's Hands Success, slow, error, performance, accessibility: the agent can now put a page through every scenario and bring you the evidence. That's a powerful tool in the engineer's hands. It doesn't decide what the evidence means. Every HITL note above comes down to the same habit: keep your eyes on the browser, and treat the agent's conclusions as claims to check, not facts. As I wrote in AI Writes Code. You Own Quality., speed without judgment means shipping bugs faster. Browser access doesn't change who owns the fix. It gives you better evidence to own it with. The agent gets eyes on the browser. You keep the judgment.
Give Claude Code a real browser with Playwright MCP Claude Code can write a login form, but it cannot see whether the form works. Give it a real browser and it can open the page, click through, and tell you what broke. Playwright MCP is Microsoft's Model Context Protocol server that does exactly this. Instead of screenshots, it hands the model Playwright's accessibility tree: a structured text view of the page. That means no vision model is needed, and actions are more deterministic than clicking at pixel coordinates. Our shorter how-to is on the Deduped use-case page. Here is the full setup. Requirements - Node.js 18 or newer - An MCP client: Claude Code, Codex, VS Code, Cursor, Windsurf, Claude Desktop, Goose and others all work Step 1: the standard config Most clients accept this config block: { "mcpServers": { "playwright": { "command": "npx", "args": ["@playwright/mcp@latest"] } } } Paste it into your client's MCP settings and restart it. Step 2: add it to Claude Code Claude Code can register MCP servers from the command line: claude mcp add playwright npx @playwright/mcp@latest Run claude mcp list afterwards to confirm it is registered. For Codex and other clients, use the config block above or the client's own MCP add command; the repo README lists per-client instructions. Step 3: give it a real task Skip "test my site". Be specific: > Open localhost, fill the form with a test email, submit it, and tell me what the page shows. If there is an error, list the exact message and which field caused it. The agent calls tools to navigate, read the accessibility snapshot, type and click, then reports what it found. This is a good loop for exploring a flow you just built, reproducing a bug a user described, or checking a form after a refactor. MCP or the CLI? The README is candid about a tradeoff. Coding agents increasingly prefer the Playwright CLI with skills, because CLI calls avoid loading large tool schemas and verbose accessibility trees into the model's context. That matters when you are also juggling a big codebase and tests inside a limited context window. The README's guidance: use the CLI plus skills for high-throughput coding agents, and use MCP for specialized loops that benefit from persistent browser state, rich introspection and iterative reasoning over page structure, such as exploratory automation, self-healing tests or long-running autonomous workflows. If your use is "poke at my app and tell me what is wrong", MCP is a fine fit. If you are burning context, try the CLI at microsoft/playwright-cli. Tips - Keep sessions short. Accessibility snapshots of busy pages are large and eat context quickly. - Point it at localhost or a staging site. Do not let an agent click around production with real accounts. - Pin the version (@playwright/mcp@0.0.x) if you need reproducible behavior, since @latest can change under you. - If you need Firefox or WebKit instead of Chromium, see the Deduped page on running it in other browsers. Who this is for Anyone building web apps with an AI coding agent who is tired of the "it should work now" guess. It will not replace a proper test suite, but it closes the gap between writing code and seeing it run. Repo: microsoft/playwright-mcp. More on Deduped: Playwright MCP in Claude Code or Codex. --- Get one email every Monday with the week's hottest AI repos and exactly how to use them: subscribe free at dedupedai.com
GitHub Copilot in VS Code: Model Context Protocol (MCP) in Action [Part 6/7] Channel: The AI Blueprint Series: GitHub Copilot in VS Code (Definitive Guide) - Episode 6 HOOK DESCRIPTION: Until now, Copilot has been confined to your local repository. In Episode 6 of our VS Code Copilot Masterclass, we connect Copilot to live databases, browser automation, and external documentation using the Model Context Protocol (MCP). Learn how to configure portable MCP servers in ~/.copilot/mcp-config.json and .mcp.json, understand why .vscode/mcp.json is deprecated, inspect live schemas with PostgreSQL/SQLite, automate end-to-end testing with Playwright, and enforce bulletproof security with Workspace Trust and process sandboxing. CHAPTERS: 00:00 - Introduction: Breaking Out of the Sandbox 00:51 - What is MCP & Why Standardized Protocols Win 02:07 - Configuring Servers & The Deprecation Warning 04:24 - Discovering Servers: Gallery & Import 05:30 - The 3 Capabilities: Tools, Resources, and Prompts 06:49 - Live Integration 1: Database & Schema Audits 08:10 - Live Integration 2: Browser Testing & Live Web Docs 09:27 - The 3-Step Verification & Debugging Workflow 10:30 - Security Guardrails: Workspace Trust & Sandboxing 12:05 - Recap & Your 5-Minute Challenge RESOURCES MENTIONED: • Model Context Protocol Specification: modelcontextprotocol.io • VS Code MCP Documentation: code.visualstudio.com • Context7 Real-Time Documentation Server: context7.com • Playwright MCP Server: microsoft/playwright-mcp • The AI Blueprint Masterclass Repository: github.com/theaiblueprint #GitHubCopilot #MCP #ModelContextProtocol #VSCode #Playwright #PostgreSQL #TheAIBlueprint #SoftwareEngineering
Chrome DevTools MCP in Claude Code (setup, attach mode, vs Playwright MCP) TL;DR: Chrome DevTools MCP is the Chrome DevTools team's open-source MCP server. It lets Claude Code, Cursor, Codex or Gemini CLI drive a real Chrome and use DevTools features: network requests, console, screenshots, performance traces, Lighthouse and heap snapshots. Install it with claude mcp add chrome-devtools --scope user -- npx chrome-devtools-mcp@latest. Add --autoConnect (Chrome 144+) to let it attach to the Chrome you're already signed in to. It's great for debugging the page in front of it. It's a poor fit for "map this app's whole API". Why I wanted it My agent kept writing frontend fixes it couldn't check. With a browser MCP server it opens the page, reads the console, looks at the failing request and tells me what broke. The Chrome team shipped this as a public preview in September 2025, and it now has around 60 tools (some behind opt-in flags). Setup You need Node.js LTS and current stable Chrome. Claude Code claude mcp add chrome-devtools --scope user -- npx chrome-devtools-mcp@latest Or the plugin, which also installs skills for a11y, cookies, LCP and memory leaks: /plugin marketplace add ChromeDevTools/chrome-devtools-mcp /plugin install chrome-devtools-mcp@chrome-devtools-plugins Cursor (Settings → MCP → New MCP Server) and most other clients: { "mcpServers": { "chrome-devtools": { "command": "npx", "args": ["-y", "chrome-devtools-mcp@latest"] } } } Codex / Gemini CLI codex mcp add chrome-devtools -- npx chrome-devtools-mcp@latest gemini mcp add chrome-devtools npx chrome-devtools-mcp@latest First prompt to try: Check the performance of https://developer.chrome.com. You'll see a Chrome window open and a trace get recorded. The network tools There are two: - list_network_requests: requests for a page since the last navigation. Filter by resourceTypes, paginate with pageSize/pageIdx, and set includePreservedRequests to reach back 3 navigations. - get_network_request: one request with headers (including Cookie and Set-Cookie) and bodies. responseFilePath writes a big body to disk instead of into the context window. The trick I like most: call get_network_request with no reqid and it returns whatever request you have selected in the DevTools Network panel. I click the broken call, then type "why did this 403?". If headers carry tokens you'd rather not send to a model, start the server with --redactNetworkHeaders. Attach mode (your signed-in browser) By default the server launches Chrome with its own profile in ~/.cache/chrome-devtools-mcp/chrome-profile. --isolated uses a throwaway profile instead. To debug something behind your real login: 1. Open chrome://inspect/#remote-debugging in Chrome 144+ and allow incoming connections. 2. Add the flag: "args": ["-y", "chrome-devtools-mcp@latest", "--autoConnect"] 3. Approve the permission dialog Chrome shows each time the server connects. A "Chrome is being controlled by automated test software" banner stays up while it's attached. No --autoConnect (sandboxes, older Chrome)? Start Chrome yourself and point the server at it: /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \ --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-profile-stable "args": ["chrome-devtools-mcp@latest", "--browser-url=http://127.0.0.1:9222"] Heads up: attach mode gives the agent your cookies and signed-in accounts. Google's own docs say to only use it with agents you trust. Also, usage statistics are on by default (--no-usage-statistics), and performance tools can send trace URLs to CrUX (--no-performance-crux). Chrome DevTools MCP vs Playwright MCP Playwright MCP (claude mcp add playwright npx @playwright/mcp@latest) overlaps a lot. How I pick: | | Chrome DevTools MCP | Playwright MCP | |---|---|---| | Browsers | Chrome, Chrome for Testing | Chrome, Firefox, WebKit, Edge | | Page model | screenshots + text snapshot | accessibility tree, no vision needed | | Perf insights / Lighthouse / heap | yes | Playwright traces via --caps=devtools, no Lighthouse or heap tools listed | | Network | list + get (headers, bodies) | list (URL regex) + get, mocking via --caps=network | | Existing browser | --autoConnect, --browser-url | --extension, --cdp-endpoint | User flows and cross-browser checks: Playwright. "Why is this page slow or erroring in Chrome": DevTools MCP. Playwright's README also notes that coding agents may get on better with its CLI + skills, since those calls cost fewer tokens than MCP. Where it stops for API work Both servers only see what the browser loads while the agent is connected. When I want the agent to understand the whole API of an app, that hurts: 1. The request list resets per navigation (3 back at most), so the agent has to click through every screen. 2. Each screen costs tool calls and context. 3. /orders/1042 and /orders/1043 come back as separate URLs, so the agent has to figure out they're one endpoint. 4. Real logged-in traffic means attach mode and handing over my session. 5. Close the browser and the traffic is gone. For that job I use Netraptor, a Chrome extension I work on. It records the app's fetch/XHR calls while I browse normally (or crawls same-site pages), groups them into endpoints like /orders/{id}, and its Pro plan has a local, read-only MCP server so the agent can ask "what does GET /orders/{id} return?" from real recorded responses. It has its own gap: it records from inside the page, so browser-added headers like Cookie aren't in its copy. DevTools MCP shows those. So I run both: Netraptor for "what does the API look like", DevTools MCP for "go reproduce this". The full guide, with links to every doc above, is at netraptor.dev.
3 MCP Servers That Make Your AI Coding Assistant More Useful Your AI can explain the task. These three MCP connections help it work with the tools and information the task needs. • Context7 — library documentation and code examples. • Playwright — browser navigation, interaction, and page inspection. • GitHub MCP — repositories, issues, and pull requests. See how they fit into one workflow: read a bug report, check the documentation, then verify the fix in a browser. Start with the connection that solves your bottleneck. Keep access limited and review changes before they go live. Follow Stack Made Clear. Understand the tech. Know when to use it. Official resources: Context7: upstash/context7 Playwright MCP: microsoft/playwright-mcp GitHub MCP: github/github-mcp-server Interfaces shown are illustrative animations.
Best GitHub repos for Claude Code? 4 we actually ran Best GitHub repos for Claude Code: rea, Playwright MCP, Context7 and Chrome DevTools MCP, each run in a real test Four GitHub repos for Claude Code, each run for real in a throwaway sandbox (sped up parts marked on screen). rea and the control test: 16 Oct. Playwright MCP and Context7: 16 Oct takes. Chrome DevTools MCP: take of 18 Oct. Star counts as of 18 Oct. morluto/rea microsoft/playwright-mcp upstash/context7 ChromeDevTools/chrome-devtools-mcp Full test: youtube.com Subscribe to @readmelied for more tools we run and check against their README. README Lied runs trending open-source tools in a sandbox and checks what they really do against what their README says. New tests every week. #ai #github #coding #readmelied #claudecode #playwright
GitHub AI Skills: What These Tools Can Actually Do Explore GitHub projects behind reusable AI skills, code-driven video creation, browser automation, and AI-assisted reverse engineering. This episode looks at Anthropic Agent Skills, Remotion, Playwright MCP, and Browser Use, with a focus on what demonstrations show and where human judgment still matters. Which project would you try first? Tell us in the comments. Subscribe to World of Curios for technology stories and clear explanations. Projects discussed: anthropics/skills agentskills/agentskills remotion-dev/skills microsoft/playwright-mcp browser-use/browser-use #GitHub #AI #OpenSource
Want an AI agent to interact with websites? 🌐 Playwright MCP exposes browser actions through structured tools. Useful for testing and web workflows. 🧪 microsoft/playwright-mcp #MCP #浇朋友 #蓝朋友 #互关 #fo
想让 AI 在网页上点击、填写表单?🌐 Playwright MCP 把浏览器交互变成 MCP 工具,Agent 能读取页面结构并执行操作。适合自动化测试。🧪 microsoft/playwright-mcp #MCP #浇朋友 #蓝朋友 #互关 #fo