<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Emad Omar</title>
    <description>The latest articles on DEV Community by Emad Omar (@emad_omar_5311e0e328be24c).</description>
    <link>https://dev.to/emad_omar_5311e0e328be24c</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3838199%2F1dc5d09d-1f93-4a04-bca0-697c981810a5.jpg</url>
      <title>DEV Community: Emad Omar</title>
      <link>https://dev.to/emad_omar_5311e0e328be24c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/emad_omar_5311e0e328be24c"/>
    <language>en</language>
    <item>
      <title>Your AI Doesn't Need Screenshots. It Needs DevTools.</title>
      <dc:creator>Emad Omar</dc:creator>
      <pubDate>Sat, 28 Mar 2026 22:04:34 +0000</pubDate>
      <link>https://dev.to/emad_omar_5311e0e328be24c/your-ai-doesnt-need-screenshots-it-needs-devtools-3lg1</link>
      <guid>https://dev.to/emad_omar_5311e0e328be24c/your-ai-doesnt-need-screenshots-it-needs-devtools-3lg1</guid>
      <description>&lt;h1&gt;
  
  
  Your AI Doesn't Need Screenshots. It Needs DevTools.
&lt;/h1&gt;

&lt;p&gt;Most AI coding agents are still debugging web apps in the dumbest possible way.&lt;/p&gt;

&lt;p&gt;They ask for a screenshot.&lt;/p&gt;

&lt;p&gt;Meanwhile the real answer is usually sitting in the browser console, the Network tab, the request payload, or the response body.&lt;/p&gt;

&lt;p&gt;That is not really an AI problem. It is a tooling problem.&lt;/p&gt;

&lt;p&gt;I got tired of watching agents guess from screenshots while I had DevTools open right next to them, showing the exact reason something failed. So I built &lt;a href="https://github.com/emadklenka/mare_browser_mcp" rel="noopener noreferrer"&gt;&lt;code&gt;mare-browser-mcp&lt;/code&gt;&lt;/a&gt;, a browser MCP designed less like "remote control for a webpage" and more like "give the model the same debugging signals I actually use."&lt;/p&gt;

&lt;p&gt;That changed the loop from this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI writes code -&amp;gt; I test it -&amp;gt; I describe the bug -&amp;gt; AI guesses a fix -&amp;gt; repeat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI writes code -&amp;gt; AI tests it -&amp;gt; AI reads the failure -&amp;gt; AI fixes it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That difference matters more than people think.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Screenshot Trap
&lt;/h2&gt;

&lt;p&gt;Most browser MCPs start from the same assumption: if the model can see the page, it can debug the app.&lt;/p&gt;

&lt;p&gt;That sounds reasonable until you try to debug anything real.&lt;/p&gt;

&lt;p&gt;A screenshot does not tell the model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;that login failed with a &lt;code&gt;401&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;that the frontend sent &lt;code&gt;user_email&lt;/code&gt; instead of &lt;code&gt;email&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;that a button click triggered a JS exception&lt;/li&gt;
&lt;li&gt;that the UI is fine but the API returned invalid JSON&lt;/li&gt;
&lt;li&gt;that the missing data is actually below the fold in a scrollable grid&lt;/li&gt;
&lt;li&gt;that the context menu only appears on right-click&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A screenshot is expensive, unstructured, and often the least useful artifact in the whole debugging flow.&lt;/p&gt;

&lt;p&gt;Language models are good at reasoning over structured text. We keep handing them pixels and asking them to guess.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Wanted Instead
&lt;/h2&gt;

&lt;p&gt;I wanted a browser MCP that makes the model think more like a developer with DevTools open.&lt;/p&gt;

&lt;p&gt;That means a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It should read console logs and page errors directly&lt;/li&gt;
&lt;li&gt;It should see network requests, payloads, response bodies, and timing&lt;/li&gt;
&lt;li&gt;It should batch actions instead of making one tiny tool call per click&lt;/li&gt;
&lt;li&gt;It should query the DOM as structured data&lt;/li&gt;
&lt;li&gt;It should handle hover, drag, right-click, and nested scroll containers&lt;/li&gt;
&lt;li&gt;It should only use screenshots when the problem is actually visual&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the core idea behind &lt;code&gt;mare-browser-mcp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It is a lean MCP server built with Playwright and the MCP SDK, and the whole design is biased toward structured debugging data first.&lt;/p&gt;

&lt;h2&gt;
  
  
  The One Tool I Wish More Browser MCPs Had
&lt;/h2&gt;

&lt;p&gt;The most important tool in the server is &lt;code&gt;browser_debug&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One call returns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;current URL&lt;/li&gt;
&lt;li&gt;page title&lt;/li&gt;
&lt;li&gt;console logs&lt;/li&gt;
&lt;li&gt;page errors&lt;/li&gt;
&lt;li&gt;dialogs&lt;/li&gt;
&lt;li&gt;network request history&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the network history is the useful part. The server captures things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;method&lt;/li&gt;
&lt;li&gt;URL&lt;/li&gt;
&lt;li&gt;parsed query params&lt;/li&gt;
&lt;li&gt;request headers&lt;/li&gt;
&lt;li&gt;request body&lt;/li&gt;
&lt;li&gt;status code&lt;/li&gt;
&lt;li&gt;JSON response body&lt;/li&gt;
&lt;li&gt;duration in milliseconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So instead of the model seeing "submit button clicked and page still looks wrong," it can see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://app.example.com/api/session"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"requestBody"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"user_email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"secret"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"responseBody"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"missing field: email"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"duration_ms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a completely different debugging experience.&lt;/p&gt;

&lt;p&gt;At that point the model is not guessing anymore. It can actually reason from evidence.&lt;/p&gt;

&lt;p&gt;There are a few guardrails in the implementation too:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;static assets are skipped&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OPTIONS&lt;/code&gt; preflights are ignored&lt;/li&gt;
&lt;li&gt;bodies are capped at 4 KB&lt;/li&gt;
&lt;li&gt;auth headers are masked&lt;/li&gt;
&lt;li&gt;cookies are reduced to &lt;code&gt;"[present]"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;failed requests are logged with the failure reason&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the data stays useful without turning into junk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Batching Matters More Than It Sounds
&lt;/h2&gt;

&lt;p&gt;Another thing that slows agents down is one-action-per-call design.&lt;/p&gt;

&lt;p&gt;Click. Wait. Screenshot. Fill. Wait. Screenshot.&lt;/p&gt;

&lt;p&gt;That is not just annoying. It makes the whole debugging loop slower and dumber.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;browser_act&lt;/code&gt; fixes that by accepting an ordered list of actions in one call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fill"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"selector"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user@example.com"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fill"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"selector"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"secret"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"click"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"selector"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"button[type=submit]"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The current action set covers a lot of what real apps actually need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;click&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hover&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;drag&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;clicklink&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fill&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;select&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keypress&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;waitfor&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scrollto&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wait&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;clearconsole&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That means the model is not stuck the moment the UI uses hover states, resize handles, sortable grids, or context menus.&lt;/p&gt;

&lt;p&gt;And yes, right-click works through &lt;code&gt;click&lt;/code&gt; with &lt;code&gt;button: "right"&lt;/code&gt;, which turns out to matter more often than you might expect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structured DOM Queries Beat Giant Dumps
&lt;/h2&gt;

&lt;p&gt;Another thing I did not want was a browser tool that just vomits the whole DOM back at the model.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;browser_query&lt;/code&gt; is useful because it lets the model ask narrower questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How many rows are there?&lt;/li&gt;
&lt;li&gt;Is this button visible?&lt;/li&gt;
&lt;li&gt;What text do these badges have?&lt;/li&gt;
&lt;li&gt;Is this input disabled?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"selector"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".ag-row"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"count_only"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"selector"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"button"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"all"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"visible_only"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"limit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"selector"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".badge"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"fields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"className"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"visible"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The supported fields are deliberately practical:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;text&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;value&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;visible&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;disabled&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;className&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;href&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;innerHTML&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That keeps the output small enough to reason about and avoids wasting context on useless noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Screenshots Are Still There. They Just Aren't First.
&lt;/h2&gt;

&lt;p&gt;I did keep &lt;code&gt;browser_screenshot&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But I made the tool description explicitly say it should be the last resort, not the default.&lt;/p&gt;

&lt;p&gt;That sounds minor, but it really changes how an agent behaves. If the tool surface itself tells the model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use &lt;code&gt;browser_debug&lt;/code&gt; first&lt;/li&gt;
&lt;li&gt;use &lt;code&gt;browser_query&lt;/code&gt; second&lt;/li&gt;
&lt;li&gt;use screenshots only for visual problems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;then the model starts spending its attention on data instead of appearance.&lt;/p&gt;

&lt;p&gt;That is the behavior I wanted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real Apps Need More Than Page Scroll
&lt;/h2&gt;

&lt;p&gt;One of the easiest ways browser tools fall apart is scrolling.&lt;/p&gt;

&lt;p&gt;Scrolling the page is not enough for modern apps. A lot of important UI is inside:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;data grid viewports&lt;/li&gt;
&lt;li&gt;chat panels&lt;/li&gt;
&lt;li&gt;sidebars&lt;/li&gt;
&lt;li&gt;overflow containers&lt;/li&gt;
&lt;li&gt;modals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;browser_scroll&lt;/code&gt; can scroll the page, scroll an element into view, or scroll inside a specific container.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"container"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".ag-body-viewport"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"down"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pixels"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And because it returns scroll position data, the model can tell where it is instead of just flailing around.&lt;/p&gt;

&lt;h2&gt;
  
  
  There Is Also an Escape Hatch
&lt;/h2&gt;

&lt;p&gt;Even with all of that, fixed tools never cover every case.&lt;/p&gt;

&lt;p&gt;So there is &lt;code&gt;browser_eval&lt;/code&gt;, which runs JavaScript in the page context.&lt;/p&gt;

&lt;p&gt;That is useful for things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reading computed styles&lt;/li&gt;
&lt;li&gt;inspecting app state on &lt;code&gt;window&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;appending input text without clearing it&lt;/li&gt;
&lt;li&gt;simulating more custom interactions&lt;/li&gt;
&lt;li&gt;calling &lt;code&gt;fetch()&lt;/code&gt; directly&lt;/li&gt;
&lt;li&gt;checking CSS visibility details&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I do not think the escape hatch should be the first thing the model reaches for. But it absolutely should exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Looks Like in Practice
&lt;/h2&gt;

&lt;p&gt;A realistic flow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. browser_navigate({ url: "https://myapp.com", clear_logs: true })

2. browser_act({
     commands: [
       { action: "fill", selector: "#email", value: "user@example.com" },
       { action: "fill", selector: "#password", value: "secret" },
       { action: "click", selector: "button[type=submit]" }
     ]
   })

3. browser_wait_for_network({ url_pattern: "/api/session", method: "POST" })

4. browser_debug({ console_types: ["error"], last_n: 20 })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there the model can see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whether the request fired&lt;/li&gt;
&lt;li&gt;what payload got sent&lt;/li&gt;
&lt;li&gt;what response came back&lt;/li&gt;
&lt;li&gt;whether the browser threw an error&lt;/li&gt;
&lt;li&gt;whether the failure is frontend, backend, or both&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the kind of loop where an agent becomes genuinely useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Think This Matters
&lt;/h2&gt;

&lt;p&gt;I think a lot of people are measuring browser MCPs by the wrong thing.&lt;/p&gt;

&lt;p&gt;The question is not "can the AI click buttons?"&lt;/p&gt;

&lt;p&gt;The real question is: when something breaks, can the AI see the same evidence a good developer would look at?&lt;/p&gt;

&lt;p&gt;If the answer is yes, the quality of debugging jumps fast.&lt;/p&gt;

&lt;p&gt;If the answer is no, you end up with a very expensive screenshot viewer.&lt;/p&gt;

&lt;p&gt;That is why I built &lt;code&gt;mare-browser-mcp&lt;/code&gt; the way I did. Not to make agents better at looking at pages, but to make them better at understanding what happened in the browser.&lt;/p&gt;

&lt;p&gt;Not screenshots first. Telemetry first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/emadklenka/mare_browser_mcp
&lt;span class="nb"&gt;cd &lt;/span&gt;mare_browser_mcp
pnpm &lt;span class="nb"&gt;install
&lt;/span&gt;npx playwright &lt;span class="nb"&gt;install &lt;/span&gt;chromium
pnpm run setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also supports global install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add &lt;span class="nt"&gt;-g&lt;/span&gt; mare-browser-mcp
npx playwright &lt;span class="nb"&gt;install &lt;/span&gt;chromium
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The repo has setup instructions for Claude Code and OpenCode, and the current server exposes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;browser_navigate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;browser_act&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;browser_debug&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;browser_query&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;browser_screenshot&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;browser_eval&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;browser_scroll&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;browser_restart&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;browser_upload&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;browser_wait_for_network&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are building web apps with AI, that combination is much closer to giving your agent DevTools than giving it a screenshot and hoping for the best.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>claude</category>
      <category>playwright</category>
      <category>javascript</category>
    </item>
    <item>
      <title>claude</title>
      <dc:creator>Emad Omar</dc:creator>
      <pubDate>Sat, 28 Mar 2026 20:38:00 +0000</pubDate>
      <link>https://dev.to/emad_omar_5311e0e328be24c/claude-2m7d</link>
      <guid>https://dev.to/emad_omar_5311e0e328be24c/claude-2m7d</guid>
      <description></description>
    </item>
    <item>
      <title>Give Claude Your Browser Console — It Debugs Like a Real Developer</title>
      <dc:creator>Emad Omar</dc:creator>
      <pubDate>Sun, 22 Mar 2026 10:20:20 +0000</pubDate>
      <link>https://dev.to/emad_omar_5311e0e328be24c/give-claude-your-browser-console-it-debugs-like-a-real-developer-nmn</link>
      <guid>https://dev.to/emad_omar_5311e0e328be24c/give-claude-your-browser-console-it-debugs-like-a-real-developer-nmn</guid>
      <description>&lt;h1&gt;
  
  
  Give Claude Your Browser Console — It Debugs Like a Real Developer
&lt;/h1&gt;

&lt;p&gt;You know that moment when something breaks in your web app and you open DevTools, check the console, scan the network tab, find the failing API call, read the JSON response — and finally figure out what went wrong?&lt;/p&gt;

&lt;p&gt;That's exactly what mare-browser-mcp gives Claude.&lt;/p&gt;

&lt;p&gt;Not a screenshot. Not a DOM dump. The actual console errors, the actual network requests, the actual JSON responses from your API. Claude reads them the same way you do.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem With Other Browser MCP Tools
&lt;/h2&gt;

&lt;p&gt;Most browser MCP servers give the LLM one move: take a screenshot.&lt;/p&gt;

&lt;p&gt;Screenshots are pixels. Claude has to guess what's happening from an image. It can't see a 401 response. It can't read a JS stack trace. It can't tell if an API returned &lt;code&gt;{ error: "session expired" }&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's not debugging. That's guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What mare-browser-mcp Does Differently
&lt;/h2&gt;

&lt;p&gt;One tool does the heavy lifting: &lt;code&gt;browser_debug&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Call it after anything goes wrong and you get back:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current URL and page title&lt;/li&gt;
&lt;li&gt;All console logs (errors, warnings, everything)&lt;/li&gt;
&lt;li&gt;All network requests with &lt;strong&gt;status codes and full JSON response bodies&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"current_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://myapp.com/dashboard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dashboard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"console"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Uncaught TypeError: Cannot read properties of undefined (reading 'user')"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"network"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/api/session"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"token expired"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude reads that and knows exactly what happened — token expired, session failed, JS crashed because user was undefined. Same conclusion you'd reach in 30 seconds of DevTools.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Full Toolkit
&lt;/h2&gt;

&lt;p&gt;8 tools, each with a clear job:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;browser_navigate&lt;/code&gt; — go to a URL, optionally clear logs before starting&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;browser_act&lt;/code&gt; — click, fill, keypress, scroll — batch multiple steps in one call&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;browser_debug&lt;/code&gt; — &lt;strong&gt;start here when something breaks&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;browser_query&lt;/code&gt; — read DOM elements without a screenshot&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;browser_eval&lt;/code&gt; — run any JavaScript in the page&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;browser_scroll&lt;/code&gt; — scroll by pixels or to a specific element&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;browser_wait_for_network&lt;/code&gt; — wait for a specific API call to complete&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;browser_screenshot&lt;/code&gt; — last resort only&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real Debugging Session
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;browser_navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://myapp.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;clear_logs: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;browser_act&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
     &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;action: &lt;/span&gt;&lt;span class="s2"&gt;"fill"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;selector: &lt;/span&gt;&lt;span class="s2"&gt;"#email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;value: &lt;/span&gt;&lt;span class="s2"&gt;"user@example.com"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
     &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;action: &lt;/span&gt;&lt;span class="s2"&gt;"fill"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;selector: &lt;/span&gt;&lt;span class="s2"&gt;"#password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;value: &lt;/span&gt;&lt;span class="s2"&gt;"secret"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
     &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;action: &lt;/span&gt;&lt;span class="s2"&gt;"click"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;selector: &lt;/span&gt;&lt;span class="s2"&gt;"button[type=submit]"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;browser_wait_for_network&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="ss"&gt;url_pattern: &lt;/span&gt;&lt;span class="s2"&gt;"/api/session"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;method: &lt;/span&gt;&lt;span class="s2"&gt;"POST"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nf"&gt;browser_debug&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="ss"&gt;console_types: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
   &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;sees&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"token expired"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;

&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="no"&gt;Figures&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;fix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="no"&gt;No&lt;/span&gt; &lt;span class="n"&gt;back&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;forth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="no"&gt;No&lt;/span&gt; &lt;span class="n"&gt;screenshots&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the workflow. Claude acts, waits for the network, reads the debug output, understands what happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install in 5 Commands
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/emadklenka/mare_browser_mcp
&lt;span class="nb"&gt;cd &lt;/span&gt;mare_browser_mcp
pnpm &lt;span class="nb"&gt;install
&lt;/span&gt;npx playwright &lt;span class="nb"&gt;install &lt;/span&gt;chromium
pnpm run setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pnpm run setup&lt;/code&gt; registers the MCP with Claude Code automatically — no manual path config.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's Free
&lt;/h2&gt;

&lt;p&gt;MIT license. Use it however you want.&lt;/p&gt;

&lt;p&gt;If it saves you debugging time → &lt;a href="https://buymeacoffee.com/emadomar" rel="noopener noreferrer"&gt;https://buymeacoffee.com/emadomar&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub → &lt;a href="https://github.com/emadklenka/mare_browser_mcp" rel="noopener noreferrer"&gt;https://github.com/emadklenka/mare_browser_mcp&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Built this because I was tired of Claude guessing from screenshots. Now it debugs the way I do.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>claude</category>
      <category>playwright</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
