browser-control-mcp-server
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., "@browser-control-mcp-server Open https://news.ycombinator.com and take a screenshot"
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.
browser-control-mcp-server
MCP server that gives AI agents full browser control — navigate to any website, click, type, scroll, take screenshots, inspect DOM, and read console logs.
Works with any MCP-compatible client: Claude, Cursor, Windsurf, Cline, and more.
Features
Navigate to any URL — public sites, localhost, web apps
Screenshot pages and get visual feedback as PNG images
Click buttons, links, menus, dropdowns by CSS selector
Type into inputs, search bars, textareas, password fields
Scroll in any direction by pixel amount
Read DOM — get full HTML source for structural analysis
Console logs — read JS errors, warnings, and debug output
Custom viewports — test at desktop (1920x1080), tablet (768x1024), or mobile (375x812)
Session persistence — cookies, login state, history maintained across calls
Two modes: headless Puppeteer (background) or real Chrome browser (via CDP connect)
Anti-bot bypass — spoofed user agent, no webdriver flag
Related MCP server: Cloudflare Playwright MCP
Quick Start
1. Install
npm install -g browser-control-mcp-serverThat's it. The installer automatically configures browser-control in all detected AI clients on your system — no manual setup needed.
Supported clients (auto-configured on install): Claude Desktop · Claude Code · Cursor · Windsurf · VS Code (Copilot/Cline) · Zed · Continue · OpenCode · Cody
Works on macOS, Windows, and Linux.
After install you'll see something like:
[browser-control-mcp] Configuring AI clients...
✓ Claude Desktop configured
✓ Cursor configured
— Windsurf not found (skipped)
[browser-control-mcp] Done. Restart your AI client to activate browser-control.Just restart your AI client and the browser tools are ready.
Manual Configuration (if needed)
If auto-setup didn't catch your client, add this to your MCP config manually:
{
"mcpServers": {
"browser-control": {
"command": "npx",
"args": ["browser-control-mcp-server"]
}
}
}2. Use It
Tell your AI agent:
"Open https://example.com and take a screenshot"
"Fill out the contact form on my site and submit it"
"Check my website on mobile viewport and show me how it looks"
The agent will use the browser tools automatically.
Tools
Tool | Description |
| Choose headless or Chrome extension mode |
| Check connection status and active sessions |
| Open any URL with optional viewport size |
| Capture page as PNG image |
| Click element by CSS selector |
| Type text into input fields |
| Scroll page by pixel amount |
| Get current page URL |
| Get HTML (or plain text), optionally scoped to a selector |
| Read JS console output |
| Compact accessibility-tree view, cheaper than a full DOM dump |
| Extract visible text or an attribute, without raw HTML |
| Press keys and key combinations |
| Hover over an element |
| Select from a native |
| Wait for an element, text, or timeout |
| Accept or dismiss alert/confirm/prompt dialogs |
| Upload files to a file input |
| Drag and drop between elements |
| List, open, switch, or close tabs |
| Go back to the previous page |
| Run arbitrary JavaScript in the page |
| Get, set, delete, or clear cookies |
| Get, set, or clear localStorage/sessionStorage |
| Render the current page to a PDF file |
| List captured requests or block by resource type (headless only) |
| Configure a download directory and list downloaded files |
| Cheap page-size pre-check before calling |
| Save a named sequence of tool calls, replay it later |
| Set/clear HTTP Basic/Digest Auth credentials |
| Device presets, dark mode, timezone, geolocation, permissions, network/CPU throttling |
| List iframes; target one with |
| Fill multiple form fields (inputs, selects, checkboxes) in one call |
| Reload the page, with an optional cache-bypassing hard refresh |
| Go forward (counterpart to |
| Read uncaught JS exceptions, distinct from console logs |
| Read/write the system clipboard (auto-grants permission) |
| Full detail on one element: attributes, bounding box, styles |
| Search for elements by text/role, no CSS selector needed |
| List/delete named persistent Chrome profiles |
Browser Modes
Headless Mode (Default)
Opens an invisible background browser using Puppeteer. No setup required.
Default viewport: 1024x768
Custom viewport: pass
widthandheighttobrowser_navigateAnti-bot detection bypass included
Sessions identified by
sessionId— pass to all subsequent calls
Connect Mode (Optional)
Controls your real running Chrome browser via the Chrome DevTools Protocol (CDP). No extension required.
Setup:
Launch Chrome with the remote debugging port enabled:
# macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222
# Linux
google-chrome --remote-debugging-port=9222
# Windows
chrome.exe --remote-debugging-port=9222Then set connect mode in your AI agent:
browser_select_mode({ mode: "connect" })The server connects to your running Chrome instance and controls it directly — no extension install needed.
Examples
Check a website
browser_navigate({ url: "https://example.com" })
browser_screenshot()Test mobile layout
browser_navigate({ url: "https://example.com", width: 375, height: 812 })
browser_screenshot()Fill and submit a form
browser_navigate({ url: "https://example.com/contact" })
browser_type({ selector: "input[name=email]", text: "user@example.com" })
browser_type({ selector: "textarea[name=message]", text: "Hello!" })
browser_click({ selector: "button[type=submit]" })
browser_screenshot()Login to a site
browser_navigate({ url: "https://example.com/login" })
browser_type({ selector: "#username", text: "myuser" })
browser_type({ selector: "#password", text: "mypass" })
browser_click({ selector: "#login-btn" })
browser_screenshot()Debug JavaScript errors
browser_navigate({ url: "https://example.com" })
browser_console_logs()Tool Parameters
browser_navigate
Parameter | Type | Required | Default | Description |
| string | Yes | — | URL to navigate to |
| number | No | 1024 | Viewport width in pixels (headless only) |
| number | No | 768 | Viewport height in pixels (headless only) |
| string | No | — | Reuse existing headless session |
| string | No | — |
|
browser_click
Parameter | Type | Required | Description |
| string | Yes | CSS selector (e.g. |
| string | No | Headless session ID |
| string | No |
|
browser_type
Parameter | Type | Required | Description |
| string | Yes | CSS selector of input element |
| string | Yes | Text to type |
| string | No | Headless session ID |
| string | No |
|
browser_scroll
Parameter | Type | Required | Default | Description |
| number | No | 0 | Horizontal scroll (positive=right) |
| number | No | 0 | Vertical scroll (positive=down) |
| string | No | — | Headless session ID |
| string | No | — |
|
browser_screenshot, browser_get_url, browser_get_dom, browser_console_logs
Parameter | Type | Required | Description |
| string | No | Headless session ID |
| string | No |
|
browser_select_mode
Parameter | Type | Required | Description |
| string | No |
|
browser_status
No parameters.
Viewport Presets
Device | Width | Height |
Mobile (iPhone) | 375 | 812 |
Mobile (Android) | 360 | 800 |
Tablet (iPad) | 768 | 1024 |
Laptop | 1366 | 768 |
Desktop | 1920 | 1080 |
4K | 3840 | 2160 |
Requirements
Node.js >= 18.0.0
Chrome/Chromium (auto-downloaded by Puppeteer for headless mode)
Chrome browser + extension (for extension mode only)
Development
git clone https://github.com/yogesh-joshi-0333/browser-control-mcp-server.git
cd browser-control-mcp-server
npm install
npm run build
npm testLicense
Available Tools
40 toolsbrowser_authBrowser HTTP Basic AuthA
Set or clear HTTP Basic/Digest Auth credentials for the current page — the kind of login prompt the browser itself shows (a native dialog), not a login form on the page. Call this BEFORE browser_navigate to a protected URL (e.g. a password-protected staging site). Use clear:true to remove credentials afterward.
Inputs: mode, clear, password, username, +1 more.
browser_clickBrowser ClickA
Click any element on the page by CSS selector — buttons, links, menus, dropdowns, checkboxes, tabs, etc. Examples: "#submit-btn", "button[type=submit]", ".nav-link", "a.login". Waits for the element to be visible, clicks it, then waits for the page to stabilize (handles AJAX, animations, re-renders). Use browser_get_dom first if you need to find the right selector. To click inside an iframe, pass frameIndex from browser_frames (this always uses the simple DOM-click path, since humanClick's mouse simulation only works on the main page). To reach into shadow DOM, prefix the selector with "pierce/" instead.
Inputs: selector (required), mode, sessionId, frameIndex, +1 more.
browser_clipboardBrowser ClipboardA
Read or write the system clipboard from the page context. Automatically grants the clipboard-read/clipboard-write permissions for the current origin first — you do NOT need to call browser_emulate separately for this. Use to verify a "Copy to clipboard" button worked, or to paste text a page doesn't expose an input for.
Inputs: action (required), mode, text, sessionId.
browser_console_logsGet Browser Console LogsA
Read JavaScript console output from the current page — includes console.log, console.warn, console.error, and console.info messages with timestamps. Use this to: debug JavaScript errors, check for failed API calls, find runtime exceptions, see application logs, or diagnose why something is not working on the page.
Inputs: mode, sessionId.
browser_cookiesBrowser CookiesA
Get, set, delete, or clear cookies on the current page. Use this to inspect auth/session cookies, inject a saved session to skip a login flow, or clean up before testing a fresh session.
Inputs: action (required), mode, name, path, +6 more.
browser_downloadsBrowser DownloadsA
Configure where downloads are saved for this session, and list what has landed there. Call action "configure" once with a directory before triggering a download (e.g. clicking a download link), then action "list" afterward to see the files and their sizes.
Inputs: action (required), mode, path, sessionId.
browser_drag_dropBrowser Drag & DropA
Drag an element and drop it onto another element. Use for kanban boards, sortable lists, reordering items, or any drag-and-drop interface. Simulates a full human drag: mousedown on source → mousemove to target → mouseup on target, with proper drag events dispatched.
Inputs: sourceSelector (required), targetSelector (required), mode, sessionId.
browser_emulateBrowser EmulateA
Emulate device/environment conditions on the current page — device presets, dark mode, reduced motion, timezone, locale, geolocation, permissions, network throttling, and CPU throttling. Pass only the options you need; each is applied independently and the response lists what was actually changed. Geolocation and permissions are scoped to the page's current origin, so navigate first.
Inputs: mode, device, locale, timezone, +7 more.
browser_executeExecute JavaScriptA
Execute arbitrary JavaScript code on the current page and return the result. Use this for complex interactions that other tools cannot handle: jQuery/Select2 dropdowns (e.g. jQuery("#select").val("value").trigger("change")), reading JavaScript variables, calling page functions, manipulating complex widgets, dispatching custom events, or any DOM manipulation. The code runs in the page context with full access to window, document, jQuery, etc. Return a value from your code and it will be sent back as the result. Examples: Set Select2 dropdown: 'jQuery("#project").val("123").trigger("change")' | Read a value: 'document.querySelector("#total").textContent' | Fill multiple fields: 'jQuery("#name").val("John"); jQuery("#email").val("john@example.com"); "done"' | Trigger form submit: 'document.querySelector("form").submit()' | Check if element exists: '!!document.querySelector(".success-message")'
Inputs: code (required), mode, sessionId.
browser_extractBrowser ExtractA
Extract structured text or attributes from the page without dumping raw HTML. With no selector, returns the page's visible text content (like a reader view). With a selector, returns the text (or a given attribute) of the matching element(s). Much smaller and more directly useful than browser_get_dom when you just need the content, not the markup.
Inputs: mode, multiple, selector, attribute, +1 more.
browser_file_uploadBrowser File UploadB
Upload one or more files to a file input element. Provide the CSS selector of the element and an array of absolute file paths to upload. Works with single and multiple file inputs. Examples: browser_file_upload({selector: "input[type=file]", paths: ["/home/user/document.pdf"]}) or multiple files: browser_file_upload({selector: "#photos", paths: ["/tmp/img1.png", "/tmp/img2.png"]})
Inputs: paths (required), selector (required), mode, sessionId.
browser_findBrowser FindA
Search for element(s) by visible text and/or ARIA role, without needing a CSS selector or a full browser_snapshot dump. e.g. find({text: "sign in"}) or find({role: "button", text: "submit"}). Matches are tagged with a ref, usable as '[data-mcp-ref="f1"]' in browser_click/type/hover/select_option — same mechanism as browser_snapshot, but with an "f" prefix so the two never collide.
Inputs: mode, role, text, exact, +3 more.
browser_form_fillBrowser Form FillA
Fill multiple form fields in one call: { "#email": "user@example.com", "#country": "IN" }. Automatically uses the right interaction per element — types into text inputs/textareas, uses native selection, and clicks checkboxes/radios (interpreting a truthy value as "check it"). Optionally click a submit button afterward.
Inputs: fields (required), mode, sessionId, submitSelector.
browser_framesBrowser FramesA
List all frames (iframes) on the current page, each with an index, url, and name. Pass that index as frameIndex to browser_click, browser_type, or browser_get_dom to target content inside that iframe — the main document is not part of this list navigation-wise, but IS included as index 0 if it has children. Note: shadow DOM (unlike iframes) needs no special tool — prefix any selector with "pierce/" (e.g. "pierce/.my-shadow-element") in browser_click/type/get_dom/hover/select_option to reach into shadow roots.
Inputs: mode, sessionId.
browser_get_domGet Browser DOMA
Get the HTML source code of the current page (or a scoped subtree). Returns the rendered DOM including dynamically loaded content. Use this to: find CSS selectors for browser_click/browser_type, understand page structure, check element attributes and classes, inspect form fields, or analyze the page content as HTML or plain text. For large pages, prefer browser_snapshot (accessibility-tree view) or scope with selector — a full-page dump can be tens of thousands of characters.
Inputs: mode, format, selector, maxLength, +2 more.
browser_get_elementBrowser Get ElementA
Get full detail on ONE element by selector: tag name, all attributes, bounding box, visibility, text content, and a curated set of computed CSS properties. Complements browser_extract (text/attribute only) and browser_snapshot (a whole page of elements) — use this when you need to inspect a single specific element closely, e.g. checking why something looks wrong, or confirming an element is actually visible/enabled before interacting.
Inputs: selector (required), mode, styles, sessionId.
browser_get_urlGet Browser URLA
Get the current URL of the browser page. Useful to verify navigation succeeded, check the current location after redirects, or confirm which page the browser is on.
Inputs: mode, sessionId.
browser_handle_dialogHandle Browser DialogA
Handle JavaScript alert(), confirm(), and prompt() dialogs. Call this BEFORE triggering an action that shows a dialog (e.g. before clicking a delete button that shows a confirm). The handler will auto-accept or auto-dismiss the next dialog that appears. For prompt() dialogs, provide promptText to enter text before accepting. If a dialog is already showing, it will be handled immediately.
Inputs: action (required), mode, sessionId, promptText.
browser_hoverBrowser HoverA
Hover over an element to trigger dropdown menus, tooltips, hover effects, or any mouseover-activated content. The mouse moves to the element center and stays there. Use this before browser_click when a menu only appears on hover, or to reveal hidden UI elements.
Inputs: selector (required), mode, sessionId.
browser_keyboardBrowser KeyboardA
Press keyboard keys like Enter, Tab, Escape, arrow keys, or key combinations with Ctrl/Shift/Alt modifiers. Use to: submit forms (Enter), navigate between fields (Tab), close modals (Escape), select all text (Ctrl+A), copy/paste, or navigate autocomplete menus (ArrowDown/ArrowUp). If selector is provided, focuses that element first.
Inputs: key (required), mode, selector, modifiers, +1 more.
browser_macroBrowser MacroB
Save a named sequence of tool calls once, then replay it by name later against any session — collapses a repeated multi-step flow (e.g. "login") into a single tool call instead of N round trips.
Inputs: action (required), mode, name, steps, +1 more.
browser_networkBrowser NetworkA
Inspect or control network traffic for a headless session: list captured requests (url, method, resourceType, status), clear the log, or block requests by resource type (e.g. "image", "font", "stylesheet", "media") to speed up pages and reduce noise. Blocking is only available in headless mode — connect mode (the user's real Chrome tab) never intercepts requests, to avoid adding latency or risk to their live browsing.
Inputs: action (required), mode, limit, sessionId, +1 more.
browser_page_errorsGet Browser Page ErrorsA
Read uncaught JavaScript exceptions thrown by the page (window "error" events / unhandled errors in page scripts). Different from browser_console_logs: console_logs only captures explicit console.log/warn/error calls, this captures real crashes — a script that threw and stopped running, even if it never called console.error itself. Check this whenever a page seems "stuck" or a feature silently does nothing.
Inputs: mode, sessionId.
browser_pdfBrowser PDF ExportA
Render the current page to a PDF file on disk (not returned inline — PDFs are too large for tool-call context). Returns the saved path and file size. Headless mode only.
Inputs: path (required), mode, format, landscape, +1 more.
browser_profilesBrowser ProfilesA
List or delete named persistent browser profiles. A profile is a Chrome user-data directory whose cookies, localStorage, and login state survive across separate MCP server runs — unlike a normal session, which is wiped once it ends. Create one implicitly by passing profile: "name" to browser_navigate on a brand-new session (letters, digits, dash, underscore only in the name).
Inputs: action (required), name.
browser_reloadBrowser ReloadA
Reload the current page. Equivalent to pressing the browser's refresh button. Use ignoreCache:true for a hard refresh that bypasses the browser cache (equivalent to Ctrl+Shift+R) — useful when testing a deployed change that the page might otherwise serve stale/cached.
Inputs: mode, sessionId, ignoreCache.
browser_screenshotBrowser ScreenshotA
Capture a screenshot of the current page as a PNG image. Returns the actual rendered visual — you can see and describe layout, design, text, images, errors, and any visual content. Use this after browser_navigate to see a page, after browser_click to verify what happened, or anytime you need to visually inspect the browser. Pass sessionId to screenshot a specific headless session.
Inputs: mode, sessionId.
browser_scrollScroll Browser PageA
Scroll the page by pixel amount. Use positive y to scroll down, negative y to scroll up. Examples: scroll down 500px → {y: 500}, scroll up → {y: -500}, scroll to bottom → {y: 99999}, scroll right → {x: 500}. Returns the final scroll position. Useful for viewing content below the fold, triggering lazy-loaded images, or reaching elements further down the page.
Inputs: x, y, mode, sessionId.
browser_select_modeSelect Browser ModeA
Check available browser modes and set the session default. CALL THIS FIRST before using any other browser tool. Two modes: "connect" (connects to user's Chrome via debug port) or "headless" (invisible background Puppeteer browser, always available). Call without params to see what is available. Call with mode="headless" or mode="connect" to set the default for all subsequent calls. If only headless is available, it is auto-selected.
Inputs: mode.
browser_select_optionBrowser Select OptionA
Select an option from a native HTML dropdown by value or visible label text. Also works with Select2/jQuery dropdowns — automatically detects and triggers the correct change events. Examples: browser_select_option({selector: "#country", value: "US"}) or browser_select_option({selector: "#country", label: "United States"}). For complex custom dropdowns that don't use , use browser_execute with jQuery instead.
Inputs: selector (required), mode, label, value, +1 more.
browser_snapshotBrowser Accessibility SnapshotA
Get a compact accessibility-tree view of the page: interactive and semantic elements (links, buttons, inputs, headings, landmarks) as a small indented text list, each tagged with a stable ref like [ref=e12]. Far cheaper than browser_get_dom for finding what to interact with — use this first when exploring an unfamiliar page. Every ref is also a valid CSS selector — pass [data-mcp-ref="e12"] directly as the selector argument to browser_click, browser_type, browser_hover, or browser_select_option. Pass diff:true to get only what changed since your last browser_snapshot call in this session — much cheaper than a full snapshot for checking the result of a click/type.
Inputs: diff, mode, maxNodes, sessionId.
browser_statsBrowser Page StatsA
Cheap pre-check for page size and complexity: DOM node count, approximate HTML length, and approximate visible-text length. Call this BEFORE browser_get_dom on an unfamiliar page to decide whether a full dump is safe, or whether you should scope it (selector/maxLength) or use browser_snapshot/browser_extract instead.
Inputs: mode, sessionId.
browser_statusBrowser StatusA
Check browser readiness: reports whether a Chrome debug port is available (for connect mode) and lists all active Puppeteer session IDs. No parameters needed. Use this to verify the server is running and see which browser sessions are available before interacting with pages.
Inputs: no named parameters. Returns: connectAvailable, headlessSessions
browser_storageBrowser StorageA
Get, set, or clear localStorage/sessionStorage on the current page. Use this alongside browser_cookies to save and restore full session state (auth tokens, app state) and skip repeated login flows across calls.
Inputs: action (required), key, area, mode, +2 more.
browser_tabsBrowser TabsA
Manage browser tabs — list open tabs, create new tabs, switch between tabs, close tabs, or screenshot a specific tab WITHOUT switching to it. Use this for: OAuth flows that open popups, links that open in new tabs, multi-page workflows, comparing two open tabs side by side, or cleaning up tabs. Manages pages within the Puppeteer browser session.
Inputs: action (required), url, mode, index, +1 more.
browser_typeBrowser TypeA
Type text into any input field, textarea, search bar, or contenteditable element by CSS selector. Use this to fill out forms, enter search queries, write messages, type login credentials, etc. Examples: browser_type({selector: "input[name=email]", text: "user@example.com"}), browser_type({selector: "#search", text: "search query"}). Combine with browser_click to submit forms after filling them. To type into an element inside an iframe, pass frameIndex from browser_frames. To reach into shadow DOM, prefix the selector with "pierce/" (e.g. "pierce/input#name") — no frameIndex needed for that.
Inputs: text (required), selector (required), mode, sessionId, +1 more.
browser_wait_forWait For ConditionA
Wait for a condition before proceeding — an element to appear, text to become visible, or text to disappear. Use this to handle dynamic content, AJAX loading, animations, or any async page updates. Examples: wait for a success message after form submit, wait for a loading spinner to disappear, wait for a modal to open. Timeout defaults to 10 seconds.
Inputs: mode, text, timeout, visible, +3 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 40 tools
Several inspection tools (browser_get_dom, browser_snapshot, browser_extract, browser_get_element, browser_find, browser_stats) all retrieve page content with subtle differences, making misselection likely. Interaction and navigation tools are mostly distinct, but the large surface adds ambiguity. Descriptions help, but the overlap is still notable.
All 40 tools use the browser_ prefix with snake_case verb/noun naming (e.g., browser_navigate, browser_click, browser_get_dom). There are no deviations in case or structure. The pattern is highly predictable throughout.
40 tools is well above the 15-tool guideline and feels excessive for a browser control server. While the domain is broad, many capabilities could be consolidated (e.g., the inspection tools). The large count forces agents to navigate a heavy menu for common actions.
The surface covers navigation, interaction, inspection, network, storage, cookies, emulation, dialogs, uploads/downloads, tabs, frames, and more, with no obvious major gaps. A minor missing piece is an explicit session-close tool, though closing all tabs is a workaround. Overall coverage is strong.
Related MCP Connectors
Let your AI agent operate any website through a real, logged-in browser session.
Control a real browser from AI agents: navigate, click, type, screenshot, read the page.
Give AI agents a real cloud Chrome: open sessions, navigate, read pages, click, type and screenshot.
Undetectable cloud browser sessions for AI agents and scrapers. Navigate, extract, click, captcha.
Related MCP Servers
- AlicenseNot gradedqualityNot gradedmaintenanceEnables AI assistants to control a browser through a set of tools, allowing them to perform web automation tasks like navigation, typing, clicking, and taking screenshots.Apache 2.0
- AlicenseNot gradedqualityNot gradedmaintenanceEnables AI assistants to control a browser through a set of tools, allowing them to perform web automation tasks like navigation, typing, clicking, and taking screenshots.Apache 2.0
- AlicenseNot gradedqualityNot gradedmaintenanceEnables AI assistants to control a browser through a set of tools, allowing them to perform web automation tasks like navigation, typing, clicking, and taking screenshots.Apache 2.0
- AlicenseNot gradedqualityNot gradedmaintenanceEnables AI assistants to control a browser for web automation tasks such as navigation, typing, clicking, and taking screenshots.Apache 2.0