bob-in-browser
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@bob-in-browserOpen my site https://example.com and audit design at mobile, tablet, and desktop widths."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
bob-in-browser
A browser-inspection MCP server. It gives any MCP client the ability to open a website, look at it, and judge whether it actually renders correctly — not just whether it returns 200.
Most browser automation tools are built for end-to-end testing: assert that a button exists, that a form submits. This one is built for visual and design review. It answers the question "does this page look right?" with screenshots at real breakpoints plus a deterministic audit of the things that most often look wrong.
Viewport 390px — 7 issue(s)
OVERFLOW (1): div.wide runs 1050px past the 390px viewport
SMALL TAP TARGET (2): button.smallbtn "x" is 24x24; a.smallbtn "y" is 6x12
LOW CONTRAST (1): p.faint "This grey text fails WCAG AA contrast" 1.92:1 (needs 4.5:1)
MISSING ALT (1): img logo.png
TINY TEXT (1): p.tiny "This text is only 9 pixels tall" at 9px
CLIPPED (1): div.clip content 410x20 in box 120x20Every finding names the element and its text, so it is actionable — not a score, not a count.
Contents
Related MCP server: Refract
Why this exists
Anthropic's Claude Code ships a "Claude in Chrome" extension that lets the model drive your real
browser. It is genuinely useful for design work, but it cannot be reused by other clients: it is
bound by Chrome Native Messaging to a single whitelisted extension ID, talking over stdio to the
claude binary specifically. There is no open port and no documented protocol for anything else
to connect to.
bob-in-browser is a clean-room equivalent built on Playwright that
speaks standard MCP over stdio, so any MCP-capable client can use it. It also keeps the one
genuinely distinctive capability of the extension — inspecting pages using your already
logged-in browser session — via Chrome DevTools Protocol attach.
Requirements
Node.js | 18 or newer (developed and tested on Node 26) |
Browser | Chrome/Chromium, Firefox, and WebKit — Playwright installs them |
OS | macOS, Linux, or Windows |
Install
Clone or unzip, then from inside the folder:
npm install
npx playwright install chromium firefox webkit # or just the engines you needVerify before wiring anything up
Two self-contained checks, neither of which needs an MCP client:
npm run smoke # audits a deliberately broken page; expects 7 findings
./test/mcp-probe.sh # full JSON-RPC handshake over stdio; exits 0npm run smoke loads test/broken.html, a fixture with one instance of every defect the audit
detects, and prints what it found. If you see 7 issues across 6 categories, the audit engine works.
./test/mcp-probe.sh speaks raw MCP at the server exactly as a client would — initialize,
tools/list, tools/call, close_browser — and exits cleanly. If that passes, any MCP client
can talk to it.
Connect it to your MCP client
This is a standard stdio MCP server. Add it to your client's MCP configuration:
{
"mcpServers": {
"browser": {
"command": "node",
"args": ["/ABSOLUTE/PATH/TO/bob-in-browser/server.js"],
"env": {
"BOB_BROWSER_HEADLESS": "true"
}
}
}
}Use an absolute path. MCP clients do not expand ~ and do not resolve paths relative to your
shell's working directory. This is the single most common setup failure.
If your client uses a different top-level key — some use servers, some use a TOML block — keep
the command / args / env triple intact. That part is universal across MCP implementations.
Cross-browser support
All three major engines are supported, and the audit produces identical results on each — verified against the bundled fixture.
| Engine | Stands in for | Notes |
| Blink | Chrome, Edge, Brave, Opera | Uses your real installed Chrome when available, else bundled Chromium |
| WebKit | Safari (macOS + iOS) | Playwright's WebKit build — Safari's engine, not Safari itself |
| Gecko | Firefox | Playwright's patched Gecko build, not your installed Firefox |
Set the default with BOB_BROWSER_ENGINE, or switch per call:
open_page { url: "https://example.com", engine: "webkit" }
audit_design {}
open_page { url: "https://example.com", engine: "firefox" }
audit_design {}Switching engines restarts the browser, so console and network buffers reset — which is what you want, since each engine gets a clean log. Screenshots and audit output are labelled with the engine that produced them, so cross-engine comparisons are never ambiguous.
How faithful is each one?
Being precise, because this matters for design review:
Chromium is exact for Chrome, because it can drive your actual Chrome install.
WebKit is Safari's engine, but is not Safari. Layout, CSS, and font rendering behave like Safari — which is what catches the flexbox and
position: stickydifferences that bite in practice. It does not carry Safari's UI chrome, its exact version, or Safari-only features. Treat it as a very good proxy, not a substitute for a final check on a real device.Firefox is a patched Gecko build, matched to the Playwright version rather than to the Firefox you have installed.
Engine differences are real and worth catching. During development of this tool, WebKit collapsed
a broken <img> to 0x0 where Chromium gave it a 16x16 box — exactly the kind of divergence that
makes a layout break in one browser only.
Two browser modes
1. Launch (default)
The server starts its own browser instance. Clean state every run, no interference with your daily browsing. This is what you want for local development and public URLs.
Uses your installed Google Chrome when available for the most accurate rendering, and falls back
to Playwright's bundled Chromium otherwise. The mode in use is reported by open_page so you
always know what rendered your screenshot.
2. Attach to a running Chrome
Inspect pages behind a login without re-authenticating, by attaching to a Chrome you have already signed into. This is the capability a plain headless browser cannot give you.
Chromium only. The Chrome DevTools Protocol is a Chromium feature; Firefox and WebKit have no equivalent. With
BOB_BROWSER_CDP_URLset, requesting another engine returns a clear error rather than silently falling back.
# 1. Quit Chrome completely, then start it with the DevTools port open.
# The separate --user-data-dir keeps this isolated from your main profile.
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
--remote-debugging-port=9222 \
--user-data-dir="$HOME/.chrome-inspect-profile"
# 2. Point the server at it.
export BOB_BROWSER_CDP_URL=http://localhost:9222Sign in to the target app once in that window. Every subsequent inspection reuses the session.
Security note:
--remote-debugging-portlets any local process drive that browser. Use a dedicated--user-data-diras shown, close the window when finished, and do not enable it on a shared or untrusted machine.
Configuration
All configuration is environment variables — no config file.
Variable | Default | Purpose |
|
| Default engine: |
| (unset) | Attach to a running Chrome at this CDP URL instead of launching one. E.g. |
|
| Set to |
|
| Directory for full-resolution PNG screenshots. |
Tool reference
Nine tools. open_page first, close_browser last, anything in between.
open_page
Navigate to a URL and begin capturing console output and network failures. Call this first — the capture buffers reset on every call, so each page gets a clean log.
Parameter | Type | Default | Notes |
| string | required |
|
| number |
| Viewport width in px |
| number |
| Viewport height in px |
| enum |
|
|
| enum |
|
|
Returns the final URL, page title, HTTP status, active engine, and browser mode.
screenshot
Capture the page as an image. Returns it inline as JPEG (cheap in context) and simultaneously saves a full-resolution PNG to disk, returning the path.
Parameter | Type | Default | Notes |
| number | current | Resize viewport before capturing |
| boolean |
| Capture the whole scrollable page |
| string | — | Capture just one element |
| enum |
|
|
check_responsive
The core tool. Screenshots and audits the page at several widths in one call, so you can see precisely which breakpoint breaks rather than guessing.
Parameter | Type | Default | Notes |
| number[] |
| Phone, tablet, desktop |
| boolean |
| Full scrollable capture at each width |
| boolean |
| Set |
audit_design
Run the automated design and accessibility checks at a single width. See What the audit catches.
Parameter | Type | Default |
| number | current viewport |
read_console
Console messages and uncaught page errors captured since open_page. A JS error is the most
common reason a page renders wrong.
Parameter | Type | Default | Notes |
| string | — | Case-insensitive regex filter on message text |
| enum | — |
|
| number |
| Most recent N |
read_network_errors
Failed requests and HTTP 4xx/5xx responses — catches missing fonts, images, and stylesheets that silently degrade a design without throwing any error.
Parameter | Type | Default |
| number |
|
get_page_text
The rendered text of the page. Use it to check copy, heading hierarchy, and that content actually loaded rather than silently failing.
Parameter | Type | Default |
| string | whole body |
| number |
|
interact
Drive the page to a state worth inspecting — open a menu, submit a form, scroll to a section. Returns any new console errors the action triggered.
Parameter | Type | Notes |
| enum |
|
| string | Required for |
| string | Text for |
Avoid clicking controls that open native
alert/confirm/promptdialogs. They block the page and stall further commands.
close_browser
Close the browser and release resources. Takes no parameters.
What the audit catches
Six deterministic checks, each capped at 8 findings per run so output stays readable. All thresholds come from published standards rather than taste.
Check | Rule | Why it matters |
Horizontal overflow | Element extends past the viewport edge, excluding | The single most common responsive bug. Causes the whole page to scroll sideways on phones. |
Small tap targets | Interactive element under 44×44 px | WCAG 2.5.5 and the Apple HIG minimum. Below this, people miss the target. |
Low contrast | Below WCAG AA — 4.5:1 body, 3:1 large text | Large text is ≥24px, or ≥18.66px bold. Unreadable for low-vision users and in sunlight. |
Missing alt |
|
|
Tiny text | Rendered font size under 12px | Below comfortable reading size on any device. |
Clipped content |
| Text silently cut off — often only at certain widths or in certain languages. |
On contrast specifically: the check resolves the actual background by walking up the
ancestor chain until it finds a colour with alpha > 0.5, so inherited and transparent backgrounds
are handled correctly rather than assumed to be white. Interactive elements are matched by role as
well as tag ([role="button"], [role="link"], [onclick]), so custom components are covered.
Elements that are display:none, visibility:hidden, opacity:0, or zero-sized are skipped
throughout — hidden content is not judged.
Use cases
Catch a responsive break before it ships
open_page { url: "http://localhost:3000/pricing" }
check_responsive { widths: [360, 390, 768, 1024, 1440] }One call, five viewports, screenshots plus findings for each. When the pricing table overflows at 768px but not 1024px, you see exactly that — with the offending selector named.
Debug a page that renders wrong
open_page { url: "https://staging.example.com" }
read_console { level: "error" }
read_network_errors {}
screenshot { full_page: true }Covers the three usual culprits in order: a JS exception that halted rendering, an asset that failed to load, and finally what the page actually looks like.
Accessibility pass before a release
open_page { url: "https://example.com/checkout", width: 390 }
audit_design {}Contrast, tap targets, alt text, and text size in one pass, at the viewport where these problems are worst.
Inspect a page behind a login
Start Chrome with --remote-debugging-port=9222, sign in once, set BOB_BROWSER_CDP_URL, then
inspect authenticated pages normally. Dashboards, admin panels, and internal tools become
reviewable without scripting a login flow or storing credentials.
Review a state that only exists after interaction
open_page { url: "https://example.com" }
interact { action: "click", selector: "nav .menu-toggle" }
screenshot { }
audit_design {}Mobile menus, modals, and expanded accordions are frequently where layout breaks, precisely because they are not visible in a static screenshot.
Check the same page across Chrome, Safari, and Firefox
open_page { url: "https://example.com", engine: "chromium", width: 390 }
audit_design {}
open_page { url: "https://example.com", engine: "webkit", width: 390 }
audit_design {}
open_page { url: "https://example.com", engine: "firefox", width: 390 }
audit_design {}Three engines, same viewport, labelled output. Where the findings diverge, you have found a
browser-specific bug — usually flexbox, position: sticky, or a font fallback.
Compare a build against a reference
Point it at a production URL and a local build at the same widths, and compare the saved PNGs. Every capture returns its path, so the files are there to diff by eye or by tool.
How it works
MCP client ──stdio JSON-RPC──▶ server.js tool schemas, dispatch, result shaping
│
▼
browser.js Playwright lifecycle, console/network capture
│
▼
checks.js audit function, executed inside the pageserver.jsdeclares the nine tools as raw JSON Schema — deliberately not zod — so the server does not impose a validation-library version on the client. Results are shaped into MCPtextandimagecontent blocks.browser.jsowns the single browser/page instance, decides between launch and CDP attach, and wires theconsole,pageerror,requestfailed, andresponselisteners whose buffers backread_consoleandread_network_errors.checks.jsexports one self-contained function serialized into the page bypage.evaluate(). It closes over nothing, so it runs correctly in the browser context.
open_page falls back from networkidle to domcontentloaded automatically, so pages that poll
continuously do not hang the call — a common failure with naive Playwright wrappers.
Troubleshooting
The client shows no tools. Almost always a path problem. Confirm the server runs standalone
with ./test/mcp-probe.sh, then check that args uses an absolute path with no ~.
browserType.launch: Executable doesn't exist. Playwright has no browser installed. Run
npx playwright install chromium.
CDP attach fails with ECONNREFUSED. Chrome is not running with the debugging port, or was
already running when you launched it with the flag. Quit Chrome completely first — the flag is
ignored if an instance is already up.
Screenshots are blank or half-rendered. The page is still loading. Use
wait_until: "networkidle", or add interact { action: "wait", value: "1500" } before capturing.
The server seems to hang. It is a long-lived stdio server; staying alive is correct. It exits
when stdin closes, provided the browser has been released — call close_browser when done.
Everything is flagged as low contrast. Usually a page that sets colours via a framework
stylesheet that failed to load. Check read_network_errors first.
Limitations
One page at a time. A single browser and page instance; no parallel tabs or sessions.
The audit is deterministic, not aesthetic. It finds measurable defects — overflow, contrast, size. It does not judge whether a design is good. Pair the screenshots with a model's visual judgment for that.
No visual regression diffing. Screenshots are saved with paths returned, but comparing them across runs is left to you.
No native dialog handling.
alert/confirm/promptwill block the page.WebKit is not Safari, and Gecko is not your Firefox. Both are Playwright's builds of the respective engines. Excellent proxies for layout and CSS behaviour; not a replacement for a final pass on real devices, especially for iOS Safari.
CDP attach is Chromium-only, so inspecting a logged-in session is not available in WebKit or Firefox.
Contrast checking assumes solid backgrounds. Text over an image or gradient is resolved to the nearest solid ancestor colour, which may not reflect what a reader actually sees.
License
MIT
Available Tools
9 toolsaudit_designA
Run automated design and accessibility checks on the current page: horizontal overflow, tap targets under 44x44, WCAG AA text contrast, images missing alt, text under 12px, and content clipped by overflow:hidden.
| Name | Required | Description | Default |
|---|---|---|---|
| width | No | Audit at this viewport width. Omit to use current. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description is transparent about the audit scope by listing the exact checks performed. However, without annotations, it does not disclose whether the tool is read-only, whether it temporarily resizes the viewport (given the width parameter), or what format the results take. These are meaningful behavioral gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, front-loaded sentence uses a colon to introduce a compact list of checks. Every word earns its place, with no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The definition clearly explains what the tool does and where it operates, but it omits any description of the output or result format. Since there is no output schema and no annotations, this missing information leaves an agent uncertain how to interpret the tool's response.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already documents the width parameter with 100% coverage, so the baseline is 3. The description adds no extra parameter guidance, but none is needed given the schema's clarity.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Run') and resource ('automated design and accessibility checks on the current page') and enumerates concrete checks (horizontal overflow, tap targets, WCAG contrast, alt text, text size, clipping). This level of specificity clearly distinguishes it from siblings like screenshot or read_console.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use it ('on the current page') but does not explicitly provide when/when-not guidance or mention alternatives. It does not say how to choose between audit_design and check_responsive, which is a likely overlapping sibling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_responsiveA
THE core design check. Screenshots the page at several widths and runs a layout audit at each one, so you can see exactly which breakpoint breaks. Reports horizontal overflow, which is the most common responsive bug.
| Name | Required | Description | Default |
|---|---|---|---|
| widths | No | Viewport widths to test. | |
| full_page | No | Capture full scrollable page at each width. | |
| include_images | No | Return screenshots inline. Set false to get findings only (much cheaper). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations to rely on, the description carries the burden of disclosing behavior. It explains that the tool takes screenshots at multiple widths, audits layout at each, and reports horizontal overflow, which is meaningful behavioral detail beyond the tool name.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no filler. The core action is front-loaded, and the final sentence adds valuable domain knowledge about the most common responsive bug, making every word earn its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a diagnostic tool with no annotations and no output schema, the description gives enough context to select and invoke it correctly: it explains the method, the purpose, and the key reported finding. It could be more explicit about prerequisites such as having a page open, but the default parameter values and schema descriptions cover invocation details.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and every parameter has a helpful description, so the baseline is 3. The tool description adds only general context like 'several widths' but does not enrich parameter meaning beyond what the schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States the specific behavior: screenshots the page at several widths and runs a layout audit per width, with a concrete output of horizontal overflow detection. This clearly distinguishes it from sibling tools like screenshot and audit_design by tying the check to responsive breakpoint diagnostics.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description positions this as 'THE core design check' and explains the diagnostic outcome: seeing exactly which breakpoint breaks. It gives clear context for when to use it, though it does not explicitly name alternatives or state when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
close_browserA
Close the browser and free resources. Call when the inspection is finished.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the behavioral burden. It discloses the primary effect (closing the browser and freeing resources), but does not mention irreversible session loss or whether calling it multiple times is safe. It is functional but not deeply transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with no filler. The action is front-loaded and the usage condition follows immediately. Every word contributes value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter terminal action, the description is largely complete: it states the action and the condition for calling it. It lacks only minor context such as idempotency or what happens to the existing session, which would make it fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and 100% schema coverage, so the schema fully documents the inputs. The description adds no param details, but none are needed; baseline 4 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific action ('Close the browser') on a specific resource ('the browser') and adds the purpose ('free resources'). It clearly differs from the sibling inspection tools, which all perform read or interaction operations rather than ending the session.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says when to call the tool: 'when the inspection is finished.' This provides clear contextual guidance. It doesn't discuss exclusions or alternatives, but no competing close-like sibling exists, so the guidance is sufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_page_textA
Read the rendered text of the page, to check copy, hierarchy, and that content actually loaded.
| Name | Required | Description | Default |
|---|---|---|---|
| selector | No | CSS selector to scope to. | |
| max_chars | No | Truncate at this many characters. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the burden of behavioral disclosure. It communicates that this is a read-only operation and that it returns rendered text, which is useful. However, it does not mention potential runtime caveats such as waiting for load, handling of empty selectors, or what happens if content has not loaded.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, front-loaded sentence delivers the core action, the resource, and the use case with no filler. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only tool with only two optional, fully documented parameters, the description provides sufficient context for an agent to decide when to call it. It could be slightly richer about return value format or edge cases, but nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents both selector and max_chars. The description adds no additional parameter-level semantics beyond the stated purpose, which is acceptable but not additive.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Read') and resource ('rendered text of the page'), and gives the purpose ('check copy, hierarchy, and that content actually loaded'). This clearly distinguishes it from visual or console-oriented sibling tools like screenshot, read_console, and audit_design.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description states concrete use cases: checking copy, hierarchy, and whether content loaded. It does not explicitly name alternatives or say when not to use it, but the stated purposes make the appropriate context clear enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
interactA
Drive the page to reach a state worth inspecting: open a menu, submit a form, scroll to a section. Returns any new console errors the action triggered. Avoid elements that open native alert/confirm dialogs.
| Name | Required | Description | Default |
|---|---|---|---|
| value | No | Text for fill, key name for press, pixels for scroll, ms for wait. | |
| action | Yes | What to do. | |
| selector | No | CSS selector. Required for click, fill, hover. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it reveals that the tool performs actions, returns newly triggered console errors, and warns about native dialogs that can block automation. It does not disclose failure modes or navigation side effects, but it provides meaningful behavioral context beyond the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three concise sentences, front-loaded with the core purpose, followed by the return value and a key caution. Every sentence earns its place with no repetition or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is moderately complex and has no output schema, but the description covers intent, example actions, return behavior, and a critical pitfall. It does not spell out what happens on selector failure or navigation changes, but for its scope the description is close to complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents 'action', 'selector', and 'value' formats. The description adds context for why parameters are used but no new parameter-level detail; the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a clear purpose ('Drive the page to reach a state worth inspecting') with concrete examples ('open a menu, submit a form, scroll to a section'). It distinguishes itself from the mostly observational sibling tools by emphasizing that it performs page actions rather than reading or capturing state.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly indicates when to use the tool: when the page needs to be manipulated into a state worth inspecting. It also gives an explicit exclusion ('Avoid elements that open native alert/confirm dialogs'). It does not name alternative sibling tools, but the context makes the action-versus-inspection split reasonably clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
open_pageA
Open a URL in the browser and start capturing console + network errors. Call this first. Returns page title, HTTP status, and the active engine. Set engine to re-open the same URL in a different browser engine and compare rendering.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | URL to open. Supports http(s):// and file:// and localhost. | |
| width | No | Viewport width in px. | |
| engine | No | Browser engine. chromium = Chrome/Edge, webkit = Safari, firefox = Firefox. Switching engines restarts the browser. | chromium |
| height | No | Viewport height in px. | |
| wait_until | No | When to consider navigation done. | networkidle |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the transparency burden and does disclose the key side effects: opening a URL in the browser, starting console/network error capture, and returning title, HTTP status, and active engine. It also implies that switching engines reopens the URL, which is useful behavioral context. It does not cover persistent browser state or teardown, but sibling tools like close_browser make this less critical.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no filler. The first sentence front-loads the action and ordering; the second covers return values and the engine use case. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no output schema and five parameters, the description covers the essential return values, side effects, and engine usage tip, and the schema documents all parameters. Minor gaps remain around repeated calls and whether previous browser state is replaced, but the description is sufficient for an agent to call the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds genuine extra meaning for the engine parameter by framing it as a way to compare rendering across engines, and it connects the tool's overall purpose to capturing console/network errors. This goes slightly beyond the schema's parameter descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource ('Open a URL in the browser') and clearly adds a distinct capability ('start capturing console + network errors') that separates it from sibling tools like screenshot or read_console. The instruction 'Call this first' also identifies it as the entry-point navigation tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says 'Call this first,' which tells the agent when to use it relative to other tools. It also gives conditional context for the engine parameter ('re-open the same URL in a different browser engine and compare rendering'). It does not explicitly name alternatives or exclusions, but the ordering instruction provides clear usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_consoleA
Read console messages and uncaught page errors captured since the last open_page. JS errors are the usual cause of a page that renders wrong.
| Name | Required | Description | Default |
|---|---|---|---|
| level | No | Only this level. | |
| limit | No | Max messages to return. | |
| pattern | No | Case-insensitive regex to filter message text. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral disclosure burden. It reveals a stateful behavior: messages are captured since the last open_page, not live. It also clarifies that page errors are included. Minor gaps remain around whether the buffer is cleared or what happens before any open_page, but the core behavior is disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, no wasted words. The first sentence states scope and resource; the second gives a practical diagnostic hint. Both sentences add value and the tool identity is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read tool with three optional, fully documented parameters and no output schema, the description provides enough context to call it correctly. It explains the resource, the time window, and a common use case. Return formatting is not described, but the absence of an output schema makes this a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the parameters are already fully documented in the schema. The description adds no parameter-level detail, but none is needed because level, limit, and pattern all have clear inline descriptions. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource: 'Read console messages and uncaught page errors.' It also specifies the temporal scope ('captured since the last open_page'), which distinguishes it from related tools like read_network_errors and get_page_text. This is immediately actionable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides a clear diagnostic context: 'JS errors are the usual cause of a page that renders wrong' implies this tool should be consulted when a page renders incorrectly. It does not explicitly name alternatives or exclusions, but the context is strong enough to guide selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_network_errorsA
List failed requests and HTTP 4xx/5xx responses. Catches missing fonts, images, and stylesheets that silently degrade a design.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max entries. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
There are no annotations, so the description carries the full burden. It clearly discloses that the tool lists failed network responses and frames them as design-relevant, but it does not mention whether it requires a loaded page, whether it reads the current session only, or what side effects (if any) exist. This is a read-only listing tool, so the gap is moderate rather than severe.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no filler. The first sentence states the core action and result, and the second provides practical value. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read-only listing tool, the description gives enough context to understand what the tool does and why it matters. It does not specify return format, ordering, or whether the network log is scoped to the current page, but the low complexity and simple schema make those omissions acceptable.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema covers 100% of the single parameter with a default and a description ('Max entries.'). The tool description adds no additional meaning beyond the schema, so the baseline score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('List') and resource ('failed requests and HTTP 4xx/5xx responses'), making the tool's purpose clear. It also adds a practical use case (catching missing fonts, images, and stylesheets) but does not explicitly differentiate from sibling tools like read_console.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use the tool—when investigating silent design degradation from missing assets—but it does not provide explicit when-to-use or when-not-to-use guidance. It also does not mention alternative tools or conditions for choosing this over read_console or audit_design.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
screenshotA
Capture the current page as an image so you can visually judge layout, spacing, and alignment. Also saves a full-resolution PNG to disk and returns its path.
| Name | Required | Description | Default |
|---|---|---|---|
| width | No | Resize viewport to this width first. Omit to keep current. | |
| format | No | png is sharper, jpeg is much cheaper in tokens. | jpeg |
| selector | No | CSS selector to capture just one element. Omit for the whole page. | |
| full_page | No | Capture the entire scrollable page instead of just the viewport. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It discloses the core action, a meaningful side effect ('saves a full-resolution PNG to disk'), and the return behavior ('returns its path'). It does not detail every behavioral nuance, but it covers the key operational facts.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the main action and purpose, followed by the side effect and return path. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no annotations and no output schema, the description compensates well by stating the action, purpose, side effect, and return path. It does not mention prerequisites like an open browser page, but that is reasonably implied by the tool set and sibling names.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds no parameter-specific meaning beyond what the schema already provides, but it does not need to because each parameter is already described clearly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description states a specific verb and resource ('Capture the current page as an image') and a clear purpose ('visually judge layout, spacing, and alignment'), which distinguishes it from text-, console-, and interaction-focused sibling tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly implies when to use it — when visual layout and spacing judgment is needed — but does not explicitly name alternatives or state when not to use it. Sibling tools like check_responsive and audit_design overlap somewhat, so an explicit exclusion would help.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
9 tool updates
v1.0.0- First observed
audit_design - First observed
check_responsive - First observed
close_browser - First observed
get_page_text - First observed
interact - First observed
open_page - First observed
read_console - First observed
read_network_errors - First observed
screenshot
TDQS
Scored across 9 tools
Most tools have clear, distinct purposes, but check_responsive and audit_design both include horizontal overflow checks, which could lead to minor confusion. Overall descriptions are specific enough to tell them apart.
Most tool names follow a verb_noun snake_case pattern (check_responsive, read_console, open_page). Two deviations exist: 'screenshot' is a bare noun and 'interact' is a bare verb, but they still fit the general style.
9 tools is well within the ideal 3-15 range. Each tool covers a distinct inspection or interaction task, and none feel redundant or unnecessary for the server's browser auditing purpose.
The tool set covers the core workflow: open, inspect visually, check responsive/design/accessibility, read console/network, extract text, interact, and close. Minor gaps like explicit viewport resizing or element-level queries exist, but they are workaroundable.
Maintenance
Related MCP Connectors
Validate HTML/CSS, audit SEO and JSON-LD, check links, and capture responsive screenshots.
- mcpOAuthcom.screenshotink
Screenshot, diff, audit and sitemap-capture any web page — 5 MCP tools for AI agents.
Website QA for your coding agent: audit SEO, performance, security, accessibility over MCP.
Capture screenshots, detect visual regressions between page versions, and analyze with AI.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to capture screenshots, run visual diffs, accessibility audits, and batch sweep plans for web pages via MCP tools.14 npm2MIT
- AlicenseNot gradedqualityBmaintenanceMCP server for rendering responsive screenshots of URLs at multiple viewports. Enables agents to capture screenshots and detect visual issues like overflow, clipped elements, and missing alt text.MIT
- AlicenseNot gradedqualityCmaintenanceVisual frontend accessibility inspector MCP server. WCAG contrast checking, touch target validation, heading hierarchy audits, responsive screenshots, and S+ grading across mobile and desktop viewports.MIT
- AlicenseNot gradedqualityCmaintenanceEnables visual review of frontend UI variants by providing an MCP tool that opens, refreshes, verifies, captures, and closes review surfaces.MIT