SeleniumBase MCP
Officialš Here's a Python example that uses Pure CDP Mode (sb_cdp):(It navigates to Browserscan where it bypasses bot-detection.)
from seleniumbase import sb_cdp
sb = sb_cdp.Chrome()
sb.goto("https://browserscan.net/bot-detection")
sb.sleep(3)
sb.quit()š Here's an example script that uses Stealthy Playwright Mode:(Playwright connects to a stealthy SeleniumBase browser session.)
from playwright.sync_api import sync_playwright
from seleniumbase import sb_cdp
sb = sb_cdp.Chrome(guest=True)
endpoint_url = sb.get_endpoint_url()
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(endpoint_url)
page = browser.contexts[0].pages[0]
page.goto("https://bot.sannysoft.com/")
page.wait_for_timeout(500)from seleniumbase import sb_cdp
sb = sb_cdp.Chrome()
sb.goto("https://seleniumbase.io/demo_page")
sb.type("input", "Quickly type text!")
sb.press_keys("textarea", "Slowly type text!")
sb.click("#myButton")
sb.set_value("input#mySlider", "100")
sb.click_visible_elements("input.checkBoxClassB")
sb.select_option_by_text("#mySelect", "Set to 75%")
sb.hover_and_click("#myDropdown", "#dropOption2")
sb.click("#checkBox1")
sb.drag_and_drop("img#logo", "div#drop2")
sb.nested_click("iframe#myFrame3", ".fBox")
sb.highlight("#myButton")
sb.quit()from seleniumbase import sb_cdp
sb = sb_cdp.Chrome(locale="en", ad_block=True)
sb.goto("https://browserscan.net/bot-detection")
sb.flash("Test Results", duration=1.5, pause=0.5)
sb.assert_element('strong:contains("Normal")')
print("Bot Not Detected")
sb.flash('strong:contains("Normal")', pause=1)
sb.quit()from seleniumbase import sb_cdp
sb = sb_cdp.Chrome()
sb.goto("https://news.ycombinator.com/submitted?id=seleniumbase")
elements = sb.find_elements("span.titleline > a")
for element in elements:
print("* " + element.text)š Stealthy CDP Mode examples are located in ./examples/cdp_mode/.
š Stealthy Playwright examples are located in ./examples/cdp_mode/playwright/.
python SCRIPT.py --chromium # Use the unbranded Chromium browser
python SCRIPT.py --cft # Use Chrome-for-testing
python SCRIPT.py --edge # Use Microsoft Edge
python SCRIPT.py --brave # Use Brave browserGoogle Chrome is the default browser. Only unbranded Chromium and Chrome-for-Testing get downloaded automatically if not already present on the system.
The Chromium browser can also be set via method args, eg: cft=True, use_chromium=True, browser="edge", browser="brave", etc. Eg:
sb = sb_cdp.Chrome(use_chromium=True)from seleniumbase import SB
with SB(uc=True, test=True) as sb:
url = "https://google.com/ncr"
sb.activate_cdp_mode(url)
sb.click_if_visible('button:contains("Accept all")')
sb.type('[name="q"]', "SeleniumBase GitHub page")
sb.click('[value="Google Search"]')
sb.sleep(4) # The "AI Overview" sometimes loads
print(sb.get_page_title())
sb.save_as_pdf_to_logs()
sb.save_page_source_to_logs()
sb.save_screenshot_to_logs()
print("Logs have been saved to: ./latest_logs/")from seleniumbase import SB
with SB(uc=True, test=True, locale="en") as sb:
url = "https://gitlab.com/users/sign_in"
sb.activate_cdp_mode(url)
sb.sleep(2)
sb.solve_captcha()
# (The rest is for testing and demo purposes)
sb.assert_text("Username", '[for="user_login"]', timeout=3)
sb.assert_element('label[for="user_login"]')
sb.highlight('button:contains("Sign in")')
sb.highlight('h1:contains("GitLab")')
sb.post_message("SeleniumBase wasn't detected", duration=4)š” sb.solve_captcha() handles CAPTCHAs that aren't bypassed automatically.(If no CAPTCHA is present on the current page, then nothing happens.)
from seleniumbase import sb_cdp
sb = sb_cdp.Chrome(incognito=True)
sb.goto("https://gitlab.com/users/sign_in")
sb.sleep(2)
sb.solve_captcha()
sb.highlight('h1:contains("GitLab")')
sb.highlight('button:contains("Sign in")')
sb.quit()š The SeleniumBase/examples/ folder includes over 150 ready-to-run examples of E2E testing. Examples that start with test_ or end with _test.py/_tests.py run with pytest. Other examples run directly with raw python (those generally start with raw_ to avoid confusion).
from seleniumbase import BaseCase
BaseCase.main(__name__, __file__) # Call pytest
class MyTestClass(BaseCase):
def test_swag_labs(self):
self.goto("https://www.saucedemo.com")
self.type("#user-name", "standard_user")
self.type("#password", "secret_sauce\n")
self.assert_element("div.inventory_list")
self.click('button[name*="backpack"]')
self.click("#shopping_cart_container a")
self.assert_text("Backpack", "div.cart_item")
self.click("button#checkout")
self.type("input#first-name", "SeleniumBase")
self.type("input#last-name", "Automation")
self.type("input#postal-code", "77123")
self.click("input#continue")
self.click("button#finish")
self.assert_text("Thank you for your order!")
pytest test_get_swag.py
pytest test_coffee_cart.py --demopytest test_demo_site.pyEasy to type, click, select, toggle, drag & drop, and more.
(For more examples, see the SeleniumBase/examples/ folder.)
from seleniumbase import BaseCase
BaseCase.main(__name__, __file__)
class TestSimpleLogin(BaseCase):
def test_simple_login(self):
self.goto("seleniumbase.io/simple/login")
self.type("#username", "demo_user")
self.type("#password", "secret_pass")
self.click('a:contains("Sign in")')
self.assert_exact_text("Welcome!", "h1")
self.assert_element("img#image1")
self.highlight("#image1")
self.click_link("Sign out")
self.assert_text("signed out", "#top_message")from seleniumbase import SB
with SB() as sb:
sb.goto("seleniumbase.io/simple/login")
sb.type("#username", "demo_user")
sb.type("#password", "secret_pass")
sb.click('a:contains("Sign in")')
sb.assert_exact_text("Welcome!", "h1")
sb.assert_element("img#image1")
sb.highlight("#image1")
sb.click_link("Sign out")
sb.assert_text("signed out", "#top_message")from seleniumbase import Driver
driver = Driver()
try:
driver.goto("seleniumbase.io/simple/login")
driver.type("#username", "demo_user")
driver.type("#password", "secret_pass")
driver.click('a:contains("Sign in")')
driver.assert_exact_text("Welcome!", "h1")
driver.assert_element("img#image1")
driver.highlight("#image1")
driver.click_link("Sign out")
driver.assert_text("signed out", "#top_message")
finally:
driver.quit()šµ Add Python and Git to your System PATH.
šµ Using a Python virtual env is recommended.
šµ How to install seleniumbase from PyPI using pip:
pip install seleniumbase(Add
--upgradeOR-Uto upgrade SeleniumBase.)(Add
--force-reinstallto upgrade indirect packages.)
šµ How to install seleniumbase from a GitHub clone:
git clone https://github.com/seleniumbase/SeleniumBase.git
cd SeleniumBase/
pip install -e .šµ How to upgrade an existing install from a GitHub clone:
git pull
pip install -e .šµ Type seleniumbase or sbase to verify that SeleniumBase was installed successfully:
___ _ _ ___
/ __| ___| |___ _ _ (_)_ _ _ __ | _ ) __ _ ______
\__ \/ -_) / -_) ' \| | \| | ' \ | _ \/ _` (_-< -_)
|___/\___|_\___|_||_|_|\_,_|_|_|_\|___/\__,_/__|___|
----------------------------------------------------
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā®
ā * USAGE: "seleniumbase [COMMAND] [PARAMETERS]" ā
ā * OR: "sbase [COMMAND] [PARAMETERS]" ā
ā ā
ā COMMANDS: PARAMETERS / DESCRIPTIONS: ā
ā get / install [DRIVER_NAME] [OPTIONS] ā
ā methods (List common Python methods) ā
ā options (List common pytest options) ā
ā behave-options (List common behave options) ā
ā gui / commander [OPTIONAL PATH or TEST FILE] ā
ā behave-gui (SBase Commander for Behave) ā
ā caseplans [OPTIONAL PATH or TEST FILE] ā
ā mkdir [DIRECTORY] [OPTIONS] ā
ā mkfile [FILE.py] [OPTIONS] ā
ā mkrec / codegen [FILE.py] [OPTIONS] ā
ā recorder (Open Recorder Desktop App.) ā
ā record (If args: mkrec. Else: App.) ā
ā mkpres [FILE.py] [LANG] ā
ā mkchart [FILE.py] [LANG] ā
ā print [FILE] [OPTIONS] ā
ā translate [SB_FILE.py] [LANG] [ACTION] ā
ā convert [WEBDRIVER_UNITTEST_FILE.py] ā
ā extract-objects [SB_FILE.py] ā
ā inject-objects [SB_FILE.py] [OPTIONS] ā
ā objectify [SB_FILE.py] [OPTIONS] ā
ā revert-objects [SB_FILE.py] [OPTIONS] ā
ā encrypt / obfuscate ā
ā decrypt / unobfuscate ā
ā proxy (Start a basic proxy server) ā
ā download server (Get Selenium Grid JAR file) ā
ā grid-hub [start|stop] [OPTIONS] ā
ā grid-node [start|stop] --hub=[HOST/IP] ā
ā ā
ā * EXAMPLE => "sbase get chromedriver stable" ā
ā * For command info => "sbase help [COMMAND]" ā
ā * For info on all commands => "sbase --help" ā
ā°āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāÆā
SeleniumBase automatically downloads webdrivers as needed, such as chromedriver.
*** chromedriver to download = 149.0.7827.54 (Latest Stable)
Downloading chromedriver-mac-arm64.zip from:
https://storage.googleapis.com/chrome-for-testing-public/149.0.7827.54/mac-arm64/chromedriver-mac-arm64.zip ...
Download Complete!
Extracting ['chromedriver'] from chromedriver-mac-arm64.zip ...
Unzip Complete!
The file [chromedriver] was saved to:
~/github/SeleniumBase/seleniumbase/drivers/
chromedriver
Making [chromedriver 149.0.7827.54] executable ...
[chromedriver 149.0.7827.54] is now ready for use!šµ If you've cloned SeleniumBase, you can run tests from the examples/ folder.
cd examples/
pytest my_first_test.pyfrom seleniumbase import BaseCase
BaseCase.main(__name__, __file__)
class MyTestClass(BaseCase):
def test_swag_labs(self):
self.goto("https://www.saucedemo.com")
self.type("#user-name", "standard_user")
self.type("#password", "secret_sauce\n")
self.assert_element("div.inventory_list")
self.assert_exact_text("Products", "span.title")
self.click('button[name*="backpack"]')
self.click("#shopping_cart_container a")
self.assert_exact_text("Your Cart", "span.title")
self.assert_text("Backpack", "div.cart_item")
self.click("button#checkout")
self.type("#first-name", "SeleniumBase")
self.type("#last-name", "Automation")
self.type("#postal-code", "77123")
self.click("input#continue")
self.assert_text("Checkout: Overview")
self.assert_text("Backpack", "div.cart_item")
self.assert_text("29.99", "div.inventory_item_price")
self.click("button#finish")
self.assert_exact_text("Thank you for your order!", "h2")
self.assert_element('img[alt="Pony Express"]')
self.js_click("a#logout_sidebar_link")
self.assert_element("div#login_button_container")By default, CSS Selectors are used for finding page elements.
If you're new to CSS Selectors, games like CSS Diner can help you learn.
For more reading, here's an advanced guide on CSS attribute selectors.
self.goto(url) # Navigate the browser window to the URL.
self.open(url) # Same as `self.goto(url)`
self.activate_cdp_mode() # Activate CDP Mode from UC Mode.
self.type(selector, text) # Update the field with the text.
self.click(selector) # Click the element with the selector.
self.click_link(link_text) # Click the link containing text.
self.go_back() # Navigate back to the previous URL.
self.select_option_by_text(dropdown_selector, option)
self.hover_and_click(hover_selector, click_selector)
self.drag_and_drop(drag_selector, drop_selector)
self.get_text(selector) # Get the text from the element.
self.get_current_url() # Get the URL of the current page.
self.get_page_source() # Get the HTML of the current page.
self.get_attribute(selector, attribute) # Get element attribute.
self.get_title() # Get the title of the current page.
self.switch_to_frame(frame) # Switch into the iframe container.
self.switch_to_default_content() # Leave the iframe container.
self.open_new_window() # Open a new window in the same browser.
self.switch_to_window(window) # Switch to the browser window.
self.switch_to_default_window() # Switch to the original window.
self.get_new_driver(OPTIONS) # Open a new driver with OPTIONS.
self.switch_to_driver(driver) # Switch to the browser driver.
self.switch_to_default_driver() # Switch to the original driver.
self.wait_for_element(selector) # Wait until element is visible.
self.is_element_visible(selector) # Return element visibility.
self.is_text_visible(text, selector) # Return text visibility.
self.sleep(seconds) # Do nothing for the given amount of time.
self.save_screenshot(name) # Save a screenshot in .png format.
self.assert_element(selector) # Verify the element is visible.
self.assert_text(text, selector) # Verify text in the element.
self.assert_exact_text(text, selector) # Verify text is exact.
self.assert_title(title) # Verify the title of the web page.
self.assert_downloaded_file(file) # Verify file was downloaded.
self.assert_no_404_errors() # Verify there are no broken links.
self.assert_no_js_errors() # Verify there are no JS errors.šµ For the complete list of SeleniumBase methods, see: Method Summary
self.type("input", "dogs\n") # (The "\n" presses ENTER)Most SeleniumBase scripts can be run with pytest, pynose, or pure python. Not all test runners can run all test formats. For example, tests that use the sb pytest fixture can only be run with pytest. (See Syntax Formats) There's also a Gherkin test format that runs with behave.
pytest coffee_cart_tests.py --rs
pytest test_sb_fixture.py --demo
pytest test_suite.py --rs --html=report.html --dashboard
pynose basic_test.py --mobile
pynose test_suite.py --headless --report --show-report
python raw_sb.py
python raw_test_scripts.py
behave realworld.feature
behave calculator.feature -D rs -D dashboardPython files that start with
test_or end with_test.py.Python methods that start with
test_.
With a SeleniumBase pytest.ini file present, you can modify default discovery settings. The Python class name can be anything because seleniumbase.BaseCase inherits unittest.TestCase to trigger autodiscovery.
pytest --co -qpytest [FILE_NAME.py]::[CLASS_NAME]::[METHOD_NAME]
pynose [FILE_NAME.py]:[CLASS_NAME].[METHOD_NAME]ā SeleniumBase supports all major browsers and operating systems:
ā SeleniumBase works on all popular CI/CD platforms:
šµ Demo Mode helps you see what a test is doing. If a test is moving too fast for your eyes, run it in Demo Mode to pause the browser briefly between actions, highlight page elements being acted on, and display assertions:
pytest my_first_test.py --demošµ time.sleep(seconds) can be used to make a test wait at a specific spot:
import time; time.sleep(3) # Do nothing for 3 seconds.šµ Debug Mode with Python's built-in pdb library helps you debug tests:
breakpoint() # Shortcut for "import pdb; pdb.set_trace()"(
pdbcommands:n,c,s,u,d=>next,continue,step,up,down)
šµ To pause an active test that throws an exception or error, (and keep the browser window open while Debug Mode begins in the console), add --pdb as a pytest option:
pytest test_fail.py --pdbšµ To start tests in Debug Mode, add --trace as a pytest option:
pytest test_coffee_cart.py --traceā Here are some useful command-line options that come with pytest:
-v # Verbose mode. Prints the full name of each test and shows more details.
-q # Quiet mode. Print fewer details in the console output when running tests.
-x # Stop running the tests after the first failure is reached.
--html=report.html # Creates a detailed pytest-html report after tests finish.
--co | --collect-only # Show what tests would get run. (Without running them)
--co -q # (Both options together!) - Do a dry run with full test names shown.
-n=NUM # Multithread the tests using that many threads. (Speed up test runs!)
-s # See print statements. (Should be on by default with pytest.ini present.)
--junit-xml=report.xml # Creates a junit-xml report after tests finish.
--pdb # If a test fails, enter Post Mortem Debug Mode. (Don't use with CI!)
--trace # Enter Debug Mode at the beginning of each test. (Don't use with CI!)
-m=MARKER # Run tests with the specified pytest marker.ā SeleniumBase provides additional pytest command-line options for tests:
--browser=BROWSER # (The web browser to use. Default: "chrome".)
--chrome # (Shortcut for "--browser=chrome". On by default.)
--edge # (Shortcut for "--browser=edge".)
--firefox # (Shortcut for "--browser=firefox".)
--safari # (Shortcut for "--browser=safari".)
--opera # (Shortcut for "--browser=opera".)
--brave # (Shortcut for "--browser=brave".)
--comet # (Shortcut for "--browser=comet".)
--chromium # (Shortcut for using base `Chromium`)
--settings-file=FILE # (Override default SeleniumBase settings.)
--env=ENV # (Set the test env. Access with "self.env" in tests.)
--account=STR # (Set account. Access with "self.account" in tests.)
--data=STRING # (Extra test data. Access with "self.data" in tests.)
--var1=STRING # (Extra test data. Access with "self.var1" in tests.)
--var2=STRING # (Extra test data. Access with "self.var2" in tests.)
--var3=STRING # (Extra test data. Access with "self.var3" in tests.)
--variables=DICT # (Extra test data. Access with "self.variables".)
--user-data-dir=DIR # (Set the Chrome user data directory to use.)
--protocol=PROTOCOL # (The Selenium Grid protocol: http|https.)
--server=SERVER # (The Selenium Grid server/IP used for tests.)
--port=PORT # (The Selenium Grid port used by the test server.)
--cap-file=FILE # (The web browser's desired capabilities to use.)
--cap-string=STRING # (The web browser's desired capabilities to use.)
--proxy=SERVER:PORT # (Connect to a proxy server:port as tests are running)
--proxy=USERNAME:PASSWORD@SERVER:PORT # (Use an authenticated proxy server)
--proxy-bypass-list=STRING # (";"-separated hosts to bypass, Eg "*.foo.com")
--proxy-pac-url=URL # (Connect to a proxy server using a PAC_URL.pac file.)
--proxy-pac-url=USERNAME:PASSWORD@URL # (Authenticated proxy with PAC URL.)
--proxy-driver # (If a driver download is needed, will use: --proxy=PROXY.)
--multi-proxy # (Allow multiple authenticated proxies when multi-threaded.)
--agent=STRING # (Modify the web browser's User-Agent string.)
--mobile # (Use the mobile device emulator while running tests.)
--metrics=STRING # (Set mobile metrics: "CSSWidth,CSSHeight,PixelRatio".)
--chromium-arg="ARG=N,ARG2" # (Set Chromium args, ","-separated, no spaces.)
--firefox-arg="ARG=N,ARG2" # (Set Firefox args, comma-separated, no spaces.)
--firefox-pref=SET # (Set a Firefox preference:value set, comma-separated.)
--extension-zip=ZIP # (Load a Chrome Extension .zip|.crx, comma-separated.)
--extension-dir=DIR # (Load a Chrome Extension directory, comma-separated.)
--disable-features="F1,F2" # (Disable features, comma-separated, no spaces.)
--binary-location=PATH # (Set path of the Chromium browser binary to use.)
--driver-version=VER # (Set the chromedriver or uc_driver version to use.)
--sjw # (Skip JS Waits for readyState to be "complete" or Angular to load.)
--wfa # (Wait for AngularJS to be done loading after specific web actions.)
--pls=PLS # (Set pageLoadStrategy on Chrome: "normal", "eager", or "none".)
--headless # (The default headless mode. Linux uses this mode by default.)
--headless1 # (Use Chrome's old headless mode. Fast, but has limitations.)
--headless2 # (Use Chrome's new headless mode, which supports extensions.)
--headed # (Run tests in headed/GUI mode on Linux OS, where not default.)
--xvfb # (Run tests using the Xvfb virtual display server on Linux OS.)
--xvfb-metrics=STRING # (Set Xvfb display size on Linux: "Width,Height".)
--locale=LOCALE_CODE # (Set the Language Locale Code for the web browser.)
--interval=SECONDS # (The autoplay interval for presentations & tour steps)
--start-page=URL # (The starting URL for the web browser when tests begin.)
--archive-logs # (Archive existing log files instead of deleting them.)
--archive-downloads # (Archive old downloads instead of deleting them.)
--time-limit=SECONDS # (Safely fail any test that exceeds the time limit.)
--slow # (Slow down the automation. Faster than using Demo Mode.)
--demo # (Slow down and visually see test actions as they occur.)
--demo-sleep=SECONDS # (Set the wait time after Slow & Demo Mode actions.)
--highlights=NUM # (Number of highlight animations for Demo Mode actions.)
--message-duration=SECONDS # (The time length for Messenger alerts.)
--check-js # (Check for JavaScript errors after page loads.)
--ad-block # (Block some types of display ads from loading.)
--host-resolver-rules=RULES # (Set host-resolver-rules, comma-separated.)
--block-images # (Block images from loading during tests.)
--do-not-track # (Indicate to websites that you don't want to be tracked.)
--verify-delay=SECONDS # (The delay before MasterQA verification checks.)
--ee | --esc-end # (Lets the user end the current test via the ESC key.)
--recorder # (Enables the Recorder for turning browser actions into code.)
--rec-sb-mgr # (A Recorder Mode that generates SB() context manager code.)
--rec-sb-cdp # (A Recorder Mode that generates Pure CDP Mode sb_cdp code.)
--rec-behave # (Same as Recorder Mode, but also generates behave-gherkin.)
--rec-sleep # (If the Recorder is enabled, also records self.sleep calls.)
--rec-print # (If the Recorder is enabled, prints output after tests end.)
--disable-cookies # (Disable Cookies on websites. Pages might break!)
--disable-js # (Disable JavaScript on websites. Pages might break!)
--disable-csp # (Disable the Content Security Policy of websites.)
--disable-ws # (Disable Web Security on Chromium-based browsers.)
--enable-ws # (Enable Web Security on Chromium-based browsers.)
--enable-sync # (Enable "Chrome Sync" on websites.)
--uc | --undetected # (Use undetected-chromedriver to evade bot-detection.)
--uc-cdp-events # (Capture CDP events when running in "--undetected" mode.)
--log-cdp # ("goog:loggingPrefs", {"performance": "ALL", "browser": "ALL"})
--remote-debug # (Sync to Chrome Remote Debugger chrome://inspect/#devices)
--ftrace | --final-trace # (Debug Mode after each test. Don't use with CI!)
--dashboard # (Enable the SeleniumBase Dashboard. Saved at: dashboard.html)
--dash-title=STRING # (Set the title shown for the generated dashboard.)
--enable-3d-apis # (Enables WebGL and 3D APIs.)
--swiftshader # (Chrome "--use-gl=angle" / "--use-angle=swiftshader-webgl")
--incognito # (Enable Chrome's Incognito mode.)
--guest # (Enable Chrome's Guest mode.)
--dark # (Enable Chrome's Dark mode.)
--devtools # (Open Chrome's DevTools when the browser opens.)
--rs | --reuse-session # (Reuse browser session for all tests.)
--rcs | --reuse-class-session # (Reuse session for tests in class.)
--crumbs # (Delete all cookies between tests reusing a session.)
--disable-beforeunload # (Disable the "beforeunload" event on Chrome.)
--window-position=X,Y # (Set the browser's starting window position.)
--window-size=WIDTH,HEIGHT # (Set the browser's starting window size.)
--maximize # (Start tests with the browser window maximized.)
--screenshot # (Save a screenshot at the end of each test.)
--no-screenshot # (No screenshots saved unless tests directly ask it.)
--visual-baseline # (Set the visual baseline for Visual/Layout tests.)
--external-pdf # (Set Chromium "plugins.always_open_pdf_externally":True.)
--timeout-multiplier=MULTIPLIER # (Multiplies the default timeout values.)
--list-fail-page # (After each failing test, list the URL of the failure.)(See the full list of command-line option definitions here. For detailed examples of command-line options, see customizing_test_runs.md)
šµ During test failures, logs and screenshots from the most recent test run will get saved to the latest_logs/ folder. Those logs will get moved to archived_logs/ if you add --archive_logs to command-line options, or have ARCHIVE_EXISTING_LOGS set to True in settings.py, otherwise log files with be cleaned up at the start of the next test run. The test_suite.py collection contains tests that fail on purpose so that you can see how logging works.
cd examples/
pytest test_suite.py --chrome
pytest test_suite.py --firefoxAn easy way to override seleniumbase/config/settings.py is by using a custom settings file.
Here's the command-line option to add to tests: (See examples/custom_settings.py)
--settings_file=custom_settings.py
(Settings include default timeout values, a two-factor auth key, DB credentials, S3 credentials, and other important settings used by tests.)
šµ To pass additional data from the command-line to tests, add --data="ANY STRING".
Inside your tests, you can use self.data to access that.
šµ When running tests with pytest, you'll want a copy of pytest.ini in your root folders. When running tests with pynose, you'll want a copy of setup.cfg in your root folders. These files specify default configuration details for tests. Test folders should also include a blank init.py file to allow your test files to import other files from that folder.
šµ sbase mkdir DIR creates a folder with config files and sample tests:
sbase mkdir ui_testsThat new folder will have these files:
ui_tests/
āāā __init__.py
āāā my_first_test.py
āāā parameterized_test.py
āāā pytest.ini
āāā requirements.txt
āāā setup.cfg
āāā test_demo_site.py
āāā boilerplates/
āāā __init__.py
āāā base_test_case.py
āāā boilerplate_test.py
āāā classic_obj_test.py
āāā page_objects.py
āāā sb_fixture_test.py
āāā samples/
āāā __init__.py
āāā google_objects.py
āāā google_test.py
āāā sb_swag_test.py
āāā swag_labs_test.pyProTipā¢: You can also create a boilerplate folder without any sample tests in it by adding -b or --basic to the sbase mkdir command:
sbase mkdir ui_tests --basicThat new folder will have these files:
ui_tests/
āāā __init__.py
āāā pytest.ini
āāā requirements.txt
āāā setup.cfgOf those files, the pytest.ini config file is the most important, followed by a blank __init__.py file. There's also a setup.cfg file (for pynose). Finally, the requirements.txt file can be used to help you install seleniumbase into your environments (if it's not already installed).
ProTipā¢: Add --gha to include a GitHub Actions .yml file with default settings:
ui_tests/
āāā .github
āāā workflows/
āāā python-package.ymlLet's try an example of a test that fails:
""" test_fail.py """
from seleniumbase import BaseCase
BaseCase.main(__name__, __file__)
class MyTestClass(BaseCase):
def test_find_army_of_robots_on_xkcd_desert_island(self):
self.goto("https://xkcd.com/731/")
self.assert_element("div#ARMY_OF_ROBOTS", timeout=1) # This should failYou can run it from the examples/ folder like this:
pytest test_fail.pyšµ You'll notice that a logs folder, ./latest_logs/, was created to hold information (and screenshots) about the failing test. During test runs, past results get moved to the archived_logs folder if you have ARCHIVE_EXISTING_LOGS set to True in settings.py, or if your run tests with --archive-logs. If you choose not to archive existing logs, they will be deleted and replaced by the logs of the latest test run.
šµ The --dashboard option for pytest generates a SeleniumBase Dashboard located at dashboard.html, which updates automatically as tests run and produce results. Example:
pytest --dashboard --rs --headlessšµ Additionally, you can host your own SeleniumBase Dashboard Server on a port of your choice. Here's an example of that using Python's http.server:
python -m http.server 1948šµ Now you can navigate to http://localhost:1948/dashboard.html in order to view the dashboard as a web app. This requires two different terminal windows: one for running the server, and another for running the tests, which should be run from the same directory. (Use Ctrl+C to stop the http server.)
šµ Here's a full example of what the SeleniumBase Dashboard may look like:
pytest test_suite.py test_image_saving.py --dashboard --rs --headlessā
Using --html=report.html gives you a fancy report of the name specified after your test suite completes.
pytest test_suite.py --html=report.htmlā
When combining pytest html reports with SeleniumBase Dashboard usage, the pie chart from the Dashboard will get added to the html report. Additionally, if you set the html report URL to be the same as the Dashboard URL when also using the dashboard, (example: --dashboard --html=dashboard.html), then the Dashboard will become an advanced html report when all the tests complete.
ā Here's an example of an upgraded html report:
pytest test_suite.py --dashboard --html=report.htmlIf viewing pytest html reports in Jenkins, you may need to configure Jenkins settings for the html to render correctly. This is due to Jenkins CSP changes.
You can also use --junit-xml=report.xml to get an xml report instead. Jenkins can use this file to display better reporting for your tests.
pytest test_suite.py --junit-xml=report.xmlThe --report option gives you a fancy report after your test suite completes.
pynose test_suite.py --report(NOTE: You can add --show-report to immediately display pynose reports after the test suite completes. Only use --show-report when running tests locally because it pauses the test run.)
(The behave_bdd/ folder can be found in the examples/ folder.)
behave behave_bdd/features/ -D dashboard -D headlessYou can also use --junit to get .xml reports for each behave feature. Jenkins can use these files to display better reporting for your tests.
behave behave_bdd/features/ --junit -D rs -D headlessSee: https://allurereport.org/docs/pytest/
SeleniumBase no longer includes allure-pytest as part of installed dependencies. If you want to use it, install it first:
pip install allure-pytestNow your tests can create Allure results files, which can be processed by Allure Reports.
pytest test_suite.py --alluredir=allure_resultsIf you wish to use a proxy server for your browser tests (Chromium or Firefox), you can add --proxy=IP_ADDRESS:PORT as an argument on the command line.
pytest proxy_test.py --proxy=IP_ADDRESS:PORTIf the proxy server that you wish to use requires authentication, you can do the following (Chromium only):
pytest proxy_test.py --proxy=USERNAME:PASSWORD@IP_ADDRESS:PORTSeleniumBase also supports SOCKS4 and SOCKS5 proxies:
pytest proxy_test.py --proxy="socks4://IP_ADDRESS:PORT"
pytest proxy_test.py --proxy="socks5://IP_ADDRESS:PORT"To make things easier, you can add your frequently-used proxies to PROXY_LIST in proxy_list.py, and then use --proxy=KEY_FROM_PROXY_LIST to use the IP_ADDRESS:PORT of that key.
pytest proxy_test.py --proxy=proxy1šµ If you wish to change the User-Agent for your browser tests (Chromium and Firefox only), you can add --agent="USER AGENT STRING" as an argument on the command-line.
pytest user_agent_test.py --agent="Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1.7412.EU"šµ self.accept_alert() automatically waits for and accepts alert pop-ups. self.dismiss_alert() automatically waits for and dismisses alert pop-ups. On occasion, some methods like self.click(SELECTOR) might dismiss a pop-up on its own because they call JavaScript to make sure that the readyState of the page is complete before advancing. If you're trying to accept a pop-up that got dismissed this way, use this workaround: Call self.find_element(SELECTOR).click() instead, (which will let the pop-up remain on the screen), and then use self.accept_alert() to accept the pop-up (more on that here). If pop-ups are intermittent, wrap code in a try/except block.
šµ Learn about SeleniumBase Interactive Walkthroughs (in the examples/tour_examples/ folder). It's great for prototyping a website onboarding experience.
Here's an example of running tests with some additional features enabled:
pytest [YOUR_TEST_FILE.py] --with-db-reporting --with-s3-loggingšµ Navigating to a web page: (and related commands)
self.goto("https://xkcd.com/378/") # This method opens the specified page.
self.go_back() # This method navigates the browser to the previous page.
self.go_forward() # This method navigates the browser forward in history.
self.refresh_page() # This method reloads the current page.
self.get_current_url() # This method returns the current page URL.
self.get_page_source() # This method returns the current page source.ProTipā¢: You can use the self.get_page_source() method with Python's find() command to parse through HTML to find something specific. (For more advanced parsing, see the BeautifulSoup example.)
source = self.get_page_source()
head_open_tag = source.find('<head>')
head_close_tag = source.find('</head>', head_open_tag)
everything_inside_head = source[head_open_tag+len('<head>'):head_close_tag]šµ Clicking:
To click an element on the page:
self.click("div#my_id")ProTipā¢: In most web browsers, you can right-click on a page and select Inspect Element to see the CSS selector details that you'll need to create your own scripts.
šµ Typing Text:
self.type(selector, text) # updates the text from the specified element with the specified value. An exception is raised if the element is missing or if the text field is not editable. Example:
self.type("input#id_value", "2012")You can also use self.add_text() or the WebDriver .send_keys() command, but those won't clear the text box first if there's already text inside.
šµ Getting the text from an element on a page:
text = self.get_text("header h2")šµ Getting the attribute value from an element on a page:
attribute = self.get_attribute("#comic img", "title")šµ Asserting existence of an element on a page within some number of seconds:
self.wait_for_element_present("div.my_class", timeout=10)(NOTE: You can also use: self.assert_element_present(ELEMENT))
šµ Asserting visibility of an element on a page within some number of seconds:
self.wait_for_element_visible("a.my_class", timeout=5)(NOTE: The short versions of that are self.find_element(ELEMENT) and self.assert_element(ELEMENT). The find_element() version returns the element.)
Since the line above returns the element, you can combine that with .click() as shown below:
self.find_element("a.my_class", timeout=5).click()
# But you're better off using the following statement, which does the same thing:
self.click("a.my_class") # DO IT THIS WAY!ProTipā¢: You can use dots to signify class names (Ex: div.class_name) as a simplified version of div[class="class_name"] within a CSS selector.
You can also use *= to search for any partial value in a CSS selector as shown below:
self.click('a[name*="partial_name"]')šµ Asserting visibility of text inside an element on a page within some number of seconds:
self.assert_text("Make it so!", "div#trek div.picard div.quotes")
self.assert_text("Tea. Earl Grey. Hot.", "div#trek div.picard div.quotes", timeout=3)(NOTE: self.find_text(TEXT, ELEMENT) and self.wait_for_text(TEXT, ELEMENT) also do this. For backwards compatibility, older method names were kept, but the default timeout may be different.)
šµ Asserting Anything:
self.assert_true(var1 == var2)
self.assert_false(var1 == var2)
self.assert_equal(var1, var2)šµ Useful Conditional Statements: (with creative examples)
ā is_element_visible(selector): (visible on the page)
if self.is_element_visible('div#warning'):
print("Red Alert: Something bad might be happening!")ā is_element_present(selector): (present in the HTML)
if self.is_element_present('div#top_secret img.tracking_cookie'):
self.contact_cookie_monster() # Not a real SeleniumBase method
else:
current_url = self.get_current_url()
self.contact_the_nsa(url=current_url, message="Dark Zone Found") # Not a real SeleniumBase methoddef is_there_a_cloaked_klingon_ship_on_this_page():
if self.is_element_present("div.ships div.klingon"):
return not self.is_element_visible("div.ships div.klingon")
return Falseā is_text_visible(text, selector): (text visible on element)
if self.is_text_visible("You Shall Not Pass!", "h1"):
self.goto("https://www.youtube.com/watch?v=3xYXUeSmb-Y")def get_mirror_universe_captain_picard_superbowl_ad(superbowl_year):
selector = "div.superbowl_%s div.commercials div.transcript div.picard" % superbowl_year
if self.is_text_visible("Yes, it was I who summoned you all here.", selector):
return "Picard Paramount+ Superbowl Ad 2020"
elif self.is_text_visible("Commander, signal the following: Our Network is Secure!"):
return "Picard Mirror Universe iboss Superbowl Ad 2018"
elif self.is_text_visible("For the Love of Marketing and Earl Grey Tea!", selector):
return "Picard Mirror Universe HubSpot Superbowl Ad 2015"
elif self.is_text_visible("Delivery Drones... Engage", selector):
return "Picard Mirror Universe Amazon Superbowl Ad 2015"
elif self.is_text_visible("Bing it on Screen!", selector):
return "Picard Mirror Universe Microsoft Superbowl Ad 2015"
elif self.is_text_visible("OK Glass, Make it So!", selector):
return "Picard Mirror Universe Google Superbowl Ad 2015"
elif self.is_text_visible("Number One, I've Never Seen Anything Like It.", selector):
return "Picard Mirror Universe Tesla Superbowl Ad 2015"
elif self.is_text_visible("Let us make sure history never forgets the name ... Facebook", selector):
return "Picard Mirror Universe Facebook Superbowl Ad 2015"
elif self.is_text_visible("""With the first link, the chain is forged.
The first speech censored, the first thought forbidden,
the first freedom denied, chains us all irrevocably.""", selector):
return "Picard Mirror Universe Wikimedia Superbowl Ad 2015"
else:
raise Exception("Reports of my assimilation are greatly exaggerated.")ā is_link_text_visible(link_text):
if self.is_link_text_visible("Stop! Hammer time!"):
self.click_link("Stop! Hammer time!")self.switch_to_window(1) # This switches to the new tab (0 is the first one)šµ iframes follow the same principle as new windows: You must first switch to the iframe if you want to perform actions in there:
self.switch_to_frame("iframe")
# ... Now perform actions inside the iframe
self.switch_to_parent_frame() # Exit the current iframeTo exit from multiple iframes, use self.switch_to_default_content(). (If inside a single iframe, this has the same effect as self.switch_to_parent_frame().)
self.switch_to_frame('iframe[name="frame1"]')
self.switch_to_frame('iframe[name="frame2"]')
# ... Now perform actions inside the inner iframe
self.switch_to_default_content() # Back to the main pagešµ You can also use a context manager to act inside iframes:
with self.frame_switch("iframe"):
# ... Now perform actions while inside the code block
# You have left the iframeThis also works with nested iframes:
with self.frame_switch('iframe[name="frame1"]'):
with self.frame_switch('iframe[name="frame2"]'):
# ... Now perform actions while inside the code block
# You are now back inside the first iframe
# You have left all the iframes<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>šµ It's OK if you want to use jQuery on a page that doesn't have it loaded yet. To do so, run the following command first:
self.activate_jquery()self.execute_script("jQuery, window.scrollTo(0, 600)") # Scrolling the page
self.execute_script("jQuery('#annoying-widget').hide()") # Hiding elements on a page
self.execute_script("jQuery('#hidden-widget').show(0)") # Showing hidden elements on a page
self.execute_script("jQuery('#annoying-button a').remove()") # Removing elements on a page
self.execute_script("jQuery('%s').mouseover()" % (mouse_over_item)) # Mouse-over elements on a page
self.execute_script("jQuery('input#the_id').val('my_text')") # Fast text input on a page
self.execute_script("jQuery('div#dropdown a.link').click()") # Click elements on a page
self.execute_script("return jQuery('div#amazing')[0].text") # Returns the css "text" of the element given
self.execute_script("return jQuery('textarea')[2].value") # Returns the css "value" of the 3rd textarea element on the page(Most of the above commands can be done directly with built-in SeleniumBase methods.)
ā Some websites have a restrictive Content Security Policy to prevent users from loading jQuery and other external libraries onto their websites. If you need to use jQuery or another JS library on those websites, add --disable-csp as a pytest command-line option to load a Chromium extension that bypasses the CSP.
start_page = "https://xkcd.com/465/"
destination_page = "https://github.com/seleniumbase/SeleniumBase"
self.goto(start_page)
referral_link = '''<a class='analytics test' href='%s'>Free-Referral Button!</a>''' % destination_page
self.execute_script('''document.body.innerHTML = \"%s\"''' % referral_link)
self.click("a.analytics") # Clicks the generated button(Due to popular demand, this traffic generation example has been included in SeleniumBase with the self.generate_referral(start_page, end_page) and the self.generate_traffic(start_page, end_page, loops) methods.)
from seleniumbase import BaseCase
BaseCase.main(__name__, __file__)
class DeferredAssertTests(BaseCase):
def test_deferred_asserts(self):
self.goto("https://xkcd.com/993/")
self.wait_for_element("#comic")
self.deferred_assert_element('img[alt="Brand Identity"]')
self.deferred_assert_element('img[alt="Rocket Ship"]') # Will Fail
self.deferred_assert_element("#comicmap")
self.deferred_assert_text("Fake Item", "ul.comicNav") # Will Fail
self.deferred_assert_text("Random", "ul.comicNav")
self.deferred_assert_element('a[name="Super Fake !!!"]') # Will Fail
self.deferred_assert_exact_text("Brand Identity", "#ctitle")
self.deferred_assert_exact_text("Fake Food", "#comic") # Will Fail
self.process_deferred_asserts()deferred_assert_element() and deferred_assert_text() will save any exceptions that would be raised. To flush out all the failed deferred asserts into a single exception, make sure to call self.process_deferred_asserts() at the end of your test method. If your test hits multiple pages, you can call self.process_deferred_asserts() before navigating to a new page so that the screenshot from your log files matches the URL where the deferred asserts were made.
self.driver.delete_all_cookies()
capabilities = self.driver.capabilities
self.driver.find_elements("partial link text", "GitHub")(In general, you'll want to use the SeleniumBase versions of methods when available.)
pytest --reruns=1 --reruns-delay=1"Catch bugs in QA before deploying code to Production!"
Available Tools
25 toolsassert_conditionA
Verify an expected browser condition and fail when it is not met.
Use this tool for explicit verification. Unlike check_condition, which simply reports True or False on the current state, assert_condition treats a failed expectation as an error. (Note that URL/title checks do not wait for the 'timeout'.)
Args: check: - "element_present": Verify selector identifies a present element. - "element_visible": Verify selector identifies a visible element. - "text_visible": Verify expected text is visible within selector, or within the whole HTML document when selector is omitted. - "title": Verify the exact page title. - "url": Verify the exact current URL. - "url_contains": Verify that the current URL contains expected. selector: Element selector for element_present, element_visible, and text_visible checks. expected: Expected text/title/URL value for text_visible, title, url, and url_contains. exact: For check="text_visible", require exact text rather than a substring. timeout: Maximum seconds to wait for element/text checks. (Ignored for title and URL checks.)
Returns: A confirmation when the expectation passes.
Raises: An assertion-related SeleniumBase exception when the expectation fails; the MCP error wrapper converts it to a descriptive result.
Tool selection: - Just inspect current state -> use check_condition. - Wait for a condition to become true -> use wait_for. - Verify that an expected condition is true -> use assert_condition.
| Name | Required | Description | Default |
|---|---|---|---|
| check | No | element_visible | |
| exact | No | ||
| timeout | No | ||
| expected | No | ||
| selector | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral disclosure burden. It clearly states that failed expectations raise an assertion-related SeleniumBase exception, that the MCP error wrapper converts it to a descriptive result, and that URL/title checks ignore the timeout. This gives the agent an accurate model of the tool's control flow and failure modes.
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 well-organized with clear sections for purpose, arguments, return, exceptions, and tool selection. It is slightly redundant in places, such as repeating the verify-vs-wait distinction, but the structure makes the important information easy to find and the length is justified by the tool's complexity.
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 description covers purpose, parameters, return value, exception behavior, timing caveats, and sibling-tool routing. Given the absence of annotations and complete lack of schema-level descriptions, this description alone is sufficient for an agent to select and invoke the tool correctly across all check types.
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 0%, so the description must fully explain all five parameters. It does so comprehensively: each check enum value is described, expected is mapped to the relevant check types, selector is scoped to element/text checks, exact is explained for text_visible, and timeout's conditional applicability is called out.
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 clearly states the tool's purpose: verify an expected browser condition and fail when it is not met. It explicitly differentiates assert_condition from check_condition by noting that a failed expectation is treated as an error, not a boolean result.
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 explicit tool-selection guidance: use check_condition for inspecting current state, wait_for for waiting on a condition, and assert_condition for verifying an expected condition. It also notes the important exception that URL/title checks do not wait for the timeout, giving agents a clear operational boundary.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_conditionA
Check the current state of an element or text without waiting for the condition to become true.
Use this tool when you need an immediate boolean observation of the current page state. Use wait_for when the condition may become true later and the workflow should wait for it. Use assert_condition when the condition is an expected requirement and failure should be treated as an assertion error.
Args:
check:
The element state to inspect when text is not provided:
- "present": Return True when at least one matching element exists.
- "visible": Return True when the matching element is visible.
Defaults to "visible".
check is ignored when text is provided.
selector:
CSS selector or SeleniumBase selector identifying the element to
inspect. Defaults to "body". When `text` is provided, this also
identifies the element whose visible text is checked.
text:
Optional text to check for visibility within `selector`. When
provided, this takes precedence over `check`; the tool checks text
visibility instead of element presence or visibility. Use this when
the question is "Is this text currently visible?" rather than
whether the element itself is present or visible.Returns: True or False indicating whether the requested condition is currently satisfied. Missing elements return False rather than raising an exception.
Tool selection: - Immediate boolean observation -> use check_condition. - Wait for an element or text condition to become true/false -> use wait_for. - Verify an expected condition and fail when it is not met -> use assert_condition. - Need the number or details of matching elements -> use find_elements. - Need to read the actual page or element content -> use get_content.
Notes: This tool does not intentionally wait for elements or text to appear. It is intended for checking the current state only. If page timing or asynchronous loading matters, use wait_for instead.
When `text` is provided, `check` is ignored.
| Name | Required | Description | Default |
|---|---|---|---|
| text | No | ||
| check | No | visible | |
| selector | No | body |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully carries behavioral disclosure. It states that the tool does not wait, returns True or False, treats missing elements as False rather than raising, and ignores check when text is provided. These details go far beyond a generic 'check condition' summary.
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 well-structured with clear sections (Args, Returns, Tool selection, Notes) and the core purpose is front-loaded. However, it repeats 'check is ignored when text is provided' three times and restates the wait_for advice in multiple places, so it is slightly less concise than it could be.
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?
Despite having no output schema or annotations, the description covers the return value, error behavior for missing elements, defaults for all parameters, parameter interactions, and sibling routing. An agent has everything needed to choose and invoke 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?
The schema has 0% description coverage, so the description must fully explain the parameters. It does: check defines both enum values and the default, selector defines the default and connection to text, and text explains precedence over check and the intended question it answers ('Is this text currently visible?').
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 opens with a specific verb and resource: 'Check the current state of an element or text without waiting' and frames itself as an 'immediate boolean observation.' It also explicitly differentiates from sibling tools by naming wait_for, assert_condition, find_elements, and get_content, so an agent can distinguish it without opening schemas.
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 gives direct when-to-use guidance ('Use this tool when you need an immediate boolean observation') and explicit alternatives: wait_for for conditions that may become true later, assert_condition for expected requirements, find_elements for counts/details, get_content for reading content. It also specifies when text should be used instead of element checks.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
clickA
Click one or more elements matching a selector.
This is the primary element-clicking tool. The selector may be a CSS selector or SeleniumBase text-matching selector such as 'a:contains("Sign in")'.
Args: selector: Target CSS selector or text-matching selector. nth: Click only the Nth matching element, using 1-based indexing. Takes priority over all_matches. all_matches: Click every currently visible matching element, in order. Ignored when nth is provided. only_if_visible: Attempt the click only when the target is already visible. Does not wait for the element to become visible. parent_selector: Restrict the nested lookup to a parent element. Useful for elements inside iframes or nested containers when supported by SeleniumBase. timeout: Seconds to wait for a basic click when no specialized mode is selected. Defaults to 7 seconds. scroll: Scroll the target into view before clicking.
Tool selection: - Click one matching element -> basic click. - Click a specific matching occurrence -> set nth. - Click every visible match -> set all_matches=True. - Click only when already visible -> set only_if_visible=True. - Click an element nested inside another element -> set parent_selector.
| Name | Required | Description | Default |
|---|---|---|---|
| nth | No | ||
| scroll | No | ||
| timeout | No | ||
| selector | Yes | ||
| all_matches | No | ||
| only_if_visible | No | ||
| parent_selector | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full transparency burden. It discloses key behaviors: nth takes priority over all_matches, all_matches is ignored when nth is set, only_if_visible does not wait for visibility, and timeout defaults to 7 seconds. This is substantive, though it does not describe failure behavior or what happens when no element matches.
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?
Well-structured with Args and Tool selection sections. The Tool selection list somewhat recaps the Args details, but it serves as a useful decision aid. Overall, the description is appropriately sized for the complexity of the tool and information is easy to scan.
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 an output schema exists, return-value details are not required. The description covers selector syntax, parameter precedence, timeout behavior, visibility handling, and parent scoping. It is nearly complete, but it omits behavior for zero matching elements and any potential side effects of clicking.
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 0%, so the description fully compensates by explaining every parameter in the Args section. The inclusion of a concrete selector example ('a:contains("Sign in")') adds valuable syntax guidance beyond the schema's bare property titles.
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 ('Click one or more elements matching a selector') and identifies itself as the primary element-clicking tool. This clearly distinguishes it from sibling tools like hover_with_action and gives immediate clarity about its resource and scope.
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?
Provides an explicit 'Tool selection' section that maps use cases to parameter choices (basic click, nth, all_matches, only_if_visible, parent_selector). It does not explicitly contrast with sibling tools, but the guidance is concrete and actionable for choosing the right invocation mode.
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 active browser session and release browser resources.
Call this when the browser automation workflow is finished. Closing the session ends the persistent browser state, including its open tabs, cookies, navigation history, and page state. If browser automation is needed afterward, start a new session with start_browser.
This operation is safe to call when no browser session is active.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it delivers. It discloses that closing ends persistent browser state, enumerates the destroyed state (tabs, cookies, navigation history, page state), and explicitly states it is safe to call when no session is active. This is strong behavioral disclosure for a teardown operation.
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 compact and well-structured: an immediate behavioral statement, a clear usage condition, the side-effect disclosure, and the fallback action. Each sentence earns its place and the most important information 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?
The tool is simple (zero parameters) and has an output schema, so the description need not explain return values. It fully covers what the tool does, when to use it, what state it destroys, and how it behaves in an edge case. Nothing needed for correct invocation 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?
The tool has zero parameters and the schema documents them trivially with 100% coverage. Since there are no parameters to describe, the baseline of 4 applies; the description appropriately spends no space on parameter semantics.
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 verb-resource pair: 'Close the active browser session and release browser resources.' It is specific about the scope (the active session) and naturally distinguishes itself from the sibling start_browser without ambiguity.
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 explicitly says when to call this tool: 'when the browser automation workflow is finished.' It also names the alternative for follow-up work: 'start a new session with start_browser.' It additionally clarifies the safe no-op case, leaving no doubt about when invocation is appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_elementsA
Find matching elements and return structured element information.
Use this tool when you need to discover how many elements match a selector, inspect their text/tag names, or inspect the HTML of multiple matches.
This tool resolves element handles immediately into ordinary JSON-like dictionaries. It does not return live SeleniumBase element objects.
Args: selector: CSS selector, or a SeleniumBase selector that can match visible text. Examples include "button", ".login-link", or 'a:contains("Sign in")'. timeout: Maximum number of seconds to wait for matching elements to be found. (Defaults to 0.5 seconds.) include_html: If True, include each matching element's outer HTML. If False, return only tag name and text. (Defaults to False.)
Returns: A dictionary containing: - count: Number of matching elements found. - matches: A list of element dictionaries containing tag_name and text, plus html when include_html=True. If there are no matching elements, returns an empty dictionary.
Tool selection: - Need structured information about matching elements -> use find_elements. - Need the visible text/HTML of a page or a single element -> use get_content. - Need to click one of several matches -> use click with nth. - Need to know whether an element is present/visible -> use check_condition.
Note: Element handles cannot be persisted across MCP calls. If you find elements and then need to act on one, resolve it again with the appropriate interaction tool.
| Name | Required | Description | Default |
|---|---|---|---|
| timeout | No | ||
| selector | Yes | ||
| include_html | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full behavioral burden. It clearly discloses that element handles resolve immediately into JSON-like dictionaries rather than live SeleniumBase objects, that handles cannot persist across MCP calls, and that no matches yield an empty dictionary. These are non-obvious traits an agent must know.
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 front-loaded with a concrete purpose, then organizes content into Args, Returns, Tool selection, and Note. Each section adds distinct valueāparameter details, return shape, alternatives, and a critical persistence caveatāwithout filler or redundancy.
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 description is fully self-contained despite missing annotations and schema descriptions. It covers purpose, when to use, full parameter semantics, return structure including the empty-dictionary edge case, behavioral caveats, and sibling routing. Nothing an agent needs to correctly select and invoke the tool is absent.
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 0%, but the description fully compensates. It explains selector syntax with concrete examples, gives the timeout default and behavior, and describes exactly how include_html alters the output. Every parameter is meaningfully defined beyond its name and type.
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 first sentence states a specific verb (find) and resource (matching elements) with a clear outcome (structured element information). The Tool selection section explicitly distinguishes it from get_content, click, and check_condition, so an agent can immediately tell which tool to use.
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 'Tool selection' section explicitly lists when to use find_elements (counting matches, inspecting text/tag names, or HTML of multiple matches) and routes to alternatives for other needs. This leaves no ambiguity about when to prefer another sibling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
focus_onA
Scroll to, focus, or highlight an element.
Use this tool when an element needs to be brought into view, focused for keyboard interaction, or highlighted for debugging/demonstration.
This tool does NOT click, type into, select from, hover over, or otherwise activate the element.
Args: selector: CSS selector or SeleniumBase selector identifying the target.
action:
- "scroll_to_element": Scroll the page until the element is in
the current viewport. This is the default action.
- "focus": Move keyboard focus to the element.
- "highlight": Temporarily highlight the element for debugging or
demonstration. This can affect timing and may reduce stealth.Tool selection: - Bring an element into view -> use focus_on with the default action. - Focus an element -> use focus_on(action="focus"). - Highlight element for debugging -> use focus_on(action="highlight"). - Click -> use click. - Type text into a text field -> use type_text. - Hover -> use hover_with_action.
| Name | Required | Description | Default |
|---|---|---|---|
| action | No | scroll_to_element | |
| selector | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
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 side effects of highlighting ('can affect timing and may reduce stealth'), the default scroll behavior, and explicitly states that it does not activate the element. This is comprehensive behavioral disclosure.
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 well-structured with clear sections (overview, purpose, args, tool selection). Every sentence carries value and there is no filler. The organization makes it easy for an agent to parse quickly.
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 description covers what, when, how, and the behavioral consequences. The output schema is present, so return values do not need description. The tool selection guidance provides full contextual completeness for correct invocation.
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 0%, and the description fully compensates by explaining the 'selector' parameter and providing a detailed explanation of each enum value for 'action', including the default. This adds meaning far beyond the raw schema.
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 specific verbs ('Scroll to, focus, or highlight') tied to a clear resource ('an element') and explicitly lists what the tool does NOT do (click, type, select, hover). This sharply distinguishes it from sibling tools like click, type_text, and hover_with_action.
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 dedicated 'Tool selection' section explicitly states when to use focus_on for each action and points to alternative tools for clicking, typing, and hovering. No inference is required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_attributesA
Read HTML attributes from a matching element.
Use this tool when you need the value of one or more HTML attributes such as href, src, value, class, id, name, type, aria-label, or data-*.
Args: selector: CSS selector or SeleniumBase text-matching selector for the target element. attribute: Specific HTML attribute to retrieve. When omitted, return all HTML attributes of the element as a dictionary.
Returns: The requested attribute value, or a dictionary containing all HTML attributes of the element when attribute is omitted.
Tool selection: - Need one or more HTML attribute values from a specific element -> use this tool. - Need to discover multiple matching elements or inspect their text -> use 'find_elements'. - Need visible text or HTML content -> use 'get_content'. - Need to check element presence/visibility -> use 'check_condition'.
This is a read-only operation and does not modify the element.
| Name | Required | Description | Default |
|---|---|---|---|
| selector | Yes | ||
| attribute | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It clearly states the operation is read-only and does not modify the element, and it explains the two possible return shapes. It does not cover behavior for missing selectors or multiple matches, but the core behavioral profile 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?
The description is well-structured with Args, Returns, and Tool selection sections, and the first sentence states the purpose immediately. It is longer than strictly necessary, but each section contributes practical information with only minor 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?
For a simple read tool with no annotations or output schema, the description adequately covers parameters, return values, and tool selection. It falls short of a 5 by omitting error behavior for unmatched or missing elements and not clarifying multiple-match selector semantics.
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 0%, so the description must document the parameters, and it does: selector is defined as a CSS selector or SeleniumBase text-matching selector, and attribute is described as optional with a default of returning all attributes as a dictionary. The phrase 'one or more HTML attributes' is slightly inconsistent with the singular attribute parameter.
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 opens with a clear verb and resource: 'Read HTML attributes from a matching element.' It names concrete attribute examples and distinguishes the tool from siblings like find_elements, get_content, and check_condition in the Tool selection section, so an agent can choose correctly.
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 explicitly states when to use the tool ('Use this tool when you need the value of one or more HTML attributes') and provides a bulleted Tool selection section with alternatives and the conditions that route to them. This leaves little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_contentA
Read visible text, HTML, or discovered URLs from the current page.
Use this tool when you need actual page content or URL information rather than page metadata.
Args: selector: Optional CSS selector or SeleniumBase text-matching selector identifying the element whose content should be read. For output_format="text" or "html", the selector scopes the returned content to that element. For output_format="urls", the selector scopes URL discovery to URLs within that element. When omitted, the operation applies to the whole page.
output_format:
- "text": Return visible text from the page or selected element.
- "html": Return HTML from the page or selected element.
- "urls": Return all discovered linked/resource URLs on the page
or within the selected element. URLs associated with elements
such as anchors, links, images, scripts, and metadata may be
included. SeleniumBase returns full URLs with their URL
prefixes.
include_shadow_dom: When output_format="html" and selector is omitted,
include any shadow-root HTML present in the page. This option has
no effect for "text" or "urls", or when a selector is specified.Returns: For output_format="text", a string containing visible text. For output_format="html", a string containing HTML. For output_format="urls", a list of URL strings. This is useful for crawling, link discovery, resource inspection, and finding candidate URLs before navigating to them.
Tool selection: - Need URL, title, origin, or User-Agent -> use get_page_info. - Need visible text -> use output_format="text". - Need page or element HTML -> use output_format="html". - Need URLs from the page or an element -> use output_format="urls". - Need structured information about matching elements -> use find_elements. - Need to check element presence/visibility -> use check_condition. - Need to wait for content to appear -> use wait_for.
| Name | Required | Description | Default |
|---|---|---|---|
| selector | No | ||
| output_format | No | text | |
| include_shadow_dom | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully carries the behavioral disclosure burden. It explains returned types per output_format, the effect of include_shadow_dom (and when it has no effect), and that URLs are returned as full URL strings. This is strong transparency, though it could also explicitly state that the operation is read-only and non-mutating.
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 long but efficiently organized with clear 'Args:', 'Returns:', and 'Tool selection:' sections. The opening sentence states the core purpose immediately, and every subsequent line adds necessary detail without redundancy.
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 the tool's moderate complexity, zero annotations, and complete parameter documentation in the description, it is fully self-contained. It covers what the tool returns, how parameters affect behavior, and how to choose between this and sibling tools. No critical information is missing for correct invocation.
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 0%, so the description must fully explain each parameter. It does so in detail: selector scoping behavior per format, the meaning of each output_format enum, and the exact conditions under which include_shadow_dom applies. No parameter is left ambiguous.
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 opens with a specific verb and resource: 'Read visible text, HTML, or discovered URLs from the current page.' It clearly distinguishes from siblings by naming alternative tools for different needs, such as get_page_info for metadata and find_elements for structured element info.
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?
A dedicated 'Tool selection' section explicitly lists when to use this tool versus alternatives like get_page_info, find_elements, check_condition, and wait_for. It also maps each output_format value to the appropriate use case, leaving no ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_page_infoA
Get current browser session and page metadata.
Use this as the primary tool for determining where the browser currently is after navigation, clicks, form submissions, redirects, reloads, or tab switches.
This is a READ-ONLY metadata operation. It does not inspect arbitrary page content, find elements, check visibility, wait for conditions, or assert expected values.
Returns: A dictionary containing: - running: True when a browser session is active. - url: The complete current page URL, including path and query string. - title: The current document title. - origin: The current page origin (scheme, host, and port). - user_agent: The browser's current User-Agent string.
Tool selection: - Need URL, title, origin, or User-Agent -> use get_page_info. - Need visible page text or HTML -> use get_content. - Need information about matching elements -> use find_elements. - Need an immediate state check -> use check_condition. - Need to wait for a condition -> use wait_for. - Need to verify an expected condition -> use assert_condition.
Unlike a dedicated browser-status tool, get_page_info is the single source of browser/page metadata. If no browser session is active, it returns {"running": False} instead of attempting to access a page.
This operation does not navigate, reload, click, type, or otherwise modify the current page.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden, and it does so thoroughly. It labels the operation READ-ONLY, states what it does not do, explains the behavior when no browser session is active, and explicitly says it does not navigate, reload, click, type, or modify the page.
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?
Although the description is long, it is organized into clear sections with front-loaded purpose, a structured return specification, and an explicit tool-selection guide. Each sentence adds necessary guidance, especially given the large sibling set and absence of annotations.
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 description fully covers what the tool returns, what it does not do, when to use it, and how it behaves without an active browser session. Given the simple parameterless signature and rich output schema, nothing essential is missing for an agent to select and call it 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?
The tool has zero parameters and an empty input schema, so there is no parameter ambiguity. The description adds value by clearly documenting the returned dictionary keys and their meanings, which is the relevant semantic content for a parameterless metadata tool.
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 opens with a specific verb and resource: 'Get current browser session and page metadata.' It explicitly positions itself as the primary tool for determining the current browser location after navigation, clicks, or tab switches, and distinguishes itself from content, element, and condition-checking siblings.
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 'Tool selection' section gives direct, condition-based routing: 'Need URL, title, origin, or User-Agent -> use get_page_info' and maps each alternative need to a specific sibling tool. This leaves no ambiguity about when to use this tool versus find_elements, get_content, check_condition, wait_for, or assert_condition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
hover_with_actionA
Hover over an element, optionally click another element, or drag-&-drop.
Use this tool for hover interactions, hover-triggered menus, and drag-and-drop operations.
Args: selector1: The primary element selector.
For action="none", this is the element to hover over.
For action="click", this is the element to hover over before
clicking selector2.
For action="drag_and_drop", this is the draggable source element.
selector2:
The secondary element selector.
Required for action="click", where it identifies the element
revealed or targeted after hovering selector1.
Required for action="drag_and_drop", where it identifies the
destination/drop target.
Not used for action="none".
action:
- "none": Hover over selector1 only.
- "click": Hover over selector1, then click selector2.
- "drag_and_drop": Drag selector1 and drop it onto selector2.Returns: A confirmation describing the performed operation.
Tool selection: - Simple hover -> action="none". - Hover over one element and then click another -> action="click". - Drag one element onto another -> action="drag_and_drop".
Notes: For action="click", selector1 is the hover target and selector2 is the click target.
For action="drag_and_drop", selector1 is the source and selector2
is the destination.
| Name | Required | Description | Default |
|---|---|---|---|
| action | No | none | |
| selector1 | Yes | ||
| selector2 | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It clearly states what each action does and what the return is. It doesn't address side-effect caveats such as page navigation or visibility requirements, but the core behavior is 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?
The description is front-loaded with the summary and well organized into Args, Returns, Tool selection, and Notes. It is slightly repetitive because Notes restates selector roles already covered in Args, but the structure is scannable and easy to follow.
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?
It covers all parameters, all three action branches, selection guidance, and return behavior, so an agent can call it correctly in most cases. Minor gaps are the lack of stated preconditions such as an active browser session and no explicit exclusion for simple clicks, but these are not blocking.
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 schema has zero parameter descriptions, but the description compensates fully by explaining selector1's role per action, selector2's requirement and nullability per action, and the exact meaning of every action enum value. This is thorough and directly actionable.
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 opens with the exact operations: hover, optional click, and drag-and-drop, and explicitly names hover-triggered menus as a key use case. This clearly differentiates it from siblings like click, focus_on, and scroll.
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 provides a dedicated 'Tool selection' section that maps each action value to a scenario, and says to use the tool for hover interactions, hover-triggered menus, and drag-and-drop. It does not explicitly mention when to use sibling tools instead, but the intended usage is clear enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
manage_cookiesA
Manage cookies for the current browser session.
Use this tool to inspect, clear, save, or restore browser cookies. Cookie management is useful for inspecting session state, preserving login sessions between browser runs, restoring previously saved sessions, or resetting website state during testing.
Args: action: - "get_all": Return all cookies currently available to the browser, including attributes such as name, value, domain, path, expiry, and security flags. - "clear": Delete all cookies from the current browser session. - "save": Save current cookies to filename. The file may be created or overwritten. - "load": Load cookies from filename into the current browser session. filename: Filesystem path used by save/load. Defaults to "cookies.txt". Ignored for get_all and clear.
Returns: "get_all": Current browser cookies. "clear": Confirmation that cookies were cleared. "save": Confirmation containing the destination filename. "load": Confirmation containing the source filename.
Security: Cookie data can contain authentication credentials, session identifiers, and other private information. Only inspect, save, load, or share cookies when explicitly authorized.
`filename` is passed to SeleniumBase's cookie persistence methods and
can access the filesystem available to the MCP server. Use only
trusted, authorized paths. The save action may overwrite an existing
file.Notes: Loading saved cookies does not guarantee restoration of a login. Cookies may be expired, invalidated, domain/path restricted, or dependent on other browser state. Navigate to the relevant site when necessary so the browser has the appropriate origin for the cookies.
| Name | Required | Description | Default |
|---|---|---|---|
| action | No | get_all | |
| filename | No | cookies.txt |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description itself discloses key behaviors: clearing deletes 'all cookies', saving may overwrite existing files, loading does not guarantee login restoration, and cookie data may contain sensitive credentials. This is strong behavioral transparency.
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 detailed but well structured into Args, Returns, Security, and Notes sections. Every section provides useful information, though the Returns section partially repeats action semantics already covered in Args.
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 two parameters and no output schema, the description covers all necessary operational details: action outcomes, return descriptions, filename behavior, security considerations, and limitations of loading cookies. Nothing critical 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?
The schema has 0% description coverage, and the description fully compensates by explaining each action value and the filename parameter, including its default value and when it is ignored. This gives the agent complete parameter meaning.
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 clearly states that the tool is for managing browser cookies and enumerates specific actions: inspect, clear, save, restore. This distinguishes it from sibling tools like manage_storage by focusing specifically on cookies.
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 provides practical use cases such as preserving login sessions, restoring sessions, and resetting website state during testing. It does not explicitly mention alternatives or when not to use this tool, but the context is clear enough for correct selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
manage_historyA
Navigate through the current browser history, reload the current page, or list the current browser history.
Use this tool for navigation relative to the current browser history or for displaying the current browser history. Use the 'navigate' tool when going to an arbitrary URL.
Args: action: - "back": Navigate to the previous history entry. Has no useful effect when there is no previous history entry. - "forward": Navigate to the next history entry. Has no useful effect when there is no forward history entry. - "reload": Reload the current page while ignoring the browser cache so page resources are fetched again. - "list": Return a tuple containing the current location in history (0-indexed) and the full navigation-history list.
Returns: A confirmation message describing the operation performed for navigation actions, or, for "list", a tuple containing the current history location (0-indexed) and the full navigation-history list.
Notes: These operations can trigger page loads, redirects, and other navigation events. Use the 'get_page_info' tool afterward when you need to verify the resulting URL or title.
Tool selection: - Arbitrary destination URL -> use navigate. - Previous/next browser history entry -> use this tool. - Refresh current page -> use this tool with action="reload". - List current history -> use this tool with action="list".
| Name | Required | Description | Default |
|---|---|---|---|
| action | No | list |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden, and it delivers: it discloses that 'back' and 'forward' have no useful effect at history boundaries, that 'reload' ignores the browser cache, and that operations can trigger page loads, redirects, and navigation events. It also explains the return behavior for each action and recommends verification via 'get_page_info'.
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 long but every section earns its place: action semantics, return values, side-effect warnings, and tool selection guidance. It is well-organized with clear headings and front-loaded purpose, avoiding redundant 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 description is fully complete for a tool with one parameter and an output schema. It covers all actions, return semantics, side effects, boundary behavior, and when to use alternative tools, leaving no significant gap for an agent deciding whether and how to invoke it.
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 0%, so the description must fully explain the single parameter. It does, with a detailed breakdown of each enum value: 'back', 'forward', 'reload', and 'list'. The description adds meaning beyond the bare enum, including effect, boundary behavior, cache handling, and return format.
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 opens with a clear, specific statement: 'Navigate through the current browser history, reload the current page, or list the current browser history.' It also distinguishes itself from the 'navigate' tool by explicitly stating that 'navigate' is for arbitrary URLs, making the tool's scope unambiguous.
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 an explicit 'Tool selection' section with clear routing rules: arbitrary URL -> navigate, previous/next history entry -> this tool, refresh -> reload, list -> list. It also advises using 'get_page_info' afterward to verify the resulting URL or title, giving concrete post-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
manage_storageA
Get or set a key in localStorage or sessionStorage.
Use this tool when the browser workflow needs to inspect or modify JavaScript Web Storage belonging to the current page origin.
Tool selection: - Need localStorage/sessionStorage -> use this tool. - Need cookies or authentication cookies -> use manage_cookies. - Need arbitrary JavaScript or storage operations not covered here -> use run_javascript. - Need visible page content or HTML -> use get_content. - Need an element's HTML attributes -> use get_attributes.
When not to use: - Do not use this tool for HTTP cookies; use manage_cookies instead. - Do not use this tool for arbitrary page JavaScript; use run_javascript when a higher-level tool is insufficient. - Do not use this tool to inspect values from another origin; storage is scoped to the current page origin.
Args: key: Storage key to read or modify. value: Value to store when action="set". Required for set. storage: "local" for localStorage or "session" for sessionStorage. action: "get" to read the key or "set" to write the key.
Returns: The stored value for get, or a confirmation message for set.
Security: Web storage can contain authentication tokens, session identifiers, and other sensitive application state. Only use this tool with trusted sites and authorized MCP clients.
Notes: Storage belongs to the current page origin. Values from one website are not generally available to another origin.
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | ||
| value | No | ||
| action | No | get | |
| storage | No | local |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carres the full burden and does so thoroughly: it explains get vs set behavior, the return values, storage origin scoping, and security implications around auth tokens and session identifiers. It also notes that storage is per-origin, which is crucial behavioral context.
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?
Information is well-organized under clear headings and the core purpose is front-loaded. There is some repetition about storage being origin-scoped and about not using run_javascript for arbitrary JavaScript, but it remains concise enough for an agent to parse.
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 description covers purpose, selection, parameters, returns, and security, which is strong for a tool with no annotations and no output schema. A minor gap is that setting a null value is not explained, and the persistence distinction between local and session storage is only implied by their 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 0%, but the description fully compensates by explaining every argument: key, value, storage, and action. It even clarifies the conditional requirement that value is required when action='set', which the schema alone does not express.
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 opening sentence 'Get or set a key in localStorage or sessionStorage' names a specific verb, a concrete resource, and the storage type. It also distinguishes the tool from siblings by explicitly scoping it to Web Storage, not cookies, content, or JavaScript execution.
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 an explicit tool-selection section listing when to use this tool versus manage_cookies, run_javascript, get_content, and get_attributes. It also gives clear 'When not to use' exclusions, making the selection decision unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
manage_tabsA
List, open, switch between, or close browser tabs.
Use this tool for tab management. Browser navigation within the current tab belongs to navigate and manage_history.
Args: action: - "list": Return each open tab's index, URL, and title. Call this before switch when you need to determine a tab_index. - "open": Open a new tab, optionally navigating it to url. - "switch": Switch to the tab identified by tab_index from list. - "switch_newest": Switch to the newest tab. - "close_active": Close the currently active tab. url: URL for action="open". tab_index: Index returned by action="list" for action="switch". switch_to: For action="open", switch to the newly created tab when True.
Notes: Clicking a link or performing another browser action may open a new tab. Use action="list" to inspect available tabs before switching by index. Tab indexes should be treated as current-session values and may change after tabs are opened or closed.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | ||
| action | No | list | |
| switch_to | No | ||
| tab_index | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It explains what 'list' returns, what each action does, and warns that tab indexes are session-scoped and may change after tabs are opened or closed. It also notes that other browser actions may open new tabs, which helps the agent plan its calls.
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 well-organized with a clear opening summary, a usage boundary, an action breakdown, and a notes section. Every sentence adds necessary information, and the structure makes it easy for an agent to scan the action options and associated parameters.
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 the multi-action nature and conditional parameters, the description is complete: it covers all four parameters, all five actions, return contents for list, the relationship between list and switch, and important caveats about tab index stability. The sibling-tool boundary is also explicitly drawn, so an agent can confidently select this tool.
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 0%, so the description must fully explain parameters. It does: action is detailed with each enum value's behavior, url is tied to 'open', tab_index is tied to list results for 'switch', and switch_to is explicitly described. This fully compensates for the schema's lack of 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 opens with a specific verb and resource: 'List, open, switch between, or close browser tabs.' It clearly defines the tool's scope and distinguishes it from navigate/manage_history, which manage navigation within the current tab rather than tab-level operations.
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 explicitly states that tab management belongs here and that browser navigation within the current tab belongs to navigate and manage_history. It also advises calling action='list' before 'switch' to determine tab_index, giving concrete when-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
manage_windowA
Get or change browser window geometry and state.
Args: action: - "get_rect": Return the current window coordinates and size. - "set_rect": Set x, y, width, and height. All four are required. - "maximize": Maximize the browser window. - "minimize": Minimize the browser window. x: Horizontal screen position for set_rect. y: Vertical screen position for set_rect. width: Window width for set_rect. height: Window height for set_rect.
Use this tool for browser-window geometry/state. For switching between browser tabs, use manage_tabs instead.
| Name | Required | Description | Default |
|---|---|---|---|
| x | No | ||
| y | No | ||
| width | No | ||
| action | No | get_rect | |
| height | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description must disclose behavior itself, and it mostly does. It explains that get_rect returns coordinates and size, set_rect sets all four geometry values, and maximize/minimize change state. The main gaps are lack of detail on side effects, return format, and error behavior, which keeps it from a 5.
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 front-loaded with its purpose, followed by a compact bulleted list of actions and parameters. Every sentence contributes useful information, and the routing note is placed at the end without disrupting the core usage details.
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 description covers all five parameters, every action, the set_rect requirement, and sibling routing, which is enough for correct selection and basic invocation. It does not mention prerequisites like a running browser, return shapes, or how maximize/minimize interact with get_rect, so it is not 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 schema has 0% parameter description coverage, so the description carries the full load. It defines each parameter ('Horizontal screen position for set_rect'), explains every action enum value, and adds the crucial constraint that all four geometry parameters are required for set_rect. It stops short of specifying units or coordinate-system details, so not a 5.
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 opens with a clear verb+resource: 'Get or change browser window geometry and state.' It enumerates four concrete actions (get_rect, set_rect, maximize, minimize), making it obvious what the tool does. The closing sentence also explicitly differentiates it from the sibling tool manage_tabs.
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 when to use it: 'Use this tool for browser-window geometry/state.' It also states when not to and names the alternative: 'For switching between browser tabs, use manage_tabs instead.' This is a clear when/when-not pattern with a specific alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_javascriptA
Evaluate a JavaScript expression in the current page context.
Use this only when the required browser operation cannot be accomplished through the higher-level SeleniumBase tools.
The expression is evaluated through Chrome DevTools Protocol Runtime.evaluate in the currently active page. It executes with access to the page's JavaScript context, including DOM APIs, browser storage, and other same-origin page resources available to JavaScript.
Tool selection: - Prefer click, type_text, select_option, hover_with_action, focus_on, scroll, and other higher-level tools for normal browser interactions. - Prefer get_content, get_attributes, and find_elements for reading page content or element information. - Prefer manage_storage for ordinary localStorage/sessionStorage reads and writes. - Prefer manage_cookies for browser cookie operations. - Use this tool when a required operation needs arbitrary JavaScript that the higher-level tools do not expose.
Args: expression: A JavaScript expression or executable JavaScript code evaluated in the current page. It may reference standard browser globals such as document and window and may use DOM APIs.
Examples:
- "document.title"
- "document.querySelector('button')?.textContent"
- "localStorage.getItem('theme')"
- "document.body.classList.contains('dark')"
- "document.querySelector('#slider').value = '50'"
The expression should produce a value when a result is needed.
JavaScript that returns a Promise is supported and its resolved
value is returned.Returns: The JavaScript evaluation result when it can be serialized and returned across the MCP boundary. Primitive values, arrays, plain objects, and null are generally suitable return values. DOM objects, functions, symbols, and other non-serializable JavaScript values may not be returned directly; extract the needed property or convert the value to a serializable form first.
Security: This provides unrestricted JavaScript execution in the current browser page. It can read or modify page data and interact with the page in ways that bypass the higher-level tool abstractions. Only expose this MCP server to trusted clients.
| Name | Required | Description | Default |
|---|---|---|---|
| expression | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Even though no annotations are provided, the description discloses execution via Chrome DevTools Protocol Runtime.evaluate, access to the page's JavaScript context, Promises support, serialization limitations for return values, and unrestricted security implications. It clearly states that this tool can read or modify page data and bypass higher-level abstractions, giving the agent a complete behavioral picture.
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 long but every section earns its place: purpose, tool-selection guidance, argument semantics, return behavior, and security warning. It is well-structured with clear headers and front-loaded with the core usage constraint. No filler or redundant marketing language is present.
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 the tool's high complexity, minimal schema, no annotations, and no output schema, the description is remarkably complete. It covers execution context, supported input forms, return serialization, Promise resolution, and security risk. An agent has enough information to decide when to invoke it and to craft a correct expression.
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 only provides the parameter name 'expression' with zero description coverage, so the description carries the full burden. It thoroughly explains what the expression may reference, gives multiple concrete examples, notes that Promises are supported, and clarifies that the expression should produce a serializable value when a result is needed. This far exceeds what the schema alone 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?
The description clearly states a specific verb and resource: 'Evaluate a JavaScript expression in the current page context.' It also distinguishes itself from the higher-level sibling tools by framing itself as the low-level arbitrary-JavaScript fallback. This makes its purpose unambiguous and differentiable.
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 to use this only when higher-level SeleniumBase tools cannot accomplish the operation. It then lists preferred tools for specific categories such as click, type_text, get_content, manage_storage, and manage_cookies, and finally states the condition for using this tool. This is exemplary when-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
save_outputA
Save the current browser page as a screenshot, HTML file, or PDF.
Use this tool when an automation workflow needs a persistent artifact from the current page, such as a screenshot for debugging, page source for inspection, or a PDF representation.
Args: format: - "screenshot": Save a PNG screenshot. - "html": Save the current page source as HTML. - "pdf": Save the current page as a PDF. filename: Output filename. Defaults to screenshot.png, page_source.html, or page.pdf depending on format. folder: Optional destination folder.
Returns: A confirmation containing the output format and filename.
Security: filename and folder can affect filesystem paths available to the MCP server. Existing files may be overwritten. Use trusted, authorized paths only.
| Name | Required | Description | Default |
|---|---|---|---|
| folder | No | ||
| format | No | screenshot | |
| filename | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It discloses potentially destructive behavior ('Existing files may be overwritten') and filesystem security implications ('filename and folder can affect filesystem paths available to the MCP server'), which is meaningful beyond the schema. It also documents the return value as a confirmation containing format and filename.
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 well-structured with clear sections: purpose, usage, args, returns, and security. It is front-loaded with the core action, and every section contributes useful information without redundancy 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?
For a tool with three optional parameters and an output schema, the description covers purpose, parameter semantics, return value, and security caveats. Nothing an agent needs to decide whether and how to call this tool 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 0%, so the description must compensate, and it does thoroughly. It explains each parameter, enumerates valid format values with their output types, and clarifies that the filename default changes based on format (screenshot.png, page_source.html, or page.pdf). This adds meaning entirely beyond the bare schema.
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 opens with a specific verb and resource: 'Save the current browser page as a screenshot, HTML file, or PDF.' It clearly distinguishes the tool's artifact-saving purpose from sibling tools like get_content or check_state by emphasizing persistence rather than inspection.
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 states when to use the tool: 'when an automation workflow needs a persistent artifact from the current page, such as a screenshot for debugging, page source for inspection, or a PDF representation.' It provides clear context, though it does not name alternatives or situations when the tool should not be used.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scrollA
Scroll the current page vertically.
Args: direction: - "up": Scroll upward by amount percent of the window height. - "down": Scroll downward by amount percent of the window height. - "top": Scroll directly to the top; amount is ignored. - "bottom": Scroll directly to the bottom; amount is ignored. amount: Percentage of the current viewport height used for relative up/down scrolling. For example, amount=25 scrolls approximately one quarter of the viewport height.
Use focus_on(action="scroll_to_element") when the goal is to reveal a specific element rather than scroll the page by a relative amount.
| Name | Required | Description | Default |
|---|---|---|---|
| amount | No | ||
| direction | No | down |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It thoroughly explains direction semantics, the meaning of amount as a percentage of viewport height, and notes that amount is ignored for 'top' and 'bottom'. However, it does not mention edge cases such as bounds, invalid amounts, or behavior when the page cannot scroll further.
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 well-structured: a one-line purpose, a compact argument list, and a final routing note. Every sentence adds value, and the most important scoping information appears first. There is no redundant or filler content.
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 the tool's moderate complexity, the description covers the action, all parameter semantics, special cases, and the relevant sibling alternative. An output schema is present, so return-value documentation is not required. An agent has enough context to use this 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?
The input schema has 0% description coverage, so the description must compensate. It fully explains both parameters: each 'direction' value is defined, and 'amount' is described as a percentage of viewport height with a concrete example. This exceeds the schema's bare enum/default information.
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 opens with a specific verb and resource: 'Scroll the current page vertically.' It further differentiates itself from the sibling tool by explaining that focus_on(action="scroll_to_element") is for revealing a specific element, whereas this tool handles page scrolling.
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 states when to prefer an alternative: 'Use focus_on(action="scroll_to_element") when the goal is to reveal a specific element rather than scroll the page by a relative amount.' This gives clear, actionable routing guidance with no ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
select_optionA
Select an option from an HTML dropdown.
Args: dropdown_selector: CSS selector identifying the element. value: The option's visible text, its HTML value attribute, or its 0-based index, depending on by. by: - "text": Match the option's visible text. - "value": Match the option's HTML value attribute. - "index": Match the option's 0-based position. Both integer and numeric-string values are accepted.
Raises: An error when the dropdown or requested option cannot be found.
This tool is for native elements. For custom JavaScript dropdowns made from div/button/list elements, use click or other element-interaction tools instead.
| Name | Required | Description | Default |
|---|---|---|---|
| by | No | text | |
| value | Yes | ||
| dropdown_selector | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description takes on the burden of explaining behavior. It does this well by describing how matching works for each 'by' mode, noting that numeric-string indices are accepted, and stating that an error is raised when the dropdown or option cannot be found. It could go further by mentioning side effects or state changes, but the core behavioral contract is clearly 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?
The description is well-organized into an opening sentence, Args section, Raises note, and an explicit usage boundary. Every sentence adds necessary information, and the most important purpose statement 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?
Given the tool's moderate complexity, the description covers the full set of parameters, matching semantics, error behavior, and the critical native-vs-custom dropdown distinction. An output schema is present, so the description does not need to explain return values, and the provided context 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?
The schema provides no parameter descriptions, so the description fully compensates. It explains dropdown_selector as identifying the select element, value as visible text/value attribute/0-based index depending on 'by', and each 'by' enum value in detail. This goes well beyond what the raw schema conveys.
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 clearly states the action with a specific verb and resource: 'Select an option from an HTML <select> dropdown.' It also distinguishes itself from sibling tools by explicitly limiting its applicability to native select elements, avoiding confusion with click or fill_input.
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 states when this tool should be used: for native <select> elements. It also provides an alternative for custom JavaScript dropdowns: 'use click or other element-interaction tools instead.' This is clear, actionable guidance for choosing between this tool and its siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
solve_captchaA
Attempt a SeleniumBase CDP-based CAPTCHA interaction.
This tool attempts to interact with CAPTCHA controls such as Cloudflare Turnstile, reCAPTCHA, or FriendlyCaptcha using browser/CDP interaction.
The tool does not guarantee that a CAPTCHA was solved. Some CAPTCHA controls are embedded inside shadow DOM or otherwise do not expose an easy success signal. A successful attempt may result in changes to page state or browser cookies.
Tool workflow: 1. Inspect the page with get_content when you need to determine whether CAPTCHA-related controls are present. 2. Call solve_captcha to attempt the interaction. 3. Use get_page_info, get_content, check_condition, or manage_cookies to inspect resulting page/session state.
Returns: A message confirming that the CAPTCHA interaction was attempted, not a guarantee that the CAPTCHA challenge was solved.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description fully carries the burden of behavioral disclosure. It clearly states the tool does not guarantee a solved CAPTCHA, that controls may be shadow-DOM embedded, and that successful attempts may change page state or cookies. It also clarifies what the return message does and does not mean.
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 longer than a simple one-liner, but the extra length is justified by the tool's non-deterministic behavior and the need to set expectations. The main purpose is stated first, followed by a clear workflow and return semantics, with no 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?
For a zero-parameter tool with an output schema, the description is nearly complete. It explains what the tool attempts, its limitations, side effects, and the recommended surrounding workflow. Minor missing details like timeout or wait behavior are not critical for invoking it 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?
The tool has zero parameters, so the baseline is 4 and there is no parameter ambiguity. The description correctly focuses on behavior and workflow instead, which adds value beyond the empty schema.
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 and resource: it 'attempts to interact with CAPTCHA controls' via SeleniumBase CDP interaction. It names concrete CAPTCHA types, making the tool's scope clear and distinguishing it from page-inspection and navigation siblings.
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 an explicit workflow: inspect with get_content first, call solve_captcha, then verify state with get_page_info or check_condition. It does not explicitly state when not to use the tool, but the workflow and limitations imply the intended usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
start_browserA
Launch a persistent SeleniumBase Pure CDP Mode browser session.
This must be called before browser interaction tools such as navigate, get_content, click, type_text, or find_elements. The same browser session remains active across subsequent MCP tool calls until close_browser is called or the server process exits.
Pure CDP Mode communicates directly with the browser through the Chrome DevTools Protocol rather than WebDriver. This provides SeleniumBase's CDP-based browser automation capabilities without using WebDriver as the browser-control layer.
Args: url: Optional URL to open immediately after the browser launches. If omitted, the browser starts without navigating to a requested page.
headless: Controls whether the browser runs without a visible window.
If True, always run headless. If False, always run headed.
If omitted (None), the default depends on the operating system:
Linux defaults to headless because MCP/server environments
commonly do not have a graphical desktop, while Windows and macOS
default to headed so that a visible browser window is available.
Use True or False to explicitly override the OS-specific default
on any operating system.
use_chromium: Use Chromium instead of Google Chrome. This is useful
when Google Chrome is not installed. SeleniumBase can manage the
Chromium browser when this option is enabled.
browser_executable_path: Explicit filesystem path to the browser
executable when it is not installed in a standard location.
Do not combine this with use_chromium=True.
incognito: Launch Chrome/Chromium in incognito mode.
guest: Launch Chrome/Chromium in guest mode. Do not combine this with
incognito=True.
ad_block: Enable SeleniumBase's basic ad-blocking functionality.
proxy: Optional proxy server. Examples include
"SERVER:PORT" or "USER:PASS@SERVER:PORT".Returns: A confirmation message when the browser starts successfully, including the effective headless setting, or a descriptive error when browser startup fails.
Lifecycle: Call start_browser once at the beginning of a browser automation workflow. Reusing the existing session preserves cookies, tabs, navigation history, localStorage/sessionStorage, and other browser state between tool calls. Call close_browser when finished.
Environment requirements: The MCP runtime must have a compatible Chrome or Chromium browser available. If the browser executable cannot be discovered, use use_chromium=True or provide browser_executable_path explicitly.
On Linux, the default is headless=True so the browser can run in
typical server/container environments without a graphical desktop.
Set headless=False when a graphical display is available and a visible
browser is desired. On Windows and macOS, the default is
headless=False. Set headless=True when running without a desktop or
when a visible browser window is not desired.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | ||
| guest | No | ||
| proxy | No | ||
| ad_block | No | ||
| headless | No | ||
| incognito | No | ||
| use_chromium | No | ||
| browser_executable_path | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full responsibility for behavioral disclosure. It clearly reveals that the session is persistent across tool calls, maintains browser state (cookies, tabs, history, storage), and runs until close_browser is called or the server exits. It explains the CDP-based communication versus WebDriver, the OS-dependent headless default, and the availability of fallbacks like use_chromium and browser_executable_path when the browser cannot be found.
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 longer than the average MCP description, but the added length is purposeful: each block (Args, Returns, Lifecycle, Environment requirements) adds non-redundant integration-level detail. It could be slightly tightened by folding the OS-specific headless rules into one mention instead of repeating them in the Args and Environment sections; this repetition costs it a perfect score.
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 an 8-parameter, zero-annotation tool with no schema-level descriptions, the description is highly complete. It specifies every parameter, returns a structured message (confirmation or error), gives lifecycle guidance, and enumerates environment prerequisites. It leaves nothing essential about how or when to call this tool, and the output schema covers the return payload.
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?
With schema description coverage at 0%, the description fully compensates by explaining not only what each of the 8 parameters does (open a URL, control headless mode, choose Chromium, specify an executable path, incognito, guest, ad-block, and proxy) but also the mutual exclusivity constraints (browser_executable_path not with use_chromium, and guest not with incognito). Real included conventions for proxy format and default headless behavior per OS, making each parameter actionable.
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 immediately states the core function with a specific verb and resource: 'Launch a persistent SeleniumBase Pure CDP Mode browser session.' It goes beyond a generic launch description by naming the browser-control layer (Pure CDP Mode) and explicitly positioning itself as the prerequisite for interaction tools like navigate, click, and type_text, which clearly differentiates it from those 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?
The description provides strong usage context: it must be called before browser interaction tools, should be called once at the start of a workflow, and close_browser should be called when finished. It also explains the session remains available across calls. However, it does not explicitly outline scenarios where starting a browser is not appropriate or compare itself to a non-browser alternative, leaving room for an explicit when-not-to-use statement.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
type_textA
Fill, append, fast-type, directly set, or clear a form control.
Use this tool for input elements, textareas, and contenteditable elements.
Args: selector: CSS selector or SeleniumBase selector identifying the input, textarea, or contenteditable element. text: Text to enter or set. Not used when mode="clear_only". mode: - "fill_input": Clear the field and then type text normally. - "append": Keep the existing value and add text as keystrokes. - "fast_type": Clear the field and type text without pauses. - "set_value": Set the value directly and immediately. This can be useful for fast form filling but does not simulate normal key events. It can also be used to handle input sliders, e.g. 'input[type="range"]'. - "clear_only": Empty the text field; text is ignored. timeout: Maximum seconds to wait for the target element.
Tool selection: - Normal text entry to replace existing text -> mode="fill_input". - Add text without clearing the field first -> mode="append". - Fast typing to replace existing text -> mode="fast_type". - Directly set a value (e.g. input slider) -> mode="set_value". - Empty a field of all text -> mode="clear_only".
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | fill_input | |
| text | No | ||
| timeout | No | ||
| selector | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full behavioral weight and handles it well. It discloses that set_value bypasses normal key events, that clear_only ignores text, that fill_input clears before typing, and that timeout caps wait time. This gives the agent accurate expectations for each mode.
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 organized with a purpose line, scoped usage, an Args list, and a Tool selection summary. Repetition between mode definitions and tool selection is purposeful, giving the agent both reference detail and decision guidance without fluff.
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 4 parameters, 5 enum modes, and no annotations, the description covers all necessary operational context. An output schema exists, so the lack of return-value detail is acceptable. It is complete enough for an agent to select and invoke 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 0%, so the description must explain all parameters, and it does. Selector, text, mode, and timeout are each described with their role, including mode-specific nuances like ignored text in clear_only and slider support for set_value.
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 opens with a precise verb set and resource: 'Fill, append, fast-type, directly set, or clear a form control,' then scopes it to input, textarea, and contenteditable elements. This clearly differentiates type_text from sibling tools like click, select_option, and run_javascript.
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 'Tool selection' section explicitly maps each intended user goal to a specific mode, which is strong usage guidance. It also states the tool is for form controls, though it does not explicitly name sibling alternatives to avoid.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_forA
Wait until an element or text reaches a requested state.
When text is provided, a state of 'present' or 'visible' both wait
for the text to appear within the selector, and a state of 'not_visible'
or 'absent' both wait for the text to be absent from the selector.
Use this tool when the page is dynamic and an automation step must wait for a condition before continuing.
Unlike check_condition, this tool intentionally waits. Unlike assert_condition, its purpose is synchronization rather than validating a test expectation.
Args:
state:
- "present": Wait until the matching element exists.
- "visible": Wait until the matching element is visible.
- "not_visible": Wait until the matching element is not visible.
- "absent": Wait until the matching element no longer exists.
(This is handled differently when text is provided.)
selector: CSS selector or SeleniumBase selector for the element.
Required unless text is supplied.
text: If supplied and is not None, a state of 'present' or 'visible'
both wait for the text to appear within the selector, and a state
of 'not_visible' or 'absent' both wait for the text to be absent
from the selector (or within "body" when selector is omitted).
timeout: Maximum seconds to wait for the requested state to be true.
(Defaults to 7 seconds.)
Returns: A confirmation when the requested condition is reached.
Tool selection: - Check current state immediately -> use check_condition. - Wait for a state/content transition -> use wait_for. - Verify an expected value/condition -> use assert_condition.
| Name | Required | Description | Default |
|---|---|---|---|
| text | No | ||
| state | No | visible | |
| timeout | No | ||
| selector | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
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 explains that the tool intentionally waits, is for synchronization rather than validation, and clarifies how 'text' alters the meaning of 'present'/'visible' and 'absent'/'not_visible'. It does not discuss polling behavior or error handling, but the core behavior is clearly 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?
The description is organized with clear sections (intro, Args, Returns, Tool selection) and front-loads the core purpose. However, the text/state caveat is nearly identical in the intro and in the 'text' parameter explanation, making it slightly redundant. Still, no irrelevant content is present.
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 the tool's complexity, the description comprehensively covers purpose, when to use it, all parameters, state semantics, and alternatives. An output schema exists, so return value details are not required, and the description even summarizes the return ('A confirmation'). Nothing critical 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 coverage is 0%, so the description must fully document the parameters. It does: each state value is explained, selector's requirement is stated, text's special handling is detailed, and timeout's default is given. This adds far more meaning than the bare parameter names and enums in the schema.
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 and resource: it waits for an element or text to reach a requested state. It clearly distinguishes itself from sibling tools check_condition and assert_condition, so an agent can tell exactly which tool fits which purpose.
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?
Includes an explicit 'Use this tool when' statement about dynamic pages and waiting, plus a dedicated 'Tool selection' section that contrasts wait_for with check_condition and assert_condition. This gives the agent concrete selection criteria and exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_secondsA
Block the MCP server for a fixed number of seconds.
This is a low-level timing tool. It performs no browser action while waiting and should not be used when waiting for a page condition.
Prefer wait_for when waiting for an element or text to appear/disappear, because wait_for can return as soon as the requested condition is met.
Args: seconds: Number of seconds to block. May be an integer or float.
| Name | Required | Description | Default |
|---|---|---|---|
| seconds | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
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 clearly states that the tool blocks the MCP server and performs no browser action while waiting, which accurately conveys the side effect and limitation. It does not discuss edge cases like zero/negative values or cancellation, but the core behavior is well 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?
The description is concise and front-loaded: the core behavior appears in the first sentence, followed by usage context, the alternative, and parameter details. Every sentence contributes meaningful guidance without redundancy.
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 low-complexity tool with one required parameter, the description covers what the tool does, when to avoid it, what alternative to prefer, and what the parameter means. Since an output schema exists, return-value explanation is not required. No critical information 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 0%, so the description must explain the parameter. It adds meaning by stating that seconds is "Number of seconds to block" and clarifying that it may be an integer or float. It could explicitly state that the value must be non-negative, but the explanation is otherwise sufficient for this simple single-parameter tool.
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 opens with a precise verb and resource: "Block the MCP server for a fixed number of seconds." It clearly differentiates itself from the sibling wait_for by calling itself a low-level timing tool that performs no browser action.
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 when not to use it: "should not be used when waiting for a page condition." It also names the alternative, wait_for, and explains why wait_for is preferable for element/text conditions because it returns as soon as the condition is met.
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. Dates show when Glama detected each change.
10 tool updates
v4.53.7- Changed
assert_condition2 fields changed- removed
Input schema / properties / timeout / anyOfRemoved value: -[ - { - "type": "integer" - }, - { - "type": "number" - }, - { - "type": "null" - } -] - added
Input schema / properties / timeout / typeAdded value: +"number"
- Added
check_condition - Removed
check_for_condition - Changed
click2 fields changed- removed
Input schema / properties / timeout / anyOfRemoved value: -[ - { - "type": "integer" - }, - { - "type": "number" - }, - { - "type": "null" - } -] - added
Input schema / properties / timeout / typeAdded value: +"number"
- Changed
find_elements3 fields changed- removed
Input schema / properties / timeout / anyOfRemoved value: -[ - { - "type": "integer" - }, - { - "type": "number" - }, - { - "type": "null" - } -] - changed
Input schema / properties / timeout / defaultPrevious value: -7New value: +0.5 - added
Input schema / properties / timeout / typeAdded value: +"number"
- Added
manage_history - Removed
navigate_history - Changed
type_text2 fields changed- removed
Input schema / properties / timeout / anyOfRemoved value: -[ - { - "type": "integer" - }, - { - "type": "number" - }, - { - "type": "null" - } -] - added
Input schema / properties / timeout / typeAdded value: +"number"
- Changed
wait_for2 fields changed- removed
Input schema / properties / timeout / anyOfRemoved value: -[ - { - "type": "integer" - }, - { - "type": "number" - }, - { - "type": "null" - } -] - added
Input schema / properties / timeout / typeAdded value: +"number"
- Changed
wait_seconds2 fields changed- removed
Input schema / properties / seconds / anyOfRemoved value: -[ - { - "type": "integer" - }, - { - "type": "number" - } -] - added
Input schema / properties / seconds / typeAdded value: +"number"
2 tool updates
v4.53.6- Added
check_for_condition - Removed
check_state
4 tool updates
v4.53.5- Added
assert_condition - Removed
assert_that - Removed
fill_input - Added
type_text
5 tool updates
v4.53.4- Removed
act_on_element - Removed
drag_and_drop - Added
focus_on - Removed
hover - Added
hover_with_action
8 tool updates
v4.53.3- Added
act_on_element - Removed
browser_status - Removed
element_action - Removed
get_all_urls - Added
get_content - Removed
get_page_content - Removed
get_user_agent - Changed
start_browser3 fields changed- added
Input schema / properties / headless / anyOfAdded value: +[ + { + "type": "boolean" + }, + { + "type": "null" + } +] - changed
Input schema / properties / headless / defaultPrevious value: -falseNew value: +null - removed
Input schema / properties / headless / typeRemoved value: -"boolean"
7 tool updates
v4.53.2- Changed
assert_that1 field changed- changed
Input schema / properties / timeout / anyOfPrevious value: -[ - { - "type": "integer" - }, - { - "type": "null" - } -]New value: +[ + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "null" + } +]
- Changed
click1 field changed- changed
Input schema / properties / timeout / anyOfPrevious value: -[ - { - "type": "integer" - }, - { - "type": "null" - } -]New value: +[ + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "null" + } +]
- Changed
fill_input1 field changed- changed
Input schema / properties / timeout / anyOfPrevious value: -[ - { - "type": "integer" - }, - { - "type": "null" - } -]New value: +[ + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "null" + } +]
- Changed
find_elements1 field changed- changed
Input schema / properties / timeout / anyOfPrevious value: -[ - { - "type": "integer" - }, - { - "type": "null" - } -]New value: +[ + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "null" + } +]
- Changed
get_all_urls1 field changed- removed
Input schema / properties / absoluteRemoved value: -{ - "default": true, - "title": "Absolute", - "type": "boolean" -}
- Changed
wait_for1 field changed- changed
Input schema / properties / timeout / anyOfPrevious value: -[ - { - "type": "integer" - }, - { - "type": "null" - } -]New value: +[ + { + "type": "integer" + }, + { + "type": "number" + }, + { + "type": "null" + } +]
- Changed
wait_seconds2 fields changed- added
Input schema / properties / seconds / anyOfAdded value: +[ + { + "type": "integer" + }, + { + "type": "number" + } +] - removed
Input schema / properties / seconds / typeRemoved value: -"number"
96 tool updates
v1.0.1- Removed
assert_element - Removed
assert_element_visible - Removed
assert_exact_text - Removed
assert_text - Added
assert_that - Removed
assert_title - Removed
assert_url - Removed
assert_url_contains - Added
browser_status - Added
check_state - Removed
clear_cookies - Removed
clear_input - Changed
click5 fields changed- added
Input schema / properties / all_matchesAdded value: +{ + "default": false, + "title": "All Matches", + "type": "boolean" +} - added
Input schema / properties / nthAdded value: +{ + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Nth" +} - added
Input schema / properties / only_if_visibleAdded value: +{ + "default": false, + "title": "Only If Visible", + "type": "boolean" +} - added
Input schema / properties / parent_selectorAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Parent Selector" +} - changed
Input schema / properties / timeout / defaultPrevious value: -nullNew value: +7
- Removed
click_if_visible - Removed
click_link - Removed
click_nth_element - Removed
click_visible_elements - Removed
close_active_tab - Added
drag_and_drop - Added
element_action - Removed
evaluate - Added
fill_input - Removed
find_all_info - Removed
find_element_info - Added
find_elements - Removed
find_elements_count - Removed
focus - Removed
get_all_cookies - Added
get_attributes - Removed
get_current_url - Removed
get_element_attribute - Removed
get_element_attributes - Removed
get_element_html - Removed
get_html_source - Removed
get_local_storage_item - Removed
get_navigation_history - Removed
get_origin - Added
get_page_content - Added
get_page_info - Removed
get_session_storage_item - Removed
get_tabs_count - Removed
get_text - Removed
get_title - Removed
get_window_rect - Removed
go_back - Removed
go_forward - Removed
highlight - Added
hover - Removed
is_element_present - Removed
is_element_visible - Removed
is_text_visible - Removed
load_cookies - Added
manage_cookies - Added
manage_storage - Added
manage_tabs - Added
manage_window - Removed
maximize - Removed
minimize - Added
navigate_history - Removed
nested_click - Removed
open_new_tab - Removed
reload_page - Added
run_javascript - Removed
save_as_pdf - Removed
save_cookies - Added
save_output - Removed
save_page_source - Removed
save_screenshot - Added
scroll - Removed
scroll_down - Removed
scroll_into_view - Removed
scroll_to_bottom - Removed
scroll_to_top - Removed
scroll_up - Added
select_option - Removed
select_option_by_index - Removed
select_option_by_text - Removed
select_option_by_value - Removed
send_keys - Removed
set_local_storage_item - Removed
set_session_storage_item - Removed
set_value - Removed
set_window_rect - Removed
sleep - Changed
start_browser2 fields changed- added
Input schema / properties / browser_executable_pathAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Browser Executable Path" +} - added
Input schema / properties / use_chromiumAdded value: +{ + "default": false, + "title": "Use Chromium", + "type": "boolean" +}
- Removed
submit - Removed
switch_to_newest_tab - Removed
switch_to_tab - Removed
type_text - Added
wait_for - Removed
wait_for_element_absent - Removed
wait_for_element_not_visible - Removed
wait_for_element_present - Removed
wait_for_element_visible - Removed
wait_for_text - Added
wait_seconds
79 tool updates
v1.0.0- First observed
assert_element - First observed
assert_element_visible - First observed
assert_exact_text - First observed
assert_text - First observed
assert_title - First observed
assert_url - First observed
assert_url_contains - First observed
clear_cookies - First observed
clear_input - First observed
click - First observed
click_if_visible - First observed
click_link - First observed
click_nth_element - First observed
click_visible_elements - First observed
close_active_tab - First observed
close_browser - First observed
evaluate - First observed
find_all_info - First observed
find_element_info - First observed
find_elements_count - First observed
focus - First observed
get_all_cookies - First observed
get_all_urls - First observed
get_current_url - First observed
get_element_attribute - First observed
get_element_attributes - First observed
get_element_html - First observed
get_html_source - First observed
get_local_storage_item - First observed
get_navigation_history - First observed
get_origin - First observed
get_session_storage_item - First observed
get_tabs_count - First observed
get_text - First observed
get_title - First observed
get_user_agent - First observed
get_window_rect - First observed
go_back - First observed
go_forward - First observed
highlight - First observed
is_element_present - First observed
is_element_visible - First observed
is_text_visible - First observed
load_cookies - First observed
maximize - First observed
minimize - First observed
navigate - First observed
nested_click - First observed
open_new_tab - First observed
reload_page - First observed
save_as_pdf - First observed
save_cookies - First observed
save_page_source - First observed
save_screenshot - First observed
scroll_down - First observed
scroll_into_view - First observed
scroll_to_bottom - First observed
scroll_to_top - First observed
scroll_up - First observed
select_option_by_index - First observed
select_option_by_text - First observed
select_option_by_value - First observed
send_keys - First observed
set_local_storage_item - First observed
set_session_storage_item - First observed
set_value - First observed
set_window_rect - First observed
sleep - First observed
solve_captcha - First observed
start_browser - First observed
submit - First observed
switch_to_newest_tab - First observed
switch_to_tab - First observed
type_text - First observed
wait_for_element_absent - First observed
wait_for_element_not_visible - First observed
wait_for_element_present - First observed
wait_for_element_visible - First observed
wait_for_text
TDQS
Most tools target a distinct resource and action, and the embedded 'Tool selection' notes make even the read/state tools easy to route. A few pairs remain potential mix-upsāscroll vs focus_on(scroll_to_element), wait_for vs wait_seconds, and the check_state/wait_for/assert_that clusterāso the set is not completely ambiguity-free.
All names are lowercase snake_case imperative verbs, with clear get_*, manage_*, and navigate* families. Bare verbs like click/navigate/scroll and phrases like hover_with_action/wait_for/assert_that break the strict verb_noun pattern but remain predictable and readable.
25 tools sits in the heavy range for an MCP server; browser automation has wide scope, but several state/wait helpers and scroll-related actions could be consolidated. It is not chaotic, but the surface feels more like a full library than a lean tool set.
The domain is well covered: session lifecycle, navigation, content extraction, element interaction, state verification, cookies/storage, tabs, windows, output, and JavaScript execution are all present. Obvious gaps such as file upload or dedicated iframe switching are absent, but agents can work around them.
Maintenance
Related MCP Connectors
Crawl, scrape, search the web, and automate browsers at scale with anti-bot bypass.
AI-powered browser automation ā navigate, click, fill forms, and extract data from any website.
Stealth scraping & search. Bypasses Cloudflare, DataDome & LinkedIn via Cyborg HITL approach.
Automate cloud browsers to navigate websites, interact with elements, and extract structured data.ā¦
Related MCP Servers
- AlicenseAqualityDmaintenanceAn MCP service that automates Chrome browser control while bypassing anti-bot detection mechanisms, enabling web scraping, testing and automation on sites with sophisticated bot protection.1611MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server for stealth browser automation that uses human-like interaction patterns to bypass bot detection via the Chrome DevTools Protocol. It enables users to navigate, interact with elements, and capture data from websites using undetectable behaviors like Bezier mouse movements and Gaussian typing delays.1651MIT
- AlicenseNot gradedqualityBmaintenanceOpen-source browser automation API with anti-detection for AI agents, web scraping, and automation, providing undetectable Chrome via MCP and REST API with Cloudflare bypass.9MIT
- AlicenseAqualityDmaintenanceStealth browser automation for AI agents, using source-patched Chromium to bypass bot detection systems like Cloudflare, reCAPTCHA, and FingerprintJS.28Apache 2.0
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/seleniumbase/SeleniumBase'
If you have feedback or need assistance with the MCP directory API, please join our Discord server