ChromeDevTools

Stars and mentions

Last 30 days, Oct 5 – Nov 3

GitHub stars1,279
mentions42
0255075100Oct 5Oct 19Nov 3
UTC days · repositories ChromeDevTools owns4 repositories

Package downloads

Cumulative recorded downloads · since 2025-10-19

npm62.6M
015.7M31.3M47M62.6MOct 5Oct 19Nov 3
Oct 17npm: 1/1 packages observed

Across 1 known packages in repositories ChromeDevTools owns. Cumulative totals include recorded downloads before the selected range. Missing observations leave gaps; totals may be incomplete.

Top repositories

ChromeDevTools’s repositories ranked by new forks, as on trending.

Loading

Contributes to

Repositories outside ChromeDevTools’s account where ChromeDevTools opened or reviewed pull requests in the past 365 days.

Who noticed ChromeDevTools

Everyone who starred or forked ChromeDevTools’s repositories since the archive began in 2011.

Notable accounts

Ordered by the stars their own repositories have received.

Biggest fans

Accounts that starred the most of these repositories.

Breakout weeks

Each repository’s best week of new stars, with the release published around it.

Mentions

40posts
Nov 41 post
  1. Stop being your AI's eyes and hands: pwa-debug lets Claude debug your live, logged-in browser If you've debugged a web app with an AI assistant, you know the loop: 1. The AI asks what the console says. You copy and paste it. 2. It asks what the component's state is. You open React DevTools and describe it. 3. It asks you to click the button and report what happens. You click it. 4. It asks for a screenshot. You take one. You end up as the AI's eyes and hands. That's slow, it loses information, and it doesn't work at all for the bugs that hurt most in PWAs: stale caches, service workers that won't update, install failures, and version skew after a deploy. I built pwa-debug to remove that loop. It's an open-source (MIT) MCP server plus a browser extension that gives an AI agent like Claude Code direct, structured access to your live, logged-in browser. That covers the DOM, console, network, framework state, store state, service workers, caches, and storage, and the agent can also interact with the page. npx -y @aryanduntley/pwa-debug@latest - 📦 npm: @aryanduntley/pwa-debug - 🐙 GitHub: aryanduntley/pwa-debug-layer --- The questions it answers These are the PWA problems people search for most. pwa-debug answers them by reading the runtime directly, without screenshots or OCR: | You ask | The agent calls | |---|---| | Why won't my service worker update? Why are some users on old code? | sw_status, pwa_update_analyze (waiting-vs-active versions, version-skew verdict) | | Why is my cache stale? Why are chunks 404ing after a deploy? | cache_list / cache_inspect / cache_match (entries with age, size, cache-control) | | Why won't my PWA install? | pwa_installability (structured { gaps[], fixes[] }, not just "manifest invalid") | | What's actually in IndexedDB right now? | idb_list / idb_query, storage_get | | Why does this component have the wrong state? | react_get_state, vue_get_state, store_get_state, redux_get_state | | Does anything break at 360px, in dark mode, in Spanish? | layout_sweep (one call, every page × width × scheme × state) | --- Highlights 🔐 It runs in your real browser profile Google's chrome-devtools-mcp is great, but it starts a fresh automated Chrome. That browser has none of your cookies, sessions, or extensions, and none of your real service-worker state. If your app sits behind a login, that's a problem. pwa-debug attaches to your normal profile by default, so the agent sees what you see: authenticated sessions, your real SW and cache state, and your extensions. ⚛️ Framework and store state that CDP can't reach A script injected into the page's MAIN world reads each framework through its own devtools hooks: - React fiber tree, props, state, and hooks - Vue 3 component tree and reactive state - Svelte components with source locations - Solid detection and element lookup - Redux, Zustand, Pinia, Jotai: read, subscribe to change deltas, and (opt-in) dispatch Every framework also supports find-by-text and find-by-role, so the agent can locate "the Submit button inside <CheckoutForm>" without guessing selectors. 🛠️ The full PWA diagnostics suite This is the part the project is named for. It covers service-worker lifecycle and versions, CacheStorage contents and age, installability gaps with per-gap fixes, a live capability matrix (Push, Background Sync, Periodic Sync, Badging, File System Access, Window Controls Overlay), IndexedDB and web storage, and pwa_update_analyze. That last tool combines SW status, cache ages, and recent 404s into a verdict such as "cached HTML is older than the JS it references", which is the classic cause of "why are some users on old code." pwa_snapshot produces one capped blob of the whole runtime state, which is useful for repros and bug hand-offs. 👆 The agent drives the page itself pdl_click, pdl_fill, pdl_submit, pdl_key_press, pdl_type_sequence, pdl_navigate, and pdl_new_tab are available, along with touch gestures: tap, double-tap, long-press, swipe, drag, scroll, and pinch. Events are dispatched as native-event sequences, so React's and Vue's delegated event systems fire properly. Targets use one locator format (selector, role, text, or a framework component id). 📱 Android phones over adb The extension can't run in Android Chrome, so pwa-debug connects to phones over adb and CDP and injects the same page-world code there. One call does the setup: pdl_android_attach({ open_url: "http://localhost:5173", reverse_ports: [5173] // phone's localhost:5173 → your dev server }) → { connectionId: "cdp:127.0.0.1:<port>:<tab>" } After that, every page tool works on the phone tab, including React state, stores, PWA diagnostics, gestures, and console and network capture, and you can watch it happen on the device. I verified this live on a Galaxy S24 Ultra (Android 16, Chrome 156). 📐 Responsive layout sweep One layout_sweep call goes through a matrix of pages × viewport widths × color schemes × app states (plus extra dimensions such as language). For each view it emulates the viewport over CDP and measures the page for: - horizontal page overflow and off-screen elements - tap targets below WCAG 2.2 minimums - clipped or ellipsized text (useful when testing longer translations) - fixed bars that aren't fully on screen - clipped focus and selection rings - unresolved copy like {{name}}, undefined, NaN, [object Object] - page errors during the view, plus optional WCAG AA contrast It groups the results into distinct problems, so 150 raw findings that come from two root causes are reported as two groups, with screenshots if you ask for them. You can also pass your own custom_checks expressions. In the largest real test it swept an 83-page prototype across 4,812 views. 🔌 Library popups, replay, and source maps - WalletConnect, RainbowKit, and SDK modals that live in shadow roots or nested iframes can be recorded, replayed, and correlated with the console errors and failed requests that occurred while they were open (popup_failures). - rrweb session recording and replay, plus persistent ring buffers that survive navigations and reloads. - source_map_resolve maps minified stack frames back to src/file.ts:line:col. 🤖 Built for agents, not humans Every tool returns { ok, data, error?, next_steps[] }. The next_steps field tells the agent what to call next based on the actual result, so it recovers from setup gaps and errors without you stepping in. pdl_help serves the whole usage guide as data, and filters keep each response to the slice the agent asked for instead of dumping the full DOM. --- Works with chrome-devtools-mcp, doesn't replace it pwa-debug is complementary to chrome-devtools-mcp, and the two tool sets don't overlap. pwa-debug launches a browser with a live debug port, and chrome-devtools-mcp attaches to that same port. Both then drive the same tab over separate channels: CDP for one, extension and page-world injection for the other. pdl_launch_browser({ browser: "brave", mode: "sandbox-persistent" }) pdl_register_chrome_devtools() // pins chrome-devtools-mcp to the right port for you --- Getting started As a Claude Code plugin (no clone, no build) /plugin marketplace add aryanduntley/pwa-debug-layer /plugin install pwa-debug@pwa-debug /reload-plugins Or with any MCP client claude mcp add pwa-debug --scope user -- npx -y @aryanduntley/pwa-debug@latest Then tell your agent: > **Set up pwa-debug and open my app at http://localhost:5173.** The setup is agent-driven. It runs pdl_check_setup, registers the native-messaging host, launches a browser with the extension preloaded, and confirms the round-trip with session_ping. Each step's next_steps tells it what to do next. Browser support: Chromium-family browsers (Chrome, Chromium, Brave, Edge, Vivaldi, Opera) and Android Chrome over adb. Brave and Chromium give the smoothest experience, because Google Chrome 142+ removed --load-extension and so needs one manual "Load unpacked" step. --- How it works Claude Code ──MCP──► Native host (MCP server, ring buffers, replay store) │ native messaging ▼ Extension service worker │ ┌─────────────┴──────────────┐ ▼ ▼ Content script Page-world script (MAIN world) DOM observe, actions React/Vue hooks, fetch/XHR patch, stores - The extension handles the page: DOM, content scripts, and page-world hooks injected on every load. - The native host handles persistence and the MCP server. - MCP is the contract with the AI. The whole codebase is TypeScript written in a strict functional style: pure functions, immutable data, no classes, and side effects kept at the edges. --- Help wanted 🙏 Development happens on Linux, where everything is live-tested. The macOS and Windows code paths (browser detection, profile paths, native-messaging registration) are written and unit-tested but have never run on real hardware. If you're on a Mac or a Windows machine, trying it and opening an issue with the output would help more than anything else right now. Firefox support is on the roadmap (via WebDriver BiDi). Stars, issues, and PRs are all welcome. - ⭐ GitHub: aryanduntley/pwa-debug-layer - 📦 npm: npmjs.com If you try it on a PWA bug, I'd like to hear how it went in the comments, whether it worked or not.

  2. Chrome Is Open Source and Still Hard to Reverse Engineer. Here's Where the Real Work Is! You can read Chromium's source today, and people still spend years reverse engineering Chrome. The code isn't the hard part. The hard parts are the process model the code implies, the Google layer on top of it, and the behavior no design doc covers. This is a map of where that work pays off, and which repos and docs got there first. The Part You Don't Have to Reverse Start with what's documented, because most "Chrome internals" posts reverse-engineer things that are written down. The Chromium design docs tell you to begin with multi-process architecture. Most of the other design documents assume you've read it. The model is simple to state. The browser and renderers talk over Mojo or the legacy IPC system, and each renderer process has exactly one RenderProcess object. Mojo is also how the browser's own services talk to each other. The network service is designed as a Mojo service that doesn't need to know which thread or process it runs on. It can run in a utility process or inside the browser process. Site Isolation is where this pays off. Each renderer process can be locked to documents and workers from a single site, even when those documents sit in iframes. It isn't uniform across platforms. Desktop gets full site-per-process. Android gets a partial mode on devices with 2+ GB of RAM. Chrome for iOS runs on WebKit, which has no out-of-process iframe support. So "Chrome's security model" is really three models, and the one you reason about depends on the platform. The best primary source here is the paper from Charles Reis and the Chrome team on deploying Site Isolation. It covers the performance and compatibility problems of retrofitting a production browser with the new architecture. Read it for the tradeoffs the design docs leave out. If you want to test the boundary yourself, the security docs describe how. Passing --enable-features=MojoJS lets you call Mojo methods from JavaScript, which simulates a compromised renderer. That makes the renderer-to-browser Mojo interfaces your real attack surface. In the doc's own framing, calling a Mojo API can mean code execution in the browser process, which is a far worse outcome than code execution in the sandboxed renderer. V8 Is a Negotiation, Not a Pipeline Most developers know V8 "has a JIT." The useful model is that it's a tiering policy driven by runtime feedback. Maglev exists because the gap between Sparkplug and TurboFan was too wide. Until 2021 V8 had only Ignition and TurboFan, then added Sparkplug, and Maglev arrived in Chrome M117. The docs put the cost tradeoff at Maglev compiling about 10x slower than Sparkplug and about 10x faster than TurboFan. Per one writeup, TurboFan's internals were rebuilt onto Turboshaft by March 2025 without adding a fifth tier. The practical reverse-engineering move is reading the thresholds. v8pedia quotes the flag definitions for invocation counts at each tier, such as 400 for Maglev and 3000 for TurboFan. Treat those as a snapshot, since flag defaults change between V8 versions. Verify them against the source for the version you're analyzing. For the exploitation side, this curated resource list is the best single index I've found. It points to bug-hunting-101, Jack Halon's browser exploitation series and doar-e's TurboFan introduction. The list flags some entries as outdated, so check before relying on them. The Repos That Did the Real Reversing Three projects stand out. Each reverses a different layer. ungoogled-chromium reverses the Google dependency graph. Its premise is that Chromium still has some dependency on Google web services and binaries even without signing in. The interesting part is the method. It uses domain substitution, replacing Google domains in the source with non-existent ones ending in qjz9zk, plus binary pruning. A fail-safe blocks internal requests to those domains, in case Google introduces new components its patches don't disable. The patch set is effectively a map of every place Chromium phones home. chrome-devtools-mcp is Google reverse-exposing its own browser to agents. It's a TypeScript server wrapping Chrome DevTools and Puppeteer so that coding agents like Gemini, Claude, Cursor or Copilot can control and inspect a live Chrome. One detail matters before you point it at anything sensitive. It collects usage statistics and checks for updates by default, with flags to turn both off. The README also warns that it exposes browser content to the MCP client. js-reverse-mcp and the api-mapper skill turn Chrome into a reverse-engineering instrument for the sites inside it. The first traces function calls through logpoints and injects scripts before page load. The second captures XHR/Fetch traffic over CDP, inspects JS bundles when requests contain computed values, and probes endpoints with curl. Both reflect the same shift: the browser is now the reverse-engineering tool as well as the target. Where Google's Layer Shows Up: On-Device AI The most current example of Chrome diverging from Chromium is Gemini Nano. The APIs and the model are both built into Chrome, with the model downloaded on first use. It isn't on mobile, and from Chrome 140 it supports English, Spanish and Japanese. One analysis notes that when conditions are met, Chrome downloads the model in the background with no installation prompt. You can inspect all of it. Gemini Nano in Chrome documents the flags, the chrome://on-device-internals page, and a useful gotcha: Chrome's internal pages are built from web components with content in shadow DOM, so automation has to walk shadow roots. It reports a model footprint of roughly 4 GB on its test machine. That's one machine's number, and the docs say the size varies with updates. Why This Matters Beyond Chrome Three takeaways hold up across everything above. First, the real boundary is Mojo, not the tab. If you want to understand Chrome's security, read the interface definitions between renderer and browser. Second, Chrome is a platform with a diverging proprietary layer. Gemini Nano, DevTools-for-agents and the Google service dependencies that ungoogled-chromium strips out all sit above or beside the open core. Third, the browser has become an agent runtime. When Google ships an MCP server for its own browser, the reverse-engineering target moves from "what does Chrome do" to "what can an agent do through Chrome." Where to Start Read the multi-process architecture doc first. Then use Chromium Code Search to follow one navigation from RenderProcessHost outward. Use the ungoogled-chromium patch set as your map of Google dependencies, and run chrome-devtools-mcp against a throwaway profile. Chrome's code was never the secret. What you learn is how a billion-user browser makes its tradeoffs, and Google has written most of that down. Follow for more coverage on MCP, agentic AI, and AI infrastructure.

    7 reactions
  3. 05|Chrome DevTools MCP 網頁哪裡壞了,光看截圖不一定找得到。 這個工具讓AI代理使用Chrome DevTools,查看網路請求、網頁狀態和效能資料,幫忙追查問題。 ChromeDevTools/chrome-devtools-mcp

    1 like · 12 views
  4. 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
  5. agent 调网页 bug,全靠猜控制台报错? chrome-devtools-mcp 是 Chrome 官方 DevTools MCP:操控真浏览器,查控制台、网络、性能,附排查 skill。 调前端的话,真浏览器调试比只看日志强。 先让它查哪类问题,白屏还是接口报错? #浏览器调试 #开源 @grok ChromeDevTools/chrome-devtools-mcp

    4 likes · 303 views
  6. YouTube · · YouTube description · README Lied · ChromeDevTools/chrome-devtools-mcp

    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

    2 likes · 2 comments · 346 views
  7. サードパーティのツールを chrome-devtools-mcp に公開する仕組みあるんだ github.com/ChromeDevTools/chrome-devtools-mcp/blo…

    6 likes · 1 repost · 521 views
  8. your coding agent can read code. can it debug Chrome? Chrome DevTools MCP lets Codex inspect console errors, network requests & performance traces. install: codex mcp add chrome-devtools -- npx chrome-devtools-mcp@latest ChromeDevTools/chrome-devtools-mcp t.co

    2 likes · 107 views
  9. Making my personal website callable for AI agents with WebMCP --- title: Making my personal website callable for AI agents with WebMCP published: true description: My agent-friendly website told browser agents it had no tools. I added WebMCP so they can search my posts, talks and events directly. tags: ai, webdev, agents, webmcp cover_image: prod-assets.cosmic.aws.dev canonical_url: builder.aws.com --- The first time someone mentioned WebMCP to me, I assumed it was a diagnostics tool for web apps. The name sounds like something you would open next to the network tab. My second guess was worse: I thought maybe it was a Playwright alternative. Luckily, I was wrong both times, and figuring out why is how I ended up adding it to salih.dev (where probably nobody would use). A few months ago I wrote about building an agent-friendly personal website with specs. The site serves Markdown to agents, has an llms.txt, and answers a set of .well-known discovery files. One of those files was /.well-known/webmcp.json, and it said, politely, that there were no browser tools here. In case you don't know me, I am a very open person, if I don't have something, I would say "I don't have it". But I also don't take "No" for an answer, even to myself. So let's see how I added this very useful set of features on a not very useful scenario for the sake of learning. > The code is in the salih-dev repository: the tools are in PR #15, and the speaker kit and discovery changes are in PR #16. What is WebMCP? WebMCP is a proposed web standard from the W3C Web Machine Learning Community Group, written by people from Microsoft and Google. It lets a web page declare tools that an AI agent running in the browser can call. The page registers each tool with a name, a description, a JSON schema for its input and a function that runs it: document.modelContext.registerTool({ name: "list_events", description: "List the conferences where Salih speaks...", inputSchema: { type: "object", properties: { when: { type: "string" } } }, execute: async (input) => { /* return the answer */ }, }); The "MCP" is the same Model Context Protocol you may already run on a server. The difference is where it lives. A server MCP exposes tools from a backend. WebMCP exposes tools from the page the user has open, with the user's session and the page's state. The tools I added My site has three kinds of content an agent might care about: blog posts, past talks and upcoming events. I wrote eight tools around them: | Tool | What it answers | |---|---| | get_site_overview | Where I am right now, content counts, my next event, the latest post, and the filter values the other tools accept | | search_site | Full-text search across posts, talks and events | | list_blog_posts | Posts filtered by tag, category or text | | read_blog_post | The full Markdown of one post | | list_talks | Past talks by topic, event type, year, or whether a recording exists | | list_events | Upcoming, past or all events | | get_speaker_kit | My bio, the topics I speak on, recent talks, where I am already booked, and how to reach me | | show_talks_on_page | Applies a filter on the Talks page so the visitor sees it too | The first seven are read-only and registered on every page. The last one only exists on /talks/, and it is the one I like most. It presses the page's real filter button, so the person watching sees the same list the agent is describing. The page's own controller stays in charge of the state, including its aria-pressed attributes. I kept everything read-only on purpose. There is a comment form on the site, and I thought about exposing it. An agent posting comments on my behalf is a decision I want to make separately, after I have watched how agents use the read tools. Step 1: Bake an index at build time The tools need data, and I did not want them scraping my own HTML. The site is built with Astro, so I added a static endpoint that writes everything the tools need into one JSON file. Create it under src/pages/api/webmcp-index.json.ts: export const GET: APIRoute = async () => { const [posts, talks] = await Promise.all([ getPublishedPosts(), getPublishedTalksSnapshot(), ]); return jsonResponse( buildSiteIndex({ siteName: site.name, siteUrl: site.url, posts, talkCards: projectTalkArchive(talks).cards, siteContent: getSiteContent(), }), { headers: { "Cache-Control": "public, max-age=300" } }, ); }; 1. It reads the same published posts and talks the pages use, so the tools never disagree with what a human sees. 2. buildSiteIndex flattens them into a small shape with titles, URLs, dates, tags and snippets. 3. The file is static. My content API starts the publisher build after every write, and that build regenerates the file, so there is no extra Lambda to run. One detail took me a moment. Events move from "upcoming" to "past" on their own, and a baked file does not know what day it is. So the index stores dates, and the tools decide upcoming or past in the browser against the visitor's clock. An event that ended yesterday shows as past even if I have not rebuilt the site since. Step 2: Register the tools only when the browser supports them Most visitors use a browser without WebMCP, and I wanted them to see zero difference. The entry point checks for document.modelContext and returns if it is missing. Add it to src/lib/webmcp/register-tools.ts: export async function registerWebMcpTools(): Promise<void> { const context = document.modelContext; if (context === undefined) return; try { await registerContentTools(context); await registerTalksPageTool(context); } catch (error: unknown) { // A registration failure must never break the page for the human visitor. console.warn("WebMCP tool registration failed", error); } } Then load it from a component with no markup, src/components/WebMcpTools.astro, and add that component to the base layout: <script> import { registerWebMcpTools } from "../lib/webmcp/register-tools"; void registerWebMcpTools(); </script> For types I used the webmcp-types package, pinned to 0.1.10, and referenced it from src/env.d.ts. That gives you WebMCP.ModelContext and the registerTool signature without writing your own copy of the API. Step 3: Write descriptions for a model, and check every input A tool description is a prompt. The agent reads it to decide whether to call the tool and what to pass. I wrote mine the way I would brief a colleague, including the defaults and the order of results: description: "List the conferences and events where Salih Güler speaks or runs workshops. 'upcoming' (the default) lists events that have not ended yet, soonest first; 'past' lists finished events, most recent first; 'all' lists both.", get_site_overview returns the exact tag, category and topic values the other tools accept, and its description tells the agent to call it first when it is unsure. That one line saves a lot of failed filter calls. The spec does not promise that the browser validates input against your schema. So every execute function checks its input again before using it: const query = optionalString(input.query); if (query === undefined) throw new Error("query must be a non-empty string"); The search and filter logic lives in src/lib/webmcp/queries.ts as pure functions, which made it easy to test without a browser. There are 12 tests for it, covering search ranking, filters, the upcoming and past split, post lookup and the speaker kit. Step 4: Add a speaker kit The first version answered questions about my content. Then I thought about who actually looks me up. Most of the time it is an event organizer deciding whether to invite me, and they want a bio, the topics I cover, proof that I can give a talk, and a way to reach me. Before, an agent had to stitch that together from four tool calls and the About page. So the index got a speaker block, built from the same src/config/site.ts that renders my About and Contact pages: speaker: { role: input.speaker.role, bio: input.speaker.bioShort, longBio: [...input.speaker.bioLong], focusAreas: [...input.speaker.focusAreas], aboutUrl: absolute("/about/"), contactUrl: absolute("/contact/"), profiles: input.speaker.socials.map((social) => ({ label: social.label, url: social.href, })), }, And src/lib/webmcp/queries.ts got a speakerKit function that combines it with the talks and events. It counts how many talks I have given per topic, so the agent sees what I talk about most: const topicCounts = new Map<string, { topic: string; talks: number; order: number }>(); for (const talk of index.talks) { for (const topic of talk.topics) { const key = normalize(topic); if (key.length === 0) continue; const entry = topicCounts.get(key); if (entry) entry.talks += 1; else topicCounts.set(key, { topic, talks: 1, order: topicCounts.size }); } } The function returns the topics sorted by talk count, my five most recent talks with slides and recordings, the next five events I am booked for, and the contact routes. My site lists no email address, so the kit says that directly and points to the profiles on the contact page. An agent should not invent an address because the field looked empty. Registering it looks like the other tools. The description names the situations where an agent should pick it: await context.registerTool({ name: "get_speaker_kit", title: "Speaker kit", description: "Get what an event organizer needs to invite Salih Güler as a speaker: his role and bio, focus areas, the topics he has spoken on with talk counts, his most recent talks with slide and recording URLs, the events he is already booked for, and how to contact him. Use this when someone wants to invite him, check his availability, or write a speaker introduction.", inputSchema: { type: "object", properties: {} }, annotations: readOnly, execute: async (_input, { signal }) => speakerKit(await loadIndex(signal), today()), }); Adding the speaker block changed the index shape, so I bumped its version from 1 to 2. Step 5: Tell the humans too The tools are invisible to a person reading the site. If someone finds this post and opens salih.dev, nothing on the page says what to ask. So the About page has a new section, "Use this site with an AI agent", with example prompts and the console check from the "Try it yourself" section below. The About page also has a Markdown version for agents, and I did not want the two to drift apart. Both now render from one small module, src/lib/webmcp/visitor-guide.ts: export const AGENT_GUIDE = { heading: "Use this site with an AI agent", promptsLead: "Some questions to try:", prompts: [ "Where is Salih speaking next, and what has he talked about before?", "Find Salih's posts about AWS Amplify and summarize the newest one.", "Which of Salih's talks have a recording?", "Get Salih's speaker kit so I can invite him to our meetup.", ], // intro text, the Chrome flag, and the console call are here too } as const; about.astro maps over it for the HTML, and the Markdown serializer builds the same section from it. Try it yourself You can call the tools on salih.dev today. You need Chrome 150 or newer. From the Chrome console 1. Open chrome://flags/#enable-webmcp-testing, set WebMCP for testing to Enabled, and relaunch Chrome. 2. Open salih.dev, then open DevTools and go to the Console. 3. List the tools and call one: const tools = await document.modelContext.getTools(); tools.map((tool) => tool.name); const kit = tools.find((tool) => tool.name === "get_speaker_kit"); await document.modelContext.executeTool(kit, {}); const search = tools.find((tool) => tool.name === "search_site"); await document.modelContext.executeTool(search, { query: "agents" }); You should see seven tools on most pages and eight on /talks/. If document.modelContext is undefined, the flag is not on yet. Some Chrome builds expect the input as a JSON string, so if executeTool complains, pass JSON.stringify({ query: "agents" }) instead. On the Talks page, run show_talks_on_page with { filter: "All talks" } or one of the topic labels and watch the filter buttons on the page change. With the MCP Inspector If you want to see the calls before you hand them to an agent, use the MCP Inspector. It is the reference tool for testing MCP servers, and it can start Chrome DevTools MCP for you with the same flags as above: npx @modelcontextprotocol/inspector \ npx chrome-devtools-mcp@latest \ --categoryExperimentalWebmcp \ --chromeArg=--enable-features=WebMCP It prints a URL with a one-time token, so open that URL rather than typing localhost:6274 yourself. Turn on the switch next to the server to connect, then switch to Tools. You are now doing by hand what Claude Code and Codex did on their own: 1. Run new_page with https://salih.dev/talks/ as the url. Chrome opens the page, and the result lists its page ID. 2. Run list_webmcp_tools with that pageId. You get all eight tools with their descriptions and input schemas, exactly as an agent receives them. 3. Run execute_webmcp_tool with the pageId, a toolName and the input as a JSON string, for example get_speaker_kit and {}. !The MCP Inspector showing list_webmcp_tools for salih.dev, with each tool's name, description and input schema !The MCP Inspector showing the result of get_speaker_kit, with my role, bio, focus areas and talk topics Step 2 is the useful one when you write your own tools. You read each description the way the model reads it, flattened into one long block with its schema, so a description that only makes sense next to your page is easy to spot. The Protocol tab on the right shows the raw JSON-RPC for every call if you need to see exactly what was sent. Every tool in the list has a small warning triangle. That is the Inspector's schema portability check on Chrome DevTools MCP's own schemas, not on my tools, and the calls work anyway. From Claude Code, Codex or Kiro CLI Claude Code, Codex and Kiro CLI run in a terminal, not in a browser tab, so they cannot see document.modelContext on their own. The bridge is Chrome DevTools MCP, Google's MCP server that gives a coding agent a real Chrome. It has an experimental WebMCP category with two tools: list_webmcp_tools lists what a page registers, and execute_webmcp_tool calls one of them with JSON input. The category is off by default. You need two flags: --categoryExperimentalWebmcp turns on the two tools, and --chromeArg=--enable-features=WebMCP turns on WebMCP in the Chrome that the server starts. That Chrome uses its own profile, so the flag you set in chrome://flags does not carry over. For Claude Code: claude mcp add chrome-devtools --scope user -- \ npx chrome-devtools-mcp@latest \ --categoryExperimentalWebmcp \ --chromeArg=--enable-features=WebMCP For Codex: codex mcp add chrome-devtools -- \ npx chrome-devtools-mcp@latest \ --categoryExperimentalWebmcp \ --chromeArg=--enable-features=WebMCP If you prefer editing ~/.codex/config.toml directly, this is the same server: [mcp_servers.chrome-devtools] command = "npx" args = [ "chrome-devtools-mcp@latest", "--categoryExperimentalWebmcp", "--chromeArg=--enable-features=WebMCP", ] For Kiro CLI: kiro-cli mcp add --name chrome-devtools --scope global \ --command npx \ --args '["chrome-devtools-mcp@latest","--categoryExperimentalWebmcp","--chromeArg=--enable-features=WebMCP"]' That writes the server to ~/.kiro/settings/mcp.json. Use --scope workspace instead if you only want it in one project, in that project's .kiro/settings/mcp.json. Restart the agent and ask it something about the site. I gave Codex this prompt: Open https://salih.dev/ in the browser. Use the page's WebMCP tools to answer: where is Salih speaking next, and which topics has he given talks on? Then say which WebMCP tools you called. Do not read the page HTML. !Codex Screenshot of the Tool Call It called list_webmcp_tools, then execute_webmcp_tool three times with get_site_overview, list_events and list_talks. The answer had CityJS Athens on 21 to 23 October as my next event, the two events after it, and the topics from both talks. It did not read the page HTML once. I gave Codex a speaker question instead, and it went straight to get_speaker_kit after listing the tools. That one call was enough for my bio, focus areas and contact routes. It also repeated the kit's note that the site has no email address, which is the line I added so an agent would not make one up. One small lesson from that run: I asked for "three focus areas", the kit has four, and Codex merged two of them to match my number. The agent trusted my prompt over the data. With Kiro CLI I asked which talks I have given and whether any of them has a recording. It opened the page, called list_webmcp_tools, and then made a single execute_webmcp_tool call with list_talks. The answer had both talks with their events and dates, and it said neither has a recording because videoUrl is empty for both. Kiro CLI asks before it runs each tool, so every one of those calls went through an approval prompt first. Two things to know before you try this: - Chrome DevTools MCP can read and change anything in the browser it controls. The server prints that warning on start, and it is right. Use it on sites you trust, and keep it away from tabs with accounts you care about. - The site cannot see who is calling its tools or ask the visitor for permission. Your agent's own approval prompts are the only check, so read what it wants to call before you allow it. My tools only read, so it does not matter much here. It would matter on a site with a checkout tool. Chrome's Debug WebMCP tools with AI agents page shows the same setup from the author's side: asking your coding agent to check that your own tools register and that their schemas are clear enough for a model. With other agents If your agent runs inside a browser that supports WebMCP, ask it one of the questions from my About page, for example "Where is Salih speaking next, and what has he talked about before?", and check which tools it calls. An agent without a browser still gets the same answers. Point it at llms.txt. It lists the tools and links /api/webmcp-index.json, the data the tools read. Resources - WebMCP specification - salih-dev repository, PR #15 and PR #16 - webmcp-types on npm - Building an agent-friendly personal website with specs - Join the WebMCP origin trial - Model Context Tool Inspector - Chrome DevTools MCP and its WebMCP tool reference - Debug WebMCP tools with AI agents - MCP Inspector

    3 reactions
  10. Reddit · · r/BestGitHubRepos · u/Artilas_Digital · ChromeDevTools/chrome-devtools-mcp

    chrome-devtools-mcp: Chrome DevTools for coding agents (53.6k stars) What it does All text below is quoted directly from the project README. >Chrome DevTools for agents (chrome-devtools-mcp) lets your coding agent (such as Antigravity, Claude, Cursor or Copilot) control and inspect a live Chrome browser. It acts as a Model-Context-Protocol (MCP) server, giving your AI coding assistant access to the full power of Chrome DevTools for reliable automation, in-depth debugging, and performance analysis. A CLI is also provided for use without MCP. Key features: - Get performance insights: Uses Chrome DevTools to record traces and extract actionable performance insights. - Advanced browser debugging: Analyze network requests, take screenshots and check browser console messages (with source-mapped stack traces). - Reliable automation. Uses puppeteer to automate actions in Chrome and automatically wait for action results. Disclaimers: >chrome-devtools-mcp exposes content of the browser instance to the MCP clients allowing them to inspect, debug, and modify any data in the browser or DevTools. Avoid sharing sensitive or personal information that you don't want to share with MCP clients. >chrome-devtools-mcp officially supports Google Chrome and Chrome for Testing only. Other Chromium-based browsers may work, but this is not guaranteed, and you may encounter unexpected behavior. Use at your own discretion. Requirements: - Node.js LTS version. - Chrome current stable version or newer. - npm >If you are interested in doing only basic browser tasks, use the --slim mode. >The MCP server will start the browser automatically once the MCP client uses a tool that requires a running browser instance. Connecting to the Chrome DevTools MCP server on its own will not automatically start the browser. >If you are developing agentic tooling and want to provide an integrated browser subagent as part of your product, we recommend building on top of Chrome DevTools for agents. Repository ChromeDevTools/chrome-devtools-mcp Repository stats |Metric|Value| |:-|:-| |Stars|53,570| |Forks|6,627| |Last release|chrome-devtools-mcp-v1.10.1 (2026-09-23)| |Languages|TypeScript 97.6%, JavaScript 2.4%| |Contributors|145| |AI contributor accounts (Claude / Codex / Cursor / Copilot)|None| |AI co-authored commits|None| Main contributor |Field|Value| |:-|:-| |Name|Alex Rudenko| |GitHub|@OrKoN| |Commits to this repo|473 (top contributor)| |Company / Location|@google, Germany| |Followers|926| |Public repos|104| |On GitHub since|2010-09-14| ------------------------------------------------------------------------------------- Discover the best GitHub repos without the endless scrolling. Get top repos organized by category (AI, DevOps, Databases & more), plus key takeaways from developers' most useful comments - all in one free, twice-weekly newsletter. 👉 Get the best repos & community insights - Free

    13 points
Trending awards, every completed day and week
Gold
31st place finishes
Silver
12nd place finishes
Bronze
33rd place finishes
Awarded repositories
1Owned by ChromeDevTools now

Repositories

Ordered by gold, then silver, then bronze.

  1. chrome-devtools-mcpBest: 1st by stars, 953 stars313

A repository earns an award for finishing first, second or third in a completed trending day or week, ranked by new stars, new forks or pull request authors. Awards follow a repository through renames and transfers and count toward its current owner. Weeks run Monday to Sunday, UTC.