SeleniumBase MCP Servers
This package provides three different SeleniumBase MCP servers for driving stealthy browser automation over the Model Context Protocol.
Here are the three server variants in this folder:
| File | Backs onto | Best for |
|---|---|---|
cdp_server.py |
seleniumbase.sb_cdp.Chrome() (Pure CDP Mode, sync) |
Scraping/automation against bot-detection (Cloudflare, etc.) No WebDriver at all. Includes CAPTCHA-solving. |
driver_server.py |
seleniumbase.Driver() (WebDriver) |
General automation with Selenium ecosystem support. |
sb_server.py |
seleniumbase.SB() (used without with, via manual __enter__/__exit__) |
The broadest API surface: Everything Driver offers, plus drag-and-drop, MFA-handling, file downloads, etc. Can switch to CDP Mode mid-flow via activate_cdp_mode |
All three set headless=False by default, where the browser window is visible unless you pass headless=True when starting a session.
Point your MCP client config at whichever *_server.py fits the task (see step 3 below), or register all three under different names.
1. Install
(Requires Python 3.10+ and uv)
git clone https://github.com/seleniumbase/seleniumbase-mcp.git
cd seleniumbase-mcp
uv sync
uv sync reads pyproject.toml, creates a .venv/ in this folder, and installs the seleniumbase[mcp] dependency along with this project itself, which registers three console-script commands via [project.scripts]:
seleniumbase-cdpseleniumbase-driverseleniumbase-sb
Each just calls that server file's main() function (mcp.run(transport="stdio")). This is what lets uv run <name> work as the MCP client command in steps 3 and 4 below.
# SeleniumBase's Driver() and SB() formats need a browser driver downloaded:
uv run seleniumbase get chromedriver
# (Not needed for the "seleniumbase-cdp" Pure CDP Mode MCP Server,
# which doesn't use WebDriver at all.)
(No uv? A regular python3 -m venv venv && pip install -e . works too if you substitute python <script>.py for uv run <name> everywhere below, and use absolute venv/bin/python + script paths in your MCP client config instead of the path-free options.)
2. Try it standalone (optional sanity check)
uv run mcp dev cdp_server.py
That opens the MCP Inspector for SeleniumBase's "Pure CDP Mode" MCP Server, where you can test commands ("Tools"). Ctrl+C to exit. Next step is wiring it into a client.
3. Connect it to Claude Desktop
Claude Desktop doesn't run from a "project" directory the way Claude Code does, so a bare uv run <name> isn't guaranteed to find this repo. Two ways to get a stable config:
Option A — global install (recommended, zero paths anywhere):
uv tool install . # from inside the repo, installs the 3 commands globally
This puts seleniumbase-driver/seleniumbase-cdp/seleniumbase-sb on your PATH permanently (run uv tool ensurepath once if it warns that its bin directory isn't on PATH yet). Then claude_desktop_config.json can be just:
{
"mcpServers": {
"seleniumbase-cdp": { "command": "seleniumbase-cdp" },
"seleniumbase-driver": { "command": "seleniumbase-driver" },
"seleniumbase-sb": { "command": "seleniumbase-sb" }
}
}
Option B — point uv at the repo directly (one absolute path, but no venv/interpreter path to track down, and no separate install step):
{
"mcpServers": {
"seleniumbase-cdp": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/seleniumbase-mcp", "run", "seleniumbase-cdp"]
},
"seleniumbase-driver": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/seleniumbase-mcp", "run", "seleniumbase-driver"]
},
"seleniumbase-sb": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/seleniumbase-mcp", "run", "seleniumbase-sb"]
}
}
}
The location of claude_desktop_config.json depends on your system:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
Restart Claude Desktop. You should see a 🔨 tools icon indicating the server(s) connected, with tools like start_browser, navigate, click, etc. available. Only keep the entries you actually want. Three separate browser-automation servers is a lot if you only need one.
4. Connect it to Claude Code
This repo's .mcp.json is checked in and ready to use as-is.
No path editing is required because uv run <name> resolves this project from pyproject.toml in the current directory:
{
"mcpServers": {
"seleniumbase-cdp": {
"type": "stdio",
"command": "seleniumbase-cdp",
"args": []
},
"seleniumbase-driver": {
"type": "stdio",
"command": "seleniumbase-driver",
"args": []
},
"seleniumbase-sb": {
"type": "stdio",
"command": "seleniumbase-sb",
"args": []
}
}
}
Claude Code auto-loads .mcp.json from the directory you launch claude in, so as long as you run claude from inside this repo (or a clone of it), it just works.
If you'd rather register the servers manually instead of relying on .mcp.json:
claude mcp add seleniumbase-cdp -- uv run seleniumbase-cdp
claude mcp add seleniumbase-driver -- uv run seleniumbase-driver
claude mcp add seleniumbase-sb -- uv run seleniumbase-sb
(run from inside the repo directory, for the same reason as above.)
Tools exposed (driver_server.py)
| Tool | Purpose |
|---|---|
start_browser(browser, headless, uc, incognito) |
Launch a browser session (headless defaults to False) |
close_browser() |
End the session |
navigate(url) |
Go to a URL |
go_back() / go_forward() / refresh_page() |
History navigation |
get_current_url() / get_title() |
Page metadata |
get_page_source() |
Full HTML |
get_text(selector) |
Visible text of an element |
find_elements_count(selector) |
Count matches |
is_element_visible(selector) |
Visibility check |
click(selector, timeout) |
Click (CSS or XPath) |
type_text(selector, text, clear_first, timeout) |
Fill a field |
select_option_by_text(dropdown_selector, option) |
Choose a dropdown option |
wait_for_element_present(selector, timeout) |
Explicit wait |
switch_to_frame(selector) / switch_to_default_content() |
iframe handling |
assert_text(text, selector) |
Verify text is present |
screenshot(filename) |
Save a screenshot |
execute_script(script) |
Run a JS script |
Design notes / things to adapt for your use case
- Single global session. Each server holds one browser session at a
time. This matches how MCP servers are typically launched (one process
per client connection) and keeps the tool surface simple. If you need
multiple concurrent browser tabs/sessions, you'd extend this to a
dict of named sessions and add a
session_idparameter to each tool. - Blocking calls. SeleniumBase's calls are synchronous and will block
the server while a page loads or an element is waited on. For a
single-user local tool this is fine; for a multi-client server you'd
want to run them in a thread pool via
asyncio.to_thread. - Headless vs Headed. Default is headed (
headless=False) so you can watch the browser work and so sites that block headless Chrome still function. Passheadless=Truefor background/server use once you've confirmed a flow works.sb_server.py'suc=True(undetected- chromedriver) also helps against bot-detection walls.
Extending
Adding a tool is just adding a @mcp.tool()-decorated function that calls
the matching SeleniumBase method — SeleniumBase has methods for file
uploads, hovering, alerts, network conditions, and more that aren't wrapped
above yet.
cdp_server.py — Pure CDP Mode
Wraps seleniumbase.sb_cdp.Chrome, SeleniumBase's stealthiest mode: the
browser is driven entirely over the Chrome DevTools Protocol, no WebDriver
in the loop at all. Reference:
cdp_mode_methods.md.
Tool groups
| Group | Tool(s) |
|---|---|
| Session | start_browser(url, headless, use_chromium, browser_executable_path, incognito, guest, ad_block, proxy), close_browser |
| Navigation | navigate, navigate_history(action: back/forward/reload), get_page_info (running status, url, title, origin, user agent, history in one call) |
| Finding & reading | find_elements(selector, timeout, include_html), get_content(selector, output_format: text/html/urls, include_shadow_dom), get_attributes, check_state(check: present/visible/count/text_visible) |
| Interacting | click(selector, nth, all_matches, only_if_visible, parent_selector, timeout, scroll), hover_with_action(selector1, selector2, action: none/click/drag_and_drop), type_text(mode: fill_input/append/fast_type/set_value/clear_only), select_option(by: text/value/index), focus_on(action: scroll_to_element/focus/highlight) |
| Waiting | wait_for(state: present/visible/not_visible/absent, text) |
| Assertions | assert_condition(check: element_present/element_visible/text_visible/title/url/url_contains) |
| Cookies & storage | manage_cookies(action: get_all/clear/save/load), manage_storage(storage: local/session, action: get/set) |
| Scrolling | scroll(direction: up/down/top/bottom, amount) |
| Windows & tabs | manage_window(action: get_rect/set_rect/maximize/minimize), manage_tabs(action: list/open/switch/switch_newest/close_active) |
| Captcha | solve_captcha |
| Output & misc | save_output(format: screenshot/html/pdf), run_javascript, wait_seconds |
CDP-specific design notes
- Elements don't cross the wire as handles. In native CDP Mode,
find_element()returns a live object with its own methods (el.click(),el.get_html(), ...). MCP tools can only return JSON-serializable data, sofind_element_info/find_all_inforesolve the element immediately to a plain dict (tag_name,text,html) instead of returning a handle you could call further methods on. If you need to act on one of several matches, useclick_nth_element(acts by position) rather than "find, then click" as two separate steps. - Captcha solving isn't universal.
solve_captchahandles supported challenge types (e.g. Cloudflare Turnstile in the SeleniumBase demo app); it isn't a guaranteed bypass for arbitrary CAPTCHAs. - Session teardown.
sb.quit()(used byclose_browser) is the documented way to end a session; the browser also auto-closes if the process exits without it. - Not wrapped: PyAutoGUI-based
gui_*methods (excluded by design — see the top-level design notes), low-level plumbing (get_websocket_url,add_handler, permission grants, rawget_document/get_flattened_document), and exact method aliases (open/gotovsget) were left out to keep the tool list focused — add them the same way as any other tool if you need them.
sb_server.py — SB() without the with statement
Wraps seleniumbase.SB(), normally used as a context manager:
with SB(uc=True) as sb:
sb.goto(...)
An MCP server's tool calls happen one at a time across separate function
invocations — there's no single indented block to put with around — so
this server calls the context manager protocol manually instead:
sb_context = SB(**kwargs)
sb = sb_context.__enter__() # in start_browser
...
sb_context.__exit__(None, None, None) # in close_browser
sb is a BaseCase instance, SeleniumBase's broadest API — a superset of
what Driver (in driver_server.py) exposes, plus UC Mode stealth helpers
and a few extras driver_server.py/cdp_server.py don't have. This server
focuses on those extras rather than re-wrapping everything already covered:
| Group | Tools |
|---|---|
| UC/CDP stealth | activate_cdp_mode (flips the same session into Pure CDP Mode mid-flow) |
| Extra interactions | hover_and_click, drag_and_drop, double_click, context_click, choose_file (upload) |
| MFA | get_mfa_code, enter_mfa_code (TOTP/Google-Authenticator-style codes from a secret key) |
| Files | download_file |
| Site health | assert_no_404_errors, assert_no_js_errors |
| Visual feedback | highlight, flash |
Plus the same core navigation/interaction/waiting/assertions/cookies/
scrolling/tabs/output tools as the other two servers, called through the
BaseCase method names (e.g. sb.goto, sb.click, sb.assert_element)
rather than Driver's or CDP's.
SB()-specific design notes
- UC Mode (stealth mode) requires
uc=Trueat startup. Pass it instart_browserup front if you'll need them. activate_cdp_modedoesn't start a new session. It switches the existingsbsession's underlying mode to Pure CDP for subsequent actions — it's a mid-flow escalation, not a fresh browser.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file seleniumbase_mcp-1.2.4.tar.gz.
File metadata
- Download URL: seleniumbase_mcp-1.2.4.tar.gz
- Upload date:
- Size: 39.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8f16c9952d3c6c1a231f672afd1a17c40ed9c3277959fba7ff484ad7ff17ef65
|
|
| MD5 |
c5324d97b0a30145a5512962f914421f
|
|
| BLAKE2b-256 |
e74a43a4d7acfdc4080f3183ea6d5c9bf2d5d807fd3ccda3e2ad0575e68d1180
|
File details
Details for the file seleniumbase_mcp-1.2.4-py3-none-any.whl.
File metadata
- Download URL: seleniumbase_mcp-1.2.4-py3-none-any.whl
- Upload date:
- Size: 34.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8df137d6bc5b5092ff1cc3001b4acba41beaeac7fda335f49741cbbbc270ca1d
|
|
| MD5 |
27ffb2364b98e2f9fc532c8bfe8d851c
|
|
| BLAKE2b-256 |
13bd3e535ffcd0a109edaaf5c0e9314c3add70423e04d3b4ed2019b803daf269
|