From ec41b905a0202e13e9ed0b2f767cd755ea0f891c Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Sun, 13 Sep 2026 11:22:46 -0400 Subject: [PATCH 1/4] Update CDP Mode (add `timeout` to a few methods) --- help_docs/cdp_mode_methods.md | 4 ++-- mcp_servers/README.md | 32 ++++++++---------------------- seleniumbase/core/sb_cdp.py | 14 ++++++++----- seleniumbase/fixtures/base_case.py | 6 ++++-- 4 files changed, 23 insertions(+), 33 deletions(-) diff --git a/help_docs/cdp_mode_methods.md b/help_docs/cdp_mode_methods.md index f800533ea9e..95969664055 100644 --- a/help_docs/cdp_mode_methods.md +++ b/help_docs/cdp_mode_methods.md @@ -159,8 +159,8 @@ sb.gui_move_to_element(selector, timeframe=0.27) sb.gui_hover_x_y(x, y, timeframe=0.27) sb.gui_hover_element(selector, timeframe=0.27) sb.gui_hover_and_click(hover_selector, click_selector) -sb.hover_element(selector) -sb.hover_and_click(hover_selector, click_selector) +sb.hover_element(selector, timeout=None) +sb.hover_and_click(hover_selector, click_selector, timeout=None) sb.internalize_links() sb.is_checked(selector) sb.is_selected(selector) diff --git a/mcp_servers/README.md b/mcp_servers/README.md index d53fd96dbfa..66b022220eb 100644 --- a/mcp_servers/README.md +++ b/mcp_servers/README.md @@ -91,19 +91,19 @@ Restart Claude Desktop. You should see a 🔨 tools icon indicating the server c * `start_browser` * `close_browser` -* `goto_url` +* `open_url` * `manage_history` * `get_page_info` * `find_elements` * `get_content` * `get_attributes` -* `check_condition` +* `check_if_condition` * `click_element` * `hover_action` * `type_text` * `select_option` * `focus_element` -* `wait_for` +* `wait_for_condition` * `assert_condition` * `manage_cookies` * `manage_storage` @@ -156,15 +156,15 @@ Most tools accept a `selector` argument. Behavior varies slightly by tool, so ch ## Tools exposed -Tools here are grouped around a shared `selector` convention. Several near-identical one-off tools (e.g. separate click/hover/drag/wait/cookie/storage variants) have been consolidated into a single tool with a `mode`/`action`/`state`/`check` parameter, so there are fewer near-neighbor tools to disambiguate between while every underlying capability stays available. Tool names also follow a verb+object convention (`click_element`, `focus_element`, `scroll_page`, `save_page`, `goto_url`) rather than bare verbs, so a tool's name signals what it acts on without needing to read its description. +Tools here are grouped around a shared `selector` convention. Several near-identical one-off tools (e.g. separate click/hover/drag/wait/cookie/storage variants) have been consolidated into a single tool with a `mode`/`action`/`state`/`check` parameter, so there are fewer near-neighbor tools to disambiguate between while every underlying capability stays available. Tool names also follow a verb+object convention (`click_element`, `focus_element`, `scroll_page`, `save_page`, `open_url`) rather than bare verbs, so a tool's name signals what it acts on without needing to read its description. | Group | Tool(s) | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | Session | `start_browser(url, headless, use_chromium, browser_executable_path, incognito, guest, ad_block, proxy)`, `close_browser` | -| Navigation | `goto_url`, `manage_history(action: back/forward/reload/list)`, `get_page_info` (running status, url, title, origin, user agent in one call) | -| Finding & reading | `find_elements(selector, timeout, include_html)`, `get_content(selector, output_format: text/html/urls, timeout)`, `get_attributes(selector, attribute, timeout)`, `check_condition(check: present/visible, text)` | +| Navigation | `open_url`, `manage_history(action: back/forward/reload/list)`, `get_page_info` (running status, url, title, origin, user agent in one call) | +| Finding & reading | `find_elements(selector, timeout, include_html)`, `get_content(selector, output_format: text/html/urls, timeout)`, `get_attributes(selector, attribute, timeout)`, `check_if_condition(check: present/visible, text)` | | Interacting | `click_element(selector, nth, all_matches, only_if_visible, parent_selector, timeout, scroll)`, `hover_action(selector1, selector2, action: hover/hover_and_click/drag_and_drop)`, `type_text(mode: fill_input/append/fast_type/set_value/clear_only)`, `select_option(by: text/value/index)`, `focus_element(action: scroll_to_element/focus/highlight, timeout)` | -| Waiting | `wait_for(state: present/visible/not_visible/absent/seconds_passed, text)` | +| Waiting | `wait_for_condition(state: present/visible/not_visible/absent/seconds_passed, text)` | | Assertions | `assert_condition(check: element_present/element_visible/text_visible/title/url/url_contains)` | | Cookies & storage | `manage_cookies(action: get_all/clear/save/load)`, `manage_storage(storage: local/session, action: get/set)` | | Scrolling | `scroll_page(direction: up/down/top/bottom, amount)` | @@ -180,27 +180,11 @@ Tools here are grouped around a shared `selector` convention. Several near-ident - **`start_browser` retries once before failing.** If the first launch attempt raises, it's retried once automatically before returning an error. This was added after seeing occasional first-attempt failures when testing against Glama's MCP Inspector; it costs nothing on the common case where the first launch already succeeds. -- **Several tools were renamed from bare verbs to verb+object names.** `navigate` → `goto_url`, `click` → `click_element`, `focus` → `focus_element`, `scroll` → `scroll_page`, `save_output` → `save_page`. Behavior is unchanged in every case — these are pure renames for clarity, so a tool's name alone signals what it acts on (a page, an element, a URL) instead of reading as a generic action that could apply to anything. - - **Two error-handling paths, by design.** Most failures (a selector isn't found, an assertion fails, an invalid `action`/`mode`/`check` value is passed) are caught by the `handle_sb_errors` decorator and returned as a descriptive string, e.g. `Error in click_element: NoSuchElementException - ...`, so the calling agent can read the failure and self-correct. There's one deliberate exception: calling any tool other than `start_browser`/`close_browser` when no browser session is running raises `ToolError` (via the shared `_get_sb()` helper) instead of returning a string. `handle_sb_errors` explicitly re-raises `ToolError` rather than catching it, so this surfaces to the MCP client as a real tool-call error (`is_error=True`), not as ordinary text the agent has to pattern-match on. `start_browser` and `close_browser` handle their own lifecycle errors directly (e.g. "already running", a failed `quit()`) and also return strings rather than raising. -- **No standalone session-status tool.** There is no separate `browser_status`-style tool. `get_page_info` doubles as the status check: it returns `{"running": False}` (optionally with an `error` field) when there's no active session or the session errors out, and page metadata (`running: True`, `url`, `title`, `origin`, `user_agent`) otherwise. `get_page_info` does not include navigation history — that lives on `manage_history(action="list")` instead (see below). - -- **Navigation and history live in one tool: `manage_history`.** What used to be `navigate_history` is now `manage_history`, and it gained a fourth action: `"list"`, which returns the browser's navigation history as `{"position": <0-indexed current entry>, "entries": [...]}`, where each entry has `id`, `url`, `user_typed_url`, `title`, and `transition_type`. `"back"`, `"forward"`, and `"reload"` behave as before. This is the only way to retrieve navigation history now — `get_page_info` doesn't return it. Use `goto_url` for navigating to an arbitrary URL rather than moving through existing history. - -- **`get_content` always reads from an element, not the whole document.** `selector` now defaults to `"body"` rather than `None`/whole-page, and there's no `include_shadow_dom` option anymore — `get_content` no longer calls `get_page_source` at all. `output_format="html"` returns a single element's outer HTML (`get_element_html`), and `output_format="urls"` returns URLs discovered within that element (`get_all_urls(selector=...)`), rather than the full raw page source including shadow roots. If you need the complete page source (shadow DOM included), that capability isn't exposed by any tool here currently. `get_content` also gained a `timeout` parameter (default 5s) for waiting on the target element. - -- **`get_attributes` and `focus_element` now take a `timeout`.** Both default to 5 seconds and wait for the target element the same way most other interaction tools do; previously neither exposed a timeout. - -- **`check_condition` is deliberately narrow.** Its `check` parameter only accepts `"present"` or `"visible"` — there's no built-in `"count"` check anymore; call `find_elements` and read the returned `count` field instead. Passing `text` checks whether that text is visible within `selector` and takes priority over `check` when both are given — so `check_condition(text="Sign in")` behaves differently from `check_condition(check="visible")`, not as two variants of the same check. Note that an empty string for `text` (or for `wait_for`'s `selector`/`text`) is treated as not provided, since both tools now branch on truthiness rather than on `is not None`. - - **`find_elements` catches its own lookup failures.** Its default `timeout` is 0.5 seconds (not 5, unlike most other tools here). A failed or empty lookup never raises: no matches returns `{"count": 0, "matches": []}`, and an actual lookup error (e.g. an unsupported selector) returns `{"count": 0, "matches": [], "error": "
"}` — the error lives inside the returned dict rather than surfacing as a top-level string from `handle_sb_errors`. Pass a longer `timeout` explicitly if the elements you're looking for may still be loading. -- **`wait_seconds` was folded into `wait_for`.** There's no standalone `wait_seconds` tool anymore. Use `wait_for(state="seconds_passed", timeout=)` instead — it ignores `selector`/`text` and blocks for the full `timeout` duration. All other `wait_for` states behave as before. - -- **Hover, click-after-hover, and drag-and-drop share one tool.** `hover_action(selector1, selector2, action)` replaces the earlier separate `hover` and `drag_and_drop` tools. `action="hover"` (the default) hovers `selector1` only; `action="hover_and_click"` hovers `selector1` then clicks `selector2` (useful for dropdown/submenu items revealed by hovering); `action="drag_and_drop"` drags `selector1` onto `selector2`. (`selector2` is required when `action` is `"hover_and_click"` or `"drag_and_drop"`.) Note the action names themselves changed from an earlier `none`/`click`/`drag_and_drop` scheme — `"hover"` replaces `"none"` as the default/simple-hover value, and `"hover_and_click"` replaces the bare `"click"` to avoid confusion with the unrelated `click_element` tool. - -- **Non-activating element actions are `focus_element`.** What used to be `act_on_element` (then `focus`) is now `focus_element(selector, action, timeout)`, with actions `scroll_to_element` (the default), `focus`, and `highlight` — note the default action is scrolling the element into view, not focusing it. None of these actions click, type into, select from, or otherwise activate the element; use `click_element`, `type_text`, `select_option`, or `hover_action` for that. +- **Hover, hover-and-click, and drag-and-drop share one tool.** In `hover_action(selector1, selector2, action)`, `action="hover"` (the default) hovers `selector1` only; `action="hover_and_click"` hovers `selector1` then clicks `selector2` (useful for dropdown/submenu items revealed by hovering); `action="drag_and_drop"` drags `selector1` onto `selector2`. (`selector2` is required when `action` is `"hover_and_click"` or `"drag_and_drop"`.) - **`scroll_page`'s `amount` isn't capped at 100.** Relative up/down scrolling by more than 100% of the viewport height is allowed (e.g. `amount=200` scrolls roughly two viewport heights); negative amounts are rejected for `"up"`/`"down"`. diff --git a/seleniumbase/core/sb_cdp.py b/seleniumbase/core/sb_cdp.py index 8974d7902b9..dc671b70311 100644 --- a/seleniumbase/core/sb_cdp.py +++ b/seleniumbase/core/sb_cdp.py @@ -3034,8 +3034,10 @@ def gui_hover_element(self, selector, timeframe=0.27): self.__slow_mode_pause_if_set() self.loop.run_until_complete(self.page.wait(0.1)) - def hover_element(self, selector, timeframe=0.27): - element = self.select(selector) + def hover_element(self, selector, timeframe=0.27, timeout=None): + if not timeout: + timeout = settings.SMALL_TIMEOUT + element = self.select(selector, timeout=timeout) gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK) with gui_lock: self.bring_active_window_to_front() @@ -3043,11 +3045,13 @@ def hover_element(self, selector, timeframe=0.27): element.mouse_move() time.sleep(timeframe) - def hover_and_click(self, hover_selector, click_selector): + def hover_and_click(self, hover_selector, click_selector, timeout=None): + if not timeout: + timeout = settings.SMALL_TIMEOUT if getattr(sb_config, "_cdp_mobile_mode", None): - self.select(click_selector).click() + self.select(click_selector, timeout=timeout).click() return - hover_element = self.select(hover_selector) + hover_element = self.select(hover_selector, timeout=timeout) gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK) with gui_lock: self.bring_active_window_to_front() diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index 54a98d1a10b..84bbf203a1b 100644 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -2772,7 +2772,7 @@ def hover(self, selector, by="css selector", timeout=None): original_by = by selector, by = self.__recalculate_selector(selector, by) if self.__is_cdp_swap_needed(): - self.cdp.hover_element(selector) + self.cdp.hover_element(selector, timeout=timeout) return self.wait_for_element_visible( original_selector, by=original_by, timeout=timeout @@ -2817,7 +2817,9 @@ def hover_and_click( click_selector, click_by ) if self.__is_cdp_swap_needed(): - self.cdp.hover_and_click(hover_selector, click_selector) + self.cdp.hover_and_click( + hover_selector, click_selector, timeout=timeout + ) return dropdown_element = self.wait_for_element_visible( original_selector, by=original_by, timeout=timeout From eaef20040fe624f2b51e369e1ea8bf5c34bb4d9c Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Sun, 13 Sep 2026 11:28:28 -0400 Subject: [PATCH 2/4] Update the MCP Server --- mcp_servers/server.py | 145 ++++++++++++++++++++++++------------------ 1 file changed, 83 insertions(+), 62 deletions(-) diff --git a/mcp_servers/server.py b/mcp_servers/server.py index 6a355ade15d..2b2a63b4161 100644 --- a/mcp_servers/server.py +++ b/mcp_servers/server.py @@ -34,14 +34,15 @@ Tool-selection philosophy: - Use 'start_browser'/'close_browser' for opening/quitting the web browser. -- Use 'goto_url'/'manage_history' for browser navigation and history +- Use 'open_url'/'manage_history' for browser navigation and history inspection. - Use 'get_page_info' for reading browser/page metadata such as URL/title. - Use 'get_content'/'get_attributes' for reading text, HTML, or attributes. - Use 'find_elements' for discovering and inspecting multiple matching elements as structured data. -- Use 'check_condition' for an immediate, non-waiting state check. -- Use 'wait_for' when the agent needs to wait for a condition to become true. +- Use 'check_if_condition' for an immediate, non-waiting state check. +- Use 'wait_for_condition' when the agent needs to wait for a condition + to become true. - Use 'assert_condition' when the agent needs to verify an expected condition and treat failure as an assertion error. - Use 'click_element'/'type_text'/'select_option' for standard page @@ -111,7 +112,7 @@ def start_browser( ) -> str: """Launch a persistent SeleniumBase Pure CDP Mode browser session. - Call this before using browser interaction tools such as goto_url, + Call this before using browser interaction tools such as open_url, get_content, click_element, 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. @@ -303,8 +304,8 @@ def get_page_info() -> dict[str, Any]: - 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 an immediate state check -> use check_if_condition. + - Need to wait for a condition -> use wait_for_condition. - Need to verify an expected condition -> use assert_condition. Unlike a dedicated browser-status tool, get_page_info is the single @@ -338,8 +339,8 @@ def get_page_info() -> dict[str, Any]: @mcp.tool() @handle_sb_errors -def goto_url(url: str) -> str: - """Navigate the current browser tab to a URL. +def open_url(url: str) -> str: + """Navigate the current browser tab to the URL provided. Use this when the browser needs to visit a new URL rather than move through its existing back/forward history. @@ -350,17 +351,18 @@ def goto_url(url: str) -> str: Navigation waits for the browser's navigation operation to complete before returning. Dynamic content may still be loading; - use wait_for when synchronization is required. + use wait_for_condition when synchronization is required. + If there's an error, that gets propagated through @handle_sb_errors. Args: - url: Destination URL. May be a complete URL such as - "https://example.com" or a hostname such as "example.com". + url: The destination URL. May be a complete URL such as + "https://example.com", or a hostname such as "example.com". Returns: - A confirmation message containing the requested URL. + A confirmation message containing the requested URL if successful. Tool selection: - - Go to a new URL -> use goto_url. + - Navigate to a new URL -> use open_url. - Return to the previous page -> use manage_history(action="back"). - Go forward in history -> use manage_history(action="forward"). - Refresh the current page -> use manage_history(action="reload"). @@ -379,7 +381,7 @@ def manage_history( Use 'back' or 'forward' for history navigation, 'reload' to refresh while bypassing the cache, or 'list' to inspect history. - Use 'goto_url' for navigation to an arbitrary URL. + Use 'open_url' for navigation to an arbitrary URL. Args: action: @@ -477,7 +479,7 @@ def find_elements( use get_content. - Need to click one of several matches -> use click_element with nth. - Need to know whether an element is present/visible -> - use check_condition. + use check_if_condition. Notes: Element handles cannot be persisted across MCP calls. If you find @@ -542,8 +544,8 @@ def get_content( - Need visible text, html, or URLs on a page -> use get_content. - 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. + - Need to check element presence/visibility -> use check_if_condition. + - Need to wait for content to appear -> use wait_for_condition. If there's no matching element found within the timeout, then @handle_sb_errors returns details from the exception raised. @@ -592,7 +594,8 @@ def get_attributes( - 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'. + - Need to check element presence/visibility -> + use 'check_if_condition'. This is a read-only operation. @@ -609,7 +612,7 @@ def get_attributes( @mcp.tool() @handle_sb_errors -def check_condition( +def check_if_condition( check: Literal["present", "visible"] = "visible", selector: str = "body", text: str | None = None, @@ -618,9 +621,10 @@ def check_condition( 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. + page state. Use wait_for_condition 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: @@ -645,8 +649,8 @@ def check_condition( exception. If there's an error, returns a string with error details. Tool selection: - - Immediate boolean observation -> use check_condition. - - Wait for a state/content transition -> use wait_for. + - Immediate boolean observation -> use check_if_condition. + - Wait for a state/content transition -> use wait_for_condition. - Verify an expected condition -> use assert_condition. - Need element details of matching elements -> use find_elements. - Need to read page or element content -> use get_content. @@ -654,7 +658,7 @@ def check_condition( 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. + asynchronous loading matters, use wait_for_condition instead. When `text` is provided, `check` is ignored. """ @@ -709,7 +713,7 @@ def click_element( clicks; do not use them with `all_matches=True`. nth: 1-based occurrence to click when multiple elements match. - Must be >= 1. Takes precedence over `all_matches`, + Must be >= 1 if provided. Takes precedence over `all_matches`, `only_if_visible`, and `parent_selector`. all_matches: If True, click every currently visible matching element @@ -744,7 +748,7 @@ def click_element( """ sb = _get_sb() - if nth is not None: + if nth: if nth < 1: return "Error: nth must be >= 1." sb.click_nth_element(selector, nth, scroll=scroll) @@ -769,9 +773,10 @@ def click_element( @mcp.tool() @handle_sb_errors def hover_action( - selector1: str, - selector2: str | None = None, + selector: str, + secondary_selector: str | None = None, action: Literal["hover", "hover_and_click", "drag_and_drop"] = "hover", + timeout: float = 5, ) -> str: """Hover over an element, optionally click another, or drag-and-drop. @@ -779,51 +784,67 @@ def hover_action( drag-and-drop operations. Args: - selector1: + selector: The primary element selector. For action="hover", this is the element to hover over. For action="hover_and_click", this is the element to hover over - before clicking selector2. + before clicking 'secondary_selector'. For action="drag_and_drop", this is the draggable source element. - selector2: + secondary_selector: The secondary element selector. Required for action="hover_and_click", where it identifies - the element revealed or targeted after hovering selector1. + the element to click after hovering 'selector'. Required for action="drag_and_drop", where it identifies the destination/drop target. Not used for action="hover". action: - - "hover": Hover over selector1 only. - - "hover_and_click": Hover over selector1, then click selector2. - - "drag_and_drop": Drag selector1 and drop it onto selector2. + - "hover": Hover over 'selector' only. + - "hover_and_click": Hover over 'selector', then click + 'secondary_selector' after a short moment has passed. + - "drag_and_drop": Drag 'selector' and drop it onto + 'secondary_selector'. + + timeout: Maximum seconds to wait for 'selector'. + For drag_and_drop, the same timeout applies to secondary_selector. + For hover_and_click, SeleniumBase uses its own short wait for + secondary_selector; this parameter does not extend that secondary + wait. Returns: - A confirmation message describing the performed operation. + A confirmation message describing the performed operation's result. + + Errors: + If a required element cannot be found or interacted with within the + applicable wait period, or if an error occurs during the action, the + resulting exception message is returned through @handle_sb_errors. - Tool selection: - - Simple hover -> action="hover". - - Hover over one element and click another -> action="hover_and_click". - - Drag one element onto another -> action="drag_and_drop". """ sb = _get_sb() + if timeout < 0: + return "Error: timeout must be >= 0." + if action == "hover": - sb.hover_element(selector1) - return f"Hovered {selector1}" + sb.hover_element(selector, timeout=timeout) + return f"Hovered {selector}" if action == "hover_and_click": - if selector2 is None: - return "Error: action='click' requires selector2." - sb.hover_and_click(selector1, selector2) - return f"Hovered {selector1} and clicked {selector2}" + if not secondary_selector: + return ( + "Error: action='hover_and_click' requires secondary_selector." + ) + sb.hover_and_click(selector, secondary_selector, timeout=timeout) + return f"Hovered {selector} and clicked {secondary_selector}" if action == "drag_and_drop": - if selector2 is None: - return "Error: action='drag_and_drop' requires selector2." - sb.drag_and_drop(selector1, selector2) - return f"Dragged {selector1} onto {selector2}" + if not secondary_selector: + return ( + "Error: action='drag_and_drop' requires secondary_selector." + ) + sb.drag_and_drop(selector, secondary_selector, timeout=timeout) + return f"Dragged {selector} onto {secondary_selector}" return ( f"Error: unknown action '{action}'. " @@ -998,7 +1019,7 @@ def focus_element( @mcp.tool() @handle_sb_errors -def wait_for( +def wait_for_condition( state: Literal[ "present", "visible", @@ -1017,7 +1038,7 @@ def wait_for( condition is met or the timeout expires. It does not intentionally scroll, click, or otherwise modify the page while waiting. - Use check_condition to inspect the current state without waiting. + Use check_if_condition to inspect the current state without waiting. Use assert_condition to verify an expected condition rather than synchronize with a changing page. @@ -1056,8 +1077,8 @@ def wait_for( the tool returns the error produced by its error handler. Tool selection: - - Inspect current state immediately -> check_condition. - - Wait for a state change -> wait_for. + - Inspect current state immediately -> check_if_condition. + - Wait for a state change -> wait_for_condition. - Verify an expectation -> assert_condition. """ sb = _get_sb() @@ -1132,10 +1153,10 @@ def assert_condition( handled by `handle_sb_errors` and returned as a descriptive tool error; it is not reported as a successful result. - Unlike check_condition, this tool does not merely return whether a + Unlike check_if_condition, this tool does not merely return whether a condition is true: a failed expectation is an error. - Unlike wait_for, its purpose is to verify an expectation, not merely - synchronize with a changing page. + Unlike wait_for_condition, its purpose is to verify an expectation, + not merely synchronize with a changing page. Args: check: @@ -1169,8 +1190,8 @@ def assert_condition( instead of a success message. Tool selection: - - Inspect a condition without failing -> check_condition. - - Wait for a condition to become true -> wait_for. + - Inspect a condition without failing -> check_if_condition. + - Wait for a condition to become true -> wait_for_condition. - Verify that an expected condition is true -> assert_condition. """ sb = _get_sb() @@ -1499,7 +1520,7 @@ def manage_tabs( """Manage browser tabs, including opening new ones. Use this for listing, opening, switching, or closing tabs. - Use `goto_url` and `manage_history` for navigation within the active tab. + Use `open_url` and `manage_history` for navigation within the active tab. Args: action: @@ -1596,7 +1617,7 @@ def solve_captcha() -> str: 1. Inspect the webpage with get_content when you need to determine whether CAPTCHA-related controls are present. 2. Call solve_captcha to attempt the CAPTCHA interaction. - 3. Use get_page_info, get_content, check_condition, + 3. Use get_page_info, get_content, check_if_condition, or manage_cookies to inspect resulting page/session state. Returns: From 8945f2d745770ca06f316e990cd971e76476a1d1 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Sun, 13 Sep 2026 11:29:13 -0400 Subject: [PATCH 3/4] Refresh MCP Server versioning --- mcp_servers/pyproject.toml | 2 +- server.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mcp_servers/pyproject.toml b/mcp_servers/pyproject.toml index 8298c72f75c..01be6334101 100644 --- a/mcp_servers/pyproject.toml +++ b/mcp_servers/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "seleniumbase-mcp" -version = "1.3.3dev0" +version = "1.3.4dev0" description = "MCP server exposing SeleniumBase CDP Mode as tools for MCP clients." readme = "README.md" requires-python = ">=3.10" diff --git a/server.json b/server.json index 51c372fb632..0d8db97b280 100644 --- a/server.json +++ b/server.json @@ -3,7 +3,7 @@ "name": "io.github.seleniumbase/seleniumbase", "title": "SeleniumBase MCP", "description": "Stealthy browser automation, testing, and web-scraping via CDP Mode.", - "version": "4.54.3", + "version": "4.54.4", "repository": { "url": "https://github.com/seleniumbase/SeleniumBase", "source": "github" @@ -13,7 +13,7 @@ { "registryType": "pypi", "identifier": "seleniumbase", - "version": "4.54.3", + "version": "4.54.4", "transport": { "type": "stdio" }, From bc14832f52674fdf9ee574d87bd7b6fed6ae2f8e Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Sun, 13 Sep 2026 11:29:29 -0400 Subject: [PATCH 4/4] Version 4.54.4 --- seleniumbase/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index 12c552f43f0..664d528f8ef 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.54.3" +__version__ = "4.54.4"