The simplest, thinnest, and most powerful harness to control your real browser with your agent.
26 tools with consistent naming (browser_* prefix) and present descriptions. All tools have input schemas with type definitions. However, descriptions are terse (avg ~80 chars, well below the 194-char baseline for A+ tools), lack WHEN/WHY context, and omit error recovery guidance. Parameter descriptions are minimal. Output schemas are undocumented, LLMs cannot infer what fields to expect from responses. No tool annotations (readOnlyHint/destructiveHint). Error handling is basic (ValueError for missing elements) without actionable recovery paths. Composition is sound (single responsibility per tool), but descriptions do not guide LLM selection or explain prerequisites.
Clicks on the element specified by the CSS selector using JavaScript. This is generally more reliable for silent automation.
Dispatches a native mouse click at the given viewport coordinates (x, y). Button can be 'left', 'middle', or 'right'.
Closes the browser tab specified by the given targetId. You can get targetIds from browser_list_tabs or browser_new_tab.
Dispatches a DOM KeyboardEvent directly to the matched element. Use this when synthetic DOM events work more reliably than native CDP input.
Executes JavaScript code in the context of the current page and returns the result.
Retrieves the outerHTML of the element matched by the CSS selector. Useful for inspecting DOM structure when innerText is insufficient.
Output schemas undocumented. Tools return strings or JSON without declaring field structure. LLMs cannot infer what data is available for downstream tool calls or user display.
Descriptions lack WHEN/WHY context and error recovery guidance. E.g., 'Navigates to a specific URL' does not explain when to use this vs browser_go_back, or what happens if the URL is invalid. Descriptions average ~80 chars vs 194-char baseline.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). LLMs cannot distinguish safe reads from destructive writes without explicit hints. browser_close_tab and browser_navigate should be marked destructive/write.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 56 | 2026-07-28+ | v2 |
Retrieves the innerText of the element matched by the CSS selector.
Navigates to the previous page in history.
Navigates to the next page in history.
Handles an open JavaScript dialog (alert, confirm, prompt, beforeunload). Set accept=True to click OK/Yes, and accept=False to click Cancel/No. If it's a prompt, you can provide prompt_text to fill the input field.
Finds the targetId of the first iframe whose URL contains url_substr. This targetId can be used with js(..., target_id=...) internally, or returned for reference.
Lists all available browser tabs. Set include_chrome to False to hide internal chrome:// tabs. Returns a list of dictionaries with targetId, title, and url.
Navigates to a specific URL in the active browser tab and waits for the page to load.
Opens a new browser tab and optionally navigates to a URL. Returns the targetId of the new tab.
Returns a summary of the current page including title, URL, and viewport info.
Presses a specific keyboard key (e.g., 'Enter', 'Tab', 'Escape', 'a', 'B'). modifiers is a bitfield: 1=Alt, 2=Ctrl, 4=Meta(Cmd), 8=Shift.
Dispatches a mouse wheel scroll event at the specified (x, y) coordinates. dy is the vertical scroll delta (negative means scroll down, positive means scroll up). dx is the horizontal scroll delta.
Scrolls to the absolute bottom of the current page.
Scrolls to the absolute top of the current page.
Selects an option in a <select> dropdown by its value attribute.
Switches to the browser tab specified by the given targetId. You can get targetIds from browser_list_tabs.
Takes a screenshot of the current browser viewport and saves it to disk. Returns an Image object natively supported by FastMCP. If filename is a relative path, it is resolved inside the OS temp directory so the file always ends up in a predictable, writable location.
Types text into the browser. If a CSS selector is provided, it attempts to focus that element first using JS.
Uploads a file to an <input type="file"> element using its CSS selector. Uses the native CDP DOM.setFileInputFiles method, bypassing bot detection.
Waits for a specific amount of seconds (ideal for human-mimicry).
Waits until document.readyState == 'complete' or the timeout is reached.
Error handling is minimal. browser_click raises ValueError for missing elements but does not suggest recovery (e.g., 'Try browser_wait_for_load() first' or 'Check selector with browser_get_html()'). No categorization of retryable vs fatal errors.
Parameter descriptions are minimal or missing context. E.g., 'selector' appears in 10+ tools but descriptions do not explain CSS selector syntax, escaping rules, or what happens if multiple elements match. No constraints on string length or format.