webdriver MCP server
Commit Nov 8, 2026Lets AI agents control a real Firefox browser via Selenium WebDriver to navigate, interact with elements, and diagnose web issues.
Also known as VitexSoftware/mcp-server-webdriver
- Stars
- 4
- Tools
- 38
- Downloads, 30 days
- —
- Latest version
- —
- Last commit
- Nov 8, 2026
- License
- MIT
What is webdriver MCP?
webdriver lets AI agents control a real Firefox browser via Selenium WebDriver to navigate, interact with elements, and diagnose web issues. It exposes 38 tools, such as browser_open, browser_close, browser_status.
Summary generated from the project's README
About webdriver MCP server
Developers and QA engineers can use this server to grant AI agents direct control over a real Firefox browser. By using Selenium WebDriver and geckodriver, the assistant can navigate websites, interact with UI elements, and perform complex tasks like filling out multi-step forms or managing session cookies. This setup eliminates the need to manually copy and paste errors from DevTools into a chat interface.
The server operates via stdin/stdout and is launched by an MCP client. It requires Python 3.11 or higher, Selenium, and a recent version of Firefox. Users can configure the server to use specific Firefox profiles via command line flags, allowing the agent to access existing sessions and logged-in states.
Diagnostic capabilities are a core feature, provided the user has geckodriver 0.34 or newer to enable BiDi support. Tools like devtools_report allow the agent to inspect JavaScript errors, console logs, and network failures. It also includes specialized tools for inspecting computed CSS, managing cookies, and capturing screenshots of specific page elements.
What you can do with it
- 1Automate complex user flowsYou can instruct an agent to log into a website and navigate through a specific sequence of actions.
- 2Audit network performanceAn agent can find slow-loading assets on a page to help optimize loading speeds.
Written from the project's README. Every use case is checked against a quote from it.
webdriver MCP tools 38
Detected from the READMEbrowser_openbrowser_closebrowser_statusbrowser_set_viewportbrowser_navigatebrowser_backbrowser_forwardbrowser_refreshbrowser_screenshotbrowser_get_titlebrowser_get_urlbrowser_get_source
| browser_open | — | |
| browser_close | — | |
| browser_status | — | |
| browser_set_viewport | — | |
| browser_navigate | — | |
| browser_back | — | |
| browser_forward | — | |
| browser_refresh | — | |
| browser_screenshot | — | |
| browser_get_title | — | |
| browser_get_url | — | |
| browser_get_source | — |
Show all 38 toolsShow fewer tools
browser_get_textbrowser_get_attributebrowser_find_elementsbrowser_clickbrowser_fillbrowser_selectbrowser_execute_jsbrowser_waitbrowser_scrollbrowser_press_keybrowser_hoverbrowser_switch_framebrowser_accept_dialogbrowser_dismiss_dialogbrowser_get_cookiesbrowser_set_cookiedevtools_reportdevtools_js_errorsdevtools_consoledevtools_network_faileddevtools_network_alldevtools_cleardevtools_enable_bididevtools_computed_cssdevtools_element_infodevtools_css_variables
| browser_get_text | — | |
| browser_get_attribute | — | |
| browser_find_elements | — | |
| browser_click | — | |
| browser_fill | — | |
| browser_select | — | |
| browser_execute_js | — | |
| browser_wait | — | |
| browser_scroll | — | |
| browser_press_key | — | |
| browser_hover | — | |
| browser_switch_frame | — | |
| browser_accept_dialog | — | |
| browser_dismiss_dialog | — | |
| browser_get_cookies | — | |
| browser_set_cookie | — | |
| devtools_report | — | |
| devtools_js_errors | — | |
| devtools_console | — | |
| devtools_network_failed | — | |
| devtools_network_all | — | |
| devtools_clear | — | |
| devtools_enable_bidi | — | |
| devtools_computed_css | — | |
| devtools_element_info | — | |
| devtools_css_variables | — |
Configuration
GECKODRIVER_PATH
| Name | Description | |
|---|---|---|
| GECKODRIVER_PATH | — |
Automated checks
Ran Nov 14, 2026Full report →Not verified yet. A server needs a score of 80, no serious finding, and enough data for us to check. How checks work · What to fix for more points
- Source repository linked and reachablevitexsoftware/mcp-server-webdriver is public and reachablegithub.com/vitexsoftware/mcp-server-webdriver ↗Pass
- Package names this repository as its sourceNot checked
- Build provenance (Sigstore attestation)Not checked
- Open source license (OSI)MITspdx.org/licenses/MIT.html ↗Pass
- Commit or release in the last yearLast commit or release 2026-11-08github.com/vitexsoftware/mcp-server-webdriver ↗Pass
- OpenSSF ScorecardNot checked
- Package name not close to a popular packageNot checked
- No critical advisory in the package or its dependenciesNot checked
- No hidden instructions to the model38 tool descriptions and the README read; no override phrases, credential paths or hidden charactersPass
- Destructive tools are labelledNo tool named like delete, drop or execPass
- Remote endpoint answers the MCP handshakeNot checked
README
View on GitHubmcp-server-webdriver
MCP Server that lets AI agents control a real web browser via Selenium WebDriver (Firefox + geckodriver).
Built with FastMCP.
What it does
The server eliminates the copy-paste loop between the browser and the AI assistant. Instead of opening DevTools, copying errors, pasting them into a chat, and repeating, the assistant opens the browser itself, navigates, captures errors and screenshots, and diagnoses the problem directly.
You: "Why is the checkout button broken on /cart?"
AI: browser_open → browser_navigate("/cart")
→ devtools_report # JS errors? network failures?
→ browser_screenshot # what does it look like?
→ devtools_computed_css("button#checkout") # hidden? wrong z-index?
→ "The button has pointer-events: none — overridden by .disabled class
applied when cart.js fails to load (404 on /static/cart.js)."
Requirements
| Dependency | Version |
|---|---|
| Python | ≥ 3.11 |
| FastMCP | ≥ 2.10 |
| selenium | ≥ 4.0 |
| Firefox | any recent |
| geckodriver | ≥ 0.34 |
Installation
Recommended — Debian package from VitexSoftware repository
sudo curl -fsSL http://repo.vitexsoftware.com/KEY.gpg -o /usr/share/keyrings/vitexsoftware-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/vitexsoftware-archive-keyring.gpg] http://repo.vitexsoftware.com trixie main backports" \
| sudo tee /etc/apt/sources.list.d/vitexsoftware.list
sudo apt update
sudo apt install mcp-server-webdriver
The backports component is required, not optional: python3-mcp (a
python3-fastmcp dependency) needs python3-jsonschema >= 4.20.0, which is
newer than the version Debian trixie ships in main — it's only available
in backports. Without it, apt install fails with an unmet-dependency
error on python3-jsonschema.
This installs gecko-driver, python3-selenium, python3-fastmcp, and
mcp-server-webdriver in a single step.
Alternative — system package manager
# Debian/Ubuntu (official repos — may be older geckodriver):
sudo apt install firefox-geckodriver
# macOS:
brew install geckodriver
# Rust / cargo (build from source):
cargo install geckodriver
Then install Python dependencies:
pip install fastmcp selenium
Fallback — webdriver-manager (auto-download)
pip install fastmcp selenium webdriver-manager
# geckodriver is downloaded automatically on first browser_open call
Usage
mcp-server-webdriver [OPTIONS]
OPTIONS
-P <profile> Start Firefox with a named profile
--profile <path> Start Firefox with a profile directory at <path>
-h, --help Show help and exit
The server speaks MCP over stdin/stdout and is launched automatically by the MCP client — not by hand.
Use cases
Debug a broken page
Ask: "Why does /dashboard show a blank screen?"
The assistant will:
browser_open— open Firefox headlesslybrowser_navigate— go to/dashboarddevtools_report— get JS errors, console output, and failed network resources in one callbrowser_screenshot— see what the page actually looks like- Explain the root cause from the combined evidence
devtools_report is the primary diagnostic tool — equivalent to opening the Console
and Network tabs in DevTools and reading them simultaneously.
Diagnose a CSS / layout problem
Ask: "The sidebar overlaps the content area on mobile. Why?"
browser_open— open the pagebrowser_screenshot— capture the broken layoutdevtools_computed_css(".sidebar")— checkposition,width,z-index,overflowdevtools_css_variables("--")— verify design tokens loaded correctlydevtools_network_failed— check whether any stylesheet failed to load
Automate a login flow
Ask: "Log into the app at /login with user=admin, password=secret and screenshot the dashboard."
browser_open— start the browserbrowser_navigate— go to/loginbrowser_fill("#username", "admin")— type usernamebrowser_fill("#password", "secret")— type passwordbrowser_press_key("enter")— submit the formbrowser_wait("#dashboard", condition="visible")— wait for redirectbrowser_screenshot— capture the result
Inject a session cookie to skip login
Ask: "Check the admin panel using my existing session token."
browser_open— start the browserbrowser_navigate— go to the app's root so the cookie domain matchesbrowser_set_cookie("session", "<token>")— inject the auth cookiebrowser_navigate— now navigate to the protected pagebrowser_screenshot— confirm access
Enumerate page content
Ask: "List all the navigation links on the homepage."
browser_open+browser_navigate— open the pagebrowser_find_elements("nav a")— get all links with their text, href, and visibility- Return the structured list
Interact with hover menus
Ask: "Click the third item in the Products dropdown."
browser_hover(".nav-products")— trigger the:hoverstate that reveals the dropdownbrowser_wait(".dropdown-menu", condition="visible")— wait for animationbrowser_find_elements(".dropdown-menu a")— list the itemsbrowser_click(".dropdown-menu a:nth-child(3)")— click the right one
Test a multi-step form
Ask: "Fill out the registration form and submit it."
browser_fill("#first-name", "Alice")browser_fill("#last-name", "Smith")browser_fill("#email", "alice@example.com")browser_select("#country", "Czech Republic")browser_press_key("tab")— move focus to next fieldbrowser_click("button[type=submit"]")browser_wait(".success-message", condition="visible")devtools_report— check for any JS errors or failed API calls during submission
Handle JS dialogs
Ask: "Click the Delete button and confirm the dialog."
browser_click("#delete-btn")browser_accept_dialog— click OK on theconfirm("Are you sure?")browser_wait(".deleted-notice", condition="present")
Scroll and capture a long page
Ask: "Screenshot the footer of the page."
browser_open+browser_navigatebrowser_scroll("footer")— scroll the footer element into viewbrowser_screenshot("footer")— capture just the footer element
Or scroll by offset to trigger lazy-loaded content:
browser_scroll(by=True, y=1000)— scroll down 1000 pxbrowser_wait(".lazy-section", condition="visible")— wait for lazy contentbrowser_screenshot— capture the now-loaded content
Use a real Firefox profile (stay logged in)
Configure the server with a named profile that already has your session:
{
"mcpServers": {
"webdriver": {
"command": "mcp-server-webdriver",
"args": ["-P", "work"]
}
}
}
The browser starts with your existing cookies, saved passwords, and extensions. Ask: "Check my GitHub notifications." — no login step needed.
Profile selection is intentionally a server-launch-time setting (-P/--profile
flags or FIREFOX_PROFILE/FIREFOX_PROFILE_DIR env vars) rather than a
browser_open tool parameter. That keeps the choice to expose a real,
logged-in profile to an agent in the hands of whoever configures the MCP
client — not something an agent (or a prompt injected via a visited page)
can request at runtime.
Audit network performance
Ask: "Which resources on /shop are slowest to load?"
browser_open+browser_navigate("/shop")devtools_network_all(slow_ms=500, limit=20)— requests over 500 ms, capped at 20 entries- Report the slowest assets with their URLs, types, and durations
Available Tools
Session management
| Tool | Description |
|---|---|
browser_open |
Open Firefox (URL optional, default about:blank); accepts width, height, user_agent for mobile emulation |
browser_close |
Quit the browser session |
browser_status |
Session state, geckodriver version, BiDi status, current viewport size, buffer counts |
browser_set_viewport |
Resize the viewport mid-session (e.g. 390×844 for iPhone 14) |
Navigation
| Tool | Description |
|---|---|
browser_navigate |
Navigate to a URL (bare hostnames get https://) |
browser_back |
Go back in history |
browser_forward |
Go forward in history |
browser_refresh |
Reload the current page |
Page inspection
| Tool | Description |
|---|---|
browser_screenshot |
Full-page or element PNG screenshot |
browser_get_title |
Current page <title> |
browser_get_url |
Current URL |
browser_get_source |
Raw HTML source (wrapped as untrusted content — see Security) |
browser_get_text |
Visible text (whole page or CSS selector; wrapped as untrusted content) |
browser_get_attribute |
Value of an HTML attribute on an element (wrapped as untrusted content) |
browser_find_elements |
List all elements matching a CSS selector |
Interaction
| Tool | Description |
|---|---|
browser_click |
Click element (CSS selector) |
browser_fill |
Type text into an input field (clears first by default) |
browser_select |
Select <option> in a <select> dropdown |
browser_execute_js |
Run JavaScript — returns JSON |
browser_wait |
Wait: visible / clickable / present / text:<str> |
browser_scroll |
Scroll to coords, by offset, or element into view |
browser_press_key |
Send enter / tab / escape / arrow / F-keys |
browser_hover |
Hover mouse over element (:hover states, tooltips, dropdowns) |
browser_switch_frame |
Switch into <iframe> or back to main document |
Dialogs & cookies
| Tool | Description |
|---|---|
browser_accept_dialog |
Accept a JS alert() / confirm() / prompt() |
browser_dismiss_dialog |
Dismiss a JS confirm() / prompt() |
browser_get_cookies |
Read all cookies for the current page |
browser_set_cookie |
Inject a cookie (auth tokens, session IDs) |
DevTools (require BiDi — Firefox + geckodriver ≥ 0.34)
| Tool | Description |
|---|---|
devtools_report |
Main diagnostic tool — JS errors + console + failed/slow network |
devtools_js_errors |
JavaScript exceptions only (entries carry an untrusted marker) |
devtools_console |
Console output (log / warn / error / info / debug; entries carry an untrusted marker) |
devtools_network_failed |
Failed resources (4xx, 5xx, DNS errors) |
devtools_network_all |
All network requests (supports limit= and filters) |
devtools_clear |
Clear buffered DevTools data (use before navigating) |
devtools_enable_bidi |
Attach BiDi listeners to a running session |
devtools_computed_css |
Computed CSS properties of an element |
devtools_element_info |
Bounding box, visibility, attributes, aria, outerHTML |
devtools_css_variables |
CSS custom properties (--var) in scope |
Security
Anything a visited page contains — HTML, visible text, attribute values,
console output, JS error messages, web storage — is attacker-controllable if
the page is malicious or compromised. Tools that relay this content back to
the calling agent (browser_get_source, browser_get_text,
browser_get_attribute, devtools_console, devtools_js_errors,
devtools_report, browser_get_storage) wrap it in an explicit
-----BEGIN/END UNTRUSTED CONTENT----- envelope (or an untrusted field on
structured entries), so an agent has a structural signal that the content is
data to read, never an instruction to follow — even if it's phrased as one.
This defends against indirect prompt-injection / agent-hijacking attacks
delivered via ordinary page content.
This complements the existing Firefox-profile lockdown (see Use a real Firefox profile): both exist because a page — or an instruction injected via one — should never be able to silently expand what the agent can do or see.
The server also defaults to read-only mode: page-mutating tools
(browser_click, browser_fill, browser_upload_file, browser_select,
browser_execute_js, browser_press_key, browser_accept_dialog,
browser_dismiss_dialog, browser_set_cookie, browser_set_storage,
browser_clear_storage) refuse to run unless WEBDRIVER_READONLY=false is
set. Navigation and session/viewport management (browser_open,
browser_navigate, browser_back/forward/refresh, browser_scroll,
browser_hover, browser_wait, browser_switch_frame, browser_close,
browser_set_viewport) are unaffected, since they're needed to reach the
page a read-only session inspects.
Environment variables
| Variable | Default | Description |
|---|---|---|
GECKODRIVER_PATH |
(unset) | Absolute path to geckodriver binary (highest priority) |
GECKODRIVER_AUTO_INSTALL |
true |
Set to false to disable webdriver-manager fallback |
FIREFOX_BINARY |
(unset) | Path to a custom Firefox executable |
FIREFOX_PROFILE |
(unset) | Named Firefox profile — same as -P |
FIREFOX_PROFILE_DIR |
(unset) | Profile directory path — same as --profile |
WEBDRIVER_READONLY |
true |
Set to false to allow page-mutating tools (click/fill/upload/select/execute_js/press_key/dialogs/cookies/storage). Empty/unset values stay read-only (fail-closed). |
geckodriver resolution order
| # | Source | Configure via |
|---|---|---|
| 1 | GECKODRIVER_PATH env variable |
Absolute path to the binary |
| 2 | System PATH (default) | apt install gecko-driver from repo.vitexsoftware.com |
| 3 | webdriver-manager auto-download | Fallback; disable with GECKODRIVER_AUTO_INSTALL=false |
MCP client configuration
Minimal config:
{
"mcpServers": {
"webdriver": {
"command": "mcp-server-webdriver"
}
}
}
With a named Firefox profile (stays logged in, uses saved passwords):
{
"mcpServers": {
"webdriver": {
"command": "mcp-server-webdriver",
"args": ["-P", "work"]
}
}
}
With a profile directory and explicit geckodriver path:
{
"mcpServers": {
"webdriver": {
"command": "mcp-server-webdriver",
"args": ["--profile", "/home/user/.mozilla/firefox/abc123.dev"],
"env": {
"GECKODRIVER_PATH": "/usr/bin/geckodriver"
}
}
}
}
Running tests
# Unit tests only (no browser required):
pytest tests/ -m "not integration"
# Live capability scenario (opens about:blank when geckodriver+Firefox exist):
python tests/live_capability_scenario.py
# All tests including browser integration:
pytest tests/
The live scenario respects WEBDRIVER_READONLY=true (default): mutating tools
must refuse, while session/read tools open about:blank, call
browser_status / browser_get_title / browser_get_url / browser_get_source,
then browser_close. If /usr/bin/geckodriver or Firefox is missing, browser
steps are skipped gracefully (exit 0).
Related MCP Servers by VitexSoftware
| Server | Description |
|---|---|
| abraflexi-mcp-server | AbraFlexi accounting/ERP integration — invoices, contacts, products, bank transactions |
| mastodon-mcp-server | Mastodon integration — timelines, posting, account management, search |
| semaphore-mcp-server | Semaphore UI integration — manage Ansible, Terraform and other automation workflows |
License
MIT
webdriver MCP questions
What tools does webdriver MCP provide?
It exposes 38 tools, including browser_open, browser_close, browser_status, browser_set_viewport, browser_navigate.
What is the primary tool for diagnosing web page errors?
The devtools_report tool is the main diagnostic tool, providing JavaScript errors, console output, and failed or slow network resources in a single call.