seleniumbase-mcp 1.3.2__tar.gz → 1.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: seleniumbase-mcp
3
- Version: 1.3.2
3
+ Version: 1.3.4
4
4
  Summary: MCP servers exposing SeleniumBase as tools for MCP clients.
5
5
  Home-page: https://github.com/seleniumbase/seleniumbase-mcp
6
6
  Author: Michael Mintz
@@ -55,7 +55,7 @@ Classifier: Topic :: Utilities
55
55
  Requires-Python: >=3.10
56
56
  Description-Content-Type: text/markdown
57
57
  License-File: LICENSE
58
- Requires-Dist: seleniumbase[mcp]>=4.54.2
58
+ Requires-Dist: seleniumbase[mcp]>=4.54.4
59
59
  Requires-Dist: mcp[cli]<3.0.0,>=2.2.0
60
60
  Provides-Extra: deploy
61
61
  Requires-Dist: build>=1.0.0; extra == "deploy"
@@ -177,7 +177,7 @@ The location of `claude_desktop_config.json` depends on your system:
177
177
  - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
178
178
  - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
179
179
 
180
- Restart Claude Desktop. You should see a 🔨 tools icon indicating the server(s) connected, with tools like `start_browser`, `navigate`, `click`, etc. available. Only keep the entries you actually want. Three separate browser-automation servers is a lot if you only need one.
180
+ Restart Claude Desktop. You should see a 🔨 tools icon indicating the server(s) connected, with tools like `start_browser`, `open_url`, `click_element`, etc. available. Only keep the entries you actually want. Three separate browser-automation servers is a lot if you only need one.
181
181
 
182
182
  ## 4. Connect it to Claude Code
183
183
 
@@ -225,14 +225,14 @@ claude mcp add seleniumbase-sb -- uv run seleniumbase-sb
225
225
  |---|---|
226
226
  | `start_browser(browser, headless, uc, incognito)` | Launch a browser session (headless defaults to `False`) |
227
227
  | `close_browser()` | End the session |
228
- | `navigate(url)` | Go to a URL |
228
+ | `open_url(url)` | Go to a URL |
229
229
  | `go_back()` / `go_forward()` / `refresh_page()` | History navigation |
230
230
  | `get_current_url()` / `get_title()` | Page metadata |
231
231
  | `get_page_source()` | Full HTML |
232
232
  | `get_text(selector)` | Visible text of an element |
233
233
  | `find_elements_count(selector)` | Count matches |
234
234
  | `is_element_visible(selector)` | Visibility check |
235
- | `click(selector, timeout)` | Click (CSS or XPath) |
235
+ | `click_element(selector, timeout)` | Click (CSS or XPath) |
236
236
  | `type_text(selector, text, clear_first, timeout)` | Fill a field |
237
237
  | `select_option_by_text(dropdown_selector, option)` | Choose a dropdown option |
238
238
  | `wait_for_element_present(selector, timeout)` | Explicit wait |
@@ -279,16 +279,16 @@ in the loop at all. Reference:
279
279
  | Group | Tool(s) |
280
280
  | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
281
281
  | Session | `start_browser(url, headless, use_chromium, browser_executable_path, incognito, guest, ad_block, proxy)`, `close_browser` |
282
- | Navigation | `navigate`, `navigate_history(action: back/forward/reload)`, `get_page_info` (running status, url, title, origin, user agent, history in one call) |
283
- | Finding & reading | `find_elements(selector, timeout, include_html)`, `get_content(selector, output_format: text/html/urls, include_shadow_dom)`, `get_attributes`, `check_state(check: present/visible/count/text_visible)` |
284
- | Interacting | `click(selector, nth, all_matches, only_if_visible, parent_selector, timeout, scroll)`, `hover_action(selector1, selector2, action: none/click/drag_and_drop)`, `type_text(mode: fill_input/append/fast_type/set_value/clear_only)`, `select_option(by: text/value/index)`, `focus(action: scroll_to_element/focus/highlight)` |
285
- | Waiting | `wait_for(state: present/visible/not_visible/absent/seconds_passed, text)` |
282
+ | Navigation | `open_url`, `manage_history(action: back/forward/reload/list)`, `get_page_info` (running status, url, title, origin, user agent, history in one call) |
283
+ | Finding & reading | `find_elements(selector, timeout, include_html)`, `get_content(selector, output_format: text/html/urls)`, `get_attributes`, `check_for_condition(check: present/visible/count/text_visible)` |
284
+ | 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)` |
285
+ | Waiting | `wait_for_condition(state: present/visible/not_visible/absent/seconds_passed, text)` |
286
286
  | Assertions | `assert_condition(check: element_present/element_visible/text_visible/title/url/url_contains)` |
287
287
  | Cookies & storage | `manage_cookies(action: get_all/clear/save/load)`, `manage_storage(storage: local/session, action: get/set)` |
288
- | Scrolling | `scroll(direction: up/down/top/bottom, amount)` |
288
+ | Scrolling | `scroll_page(direction: up/down/top/bottom, amount)` |
289
289
  | Windows & tabs | `manage_window(action: get_rect/set_rect/maximize/minimize)`, `manage_tabs(action: list/open/switch/switch_newest/close_active)` |
290
290
  | Captcha | `solve_captcha` |
291
- | Output & misc | `save_output(format: screenshot/html/pdf)`, `run_javascript` |
291
+ | Output & misc | `save_page(format: screenshot/html/pdf)`, `run_javascript` |
292
292
 
293
293
  ### CDP-specific design notes
294
294
 
@@ -306,12 +306,6 @@ in the loop at all. Reference:
306
306
  - **Session teardown.** `sb.quit()` (used by `close_browser`) is the
307
307
  documented way to end a session; the browser also auto-closes if the
308
308
  process exits without it.
309
- - **Not wrapped:** PyAutoGUI-based `gui_*` methods (excluded by design —
310
- see the top-level design notes), low-level plumbing
311
- (`get_websocket_url`, `add_handler`, permission grants, raw
312
- `get_document`/`get_flattened_document`), and exact method aliases
313
- (`open`/`goto` vs `get`) were left out to keep the tool list focused —
314
- add them the same way as any other tool if you need them.
315
309
 
316
310
  ---
317
311
 
@@ -97,7 +97,7 @@ The location of `claude_desktop_config.json` depends on your system:
97
97
  - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
98
98
  - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
99
99
 
100
- Restart Claude Desktop. You should see a 🔨 tools icon indicating the server(s) connected, with tools like `start_browser`, `navigate`, `click`, etc. available. Only keep the entries you actually want. Three separate browser-automation servers is a lot if you only need one.
100
+ Restart Claude Desktop. You should see a 🔨 tools icon indicating the server(s) connected, with tools like `start_browser`, `open_url`, `click_element`, etc. available. Only keep the entries you actually want. Three separate browser-automation servers is a lot if you only need one.
101
101
 
102
102
  ## 4. Connect it to Claude Code
103
103
 
@@ -145,14 +145,14 @@ claude mcp add seleniumbase-sb -- uv run seleniumbase-sb
145
145
  |---|---|
146
146
  | `start_browser(browser, headless, uc, incognito)` | Launch a browser session (headless defaults to `False`) |
147
147
  | `close_browser()` | End the session |
148
- | `navigate(url)` | Go to a URL |
148
+ | `open_url(url)` | Go to a URL |
149
149
  | `go_back()` / `go_forward()` / `refresh_page()` | History navigation |
150
150
  | `get_current_url()` / `get_title()` | Page metadata |
151
151
  | `get_page_source()` | Full HTML |
152
152
  | `get_text(selector)` | Visible text of an element |
153
153
  | `find_elements_count(selector)` | Count matches |
154
154
  | `is_element_visible(selector)` | Visibility check |
155
- | `click(selector, timeout)` | Click (CSS or XPath) |
155
+ | `click_element(selector, timeout)` | Click (CSS or XPath) |
156
156
  | `type_text(selector, text, clear_first, timeout)` | Fill a field |
157
157
  | `select_option_by_text(dropdown_selector, option)` | Choose a dropdown option |
158
158
  | `wait_for_element_present(selector, timeout)` | Explicit wait |
@@ -199,16 +199,16 @@ in the loop at all. Reference:
199
199
  | Group | Tool(s) |
200
200
  | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
201
201
  | Session | `start_browser(url, headless, use_chromium, browser_executable_path, incognito, guest, ad_block, proxy)`, `close_browser` |
202
- | Navigation | `navigate`, `navigate_history(action: back/forward/reload)`, `get_page_info` (running status, url, title, origin, user agent, history in one call) |
203
- | Finding & reading | `find_elements(selector, timeout, include_html)`, `get_content(selector, output_format: text/html/urls, include_shadow_dom)`, `get_attributes`, `check_state(check: present/visible/count/text_visible)` |
204
- | Interacting | `click(selector, nth, all_matches, only_if_visible, parent_selector, timeout, scroll)`, `hover_action(selector1, selector2, action: none/click/drag_and_drop)`, `type_text(mode: fill_input/append/fast_type/set_value/clear_only)`, `select_option(by: text/value/index)`, `focus(action: scroll_to_element/focus/highlight)` |
205
- | Waiting | `wait_for(state: present/visible/not_visible/absent/seconds_passed, text)` |
202
+ | Navigation | `open_url`, `manage_history(action: back/forward/reload/list)`, `get_page_info` (running status, url, title, origin, user agent, history in one call) |
203
+ | Finding & reading | `find_elements(selector, timeout, include_html)`, `get_content(selector, output_format: text/html/urls)`, `get_attributes`, `check_for_condition(check: present/visible/count/text_visible)` |
204
+ | 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)` |
205
+ | Waiting | `wait_for_condition(state: present/visible/not_visible/absent/seconds_passed, text)` |
206
206
  | Assertions | `assert_condition(check: element_present/element_visible/text_visible/title/url/url_contains)` |
207
207
  | Cookies & storage | `manage_cookies(action: get_all/clear/save/load)`, `manage_storage(storage: local/session, action: get/set)` |
208
- | Scrolling | `scroll(direction: up/down/top/bottom, amount)` |
208
+ | Scrolling | `scroll_page(direction: up/down/top/bottom, amount)` |
209
209
  | Windows & tabs | `manage_window(action: get_rect/set_rect/maximize/minimize)`, `manage_tabs(action: list/open/switch/switch_newest/close_active)` |
210
210
  | Captcha | `solve_captcha` |
211
- | Output & misc | `save_output(format: screenshot/html/pdf)`, `run_javascript` |
211
+ | Output & misc | `save_page(format: screenshot/html/pdf)`, `run_javascript` |
212
212
 
213
213
  ### CDP-specific design notes
214
214
 
@@ -226,12 +226,6 @@ in the loop at all. Reference:
226
226
  - **Session teardown.** `sb.quit()` (used by `close_browser`) is the
227
227
  documented way to end a session; the browser also auto-closes if the
228
228
  process exits without it.
229
- - **Not wrapped:** PyAutoGUI-based `gui_*` methods (excluded by design —
230
- see the top-level design notes), low-level plumbing
231
- (`get_websocket_url`, `add_handler`, permission grants, raw
232
- `get_document`/`get_flattened_document`), and exact method aliases
233
- (`open`/`goto` vs `get`) were left out to keep the tool list focused —
234
- add them the same way as any other tool if you need them.
235
229
 
236
230
  ---
237
231
 
@@ -34,20 +34,23 @@ having to choose between multiple near-identical tools.
34
34
 
35
35
  Tool-selection philosophy:
36
36
  - Use 'start_browser'/'close_browser' for opening/quitting the web browser.
37
- - Use 'navigate'/'manage_history' for browser navigation & history inspection.
37
+ - Use 'open_url'/'manage_history' for browser navigation and history
38
+ inspection.
38
39
  - Use 'get_page_info' for reading browser/page metadata such as URL/title.
39
40
  - Use 'get_content'/'get_attributes' for reading text, HTML, or attributes.
40
41
  - Use 'find_elements' for discovering and inspecting multiple matching
41
42
  elements as structured data.
42
- - Use 'check_condition' for an immediate, non-waiting state check.
43
- - Use 'wait_for' when the agent needs to wait for a condition to become true.
43
+ - Use 'check_if_condition' for an immediate, non-waiting state check.
44
+ - Use 'wait_for_condition' when the agent needs to wait for a condition
45
+ to become true.
44
46
  - Use 'assert_condition' when the agent needs to verify an expected condition
45
47
  and treat failure as an assertion error.
46
- - Use 'click'/'type_text'/'select_option' for standard page interactions.
48
+ - Use 'click_element'/'type_text'/'select_option' for standard page
49
+ interactions.
47
50
  - Use 'hover_action' for just a hover, with a click, or with a drag/drop.
48
- - Use 'focus' for element positioning and visual focus.
51
+ - Use 'focus_element' for element positioning and visual focus.
49
52
  - Use 'solve_captcha' for clicking the checkbox of a CAPTCHA on the page.
50
- - Use 'save_output' for saving page output as a PNG, a PDF, or an HTML file.
53
+ - Use 'save_page' for saving page output as a PNG, a PDF, or an HTML file.
51
54
  """
52
55
  from __future__ import annotations
53
56
  import atexit
@@ -109,8 +112,8 @@ def start_browser(
109
112
  ) -> str:
110
113
  """Launch a persistent SeleniumBase Pure CDP Mode browser session.
111
114
 
112
- Call this before using browser interaction tools such as navigate,
113
- get_content, click, type_text, or find_elements. The same browser
115
+ Call this before using browser interaction tools such as open_url,
116
+ get_content, click_element, type_text, or find_elements. The same browser
114
117
  session remains active across subsequent MCP tool calls until
115
118
  close_browser is called or the server process exits.
116
119
 
@@ -301,8 +304,8 @@ def get_page_info() -> dict[str, Any]:
301
304
  - Need URL, title, origin, or User-Agent -> use get_page_info.
302
305
  - Need visible page text or HTML -> use get_content.
303
306
  - Need information about matching elements -> use find_elements.
304
- - Need an immediate state check -> use check_condition.
305
- - Need to wait for a condition -> use wait_for.
307
+ - Need an immediate state check -> use check_if_condition.
308
+ - Need to wait for a condition -> use wait_for_condition.
306
309
  - Need to verify an expected condition -> use assert_condition.
307
310
 
308
311
  Unlike a dedicated browser-status tool, get_page_info is the single
@@ -336,8 +339,8 @@ def get_page_info() -> dict[str, Any]:
336
339
 
337
340
  @mcp.tool()
338
341
  @handle_sb_errors
339
- def navigate(url: str) -> str:
340
- """Navigate the current browser tab to a URL.
342
+ def open_url(url: str) -> str:
343
+ """Navigate the current browser tab to the URL provided.
341
344
 
342
345
  Use this when the browser needs to visit a new URL rather than move
343
346
  through its existing back/forward history.
@@ -348,17 +351,18 @@ def navigate(url: str) -> str:
348
351
 
349
352
  Navigation waits for the browser's navigation operation to complete
350
353
  before returning. Dynamic content may still be loading;
351
- use wait_for when synchronization is required.
354
+ use wait_for_condition when synchronization is required.
355
+ If there's an error, that gets propagated through @handle_sb_errors.
352
356
 
353
357
  Args:
354
- url: Destination URL. May be a complete URL such as
355
- "https://example.com" or a hostname such as "example.com".
358
+ url: The destination URL. May be a complete URL such as
359
+ "https://example.com", or a hostname such as "example.com".
356
360
 
357
361
  Returns:
358
- A confirmation message containing the requested URL.
362
+ A confirmation message containing the requested URL if successful.
359
363
 
360
364
  Tool selection:
361
- - Go to a new URL -> use navigate.
365
+ - Navigate to a new URL -> use open_url.
362
366
  - Return to the previous page -> use manage_history(action="back").
363
367
  - Go forward in history -> use manage_history(action="forward").
364
368
  - Refresh the current page -> use manage_history(action="reload").
@@ -377,7 +381,7 @@ def manage_history(
377
381
 
378
382
  Use 'back' or 'forward' for history navigation, 'reload' to refresh
379
383
  while bypassing the cache, or 'list' to inspect history.
380
- Use 'navigate' for an arbitrary URL.
384
+ Use 'open_url' for navigation to an arbitrary URL.
381
385
 
382
386
  Args:
383
387
  action:
@@ -473,9 +477,9 @@ def find_elements(
473
477
  use find_elements.
474
478
  - Need the visible text/HTML of a page or a single element ->
475
479
  use get_content.
476
- - Need to click one of several matches -> use click with nth.
480
+ - Need to click one of several matches -> use click_element with nth.
477
481
  - Need to know whether an element is present/visible ->
478
- use check_condition.
482
+ use check_if_condition.
479
483
 
480
484
  Notes:
481
485
  Element handles cannot be persisted across MCP calls. If you find
@@ -524,6 +528,7 @@ def get_content(
524
528
 
525
529
  Args:
526
530
  selector: CSS selector or SeleniumBase-supported XPath selector.
531
+ Default: "body".
527
532
 
528
533
  output_format:
529
534
  - "text": Return visible text from the selected element.
@@ -532,18 +537,18 @@ def get_content(
532
537
  selected element. Returned URLs are normalized to full URLs
533
538
  with their protocol prefixes.
534
539
 
535
-
536
540
  timeout: Maximum seconds to wait for the target element. Default: 5.
537
541
 
538
542
  Tool selection:
539
543
  - Need URL, title, origin, or User-Agent -> use get_page_info.
540
- - Need visible text -> use output_format="text".
541
- - Need page or element HTML -> use output_format="html".
542
- - Need URLs from the page or an element -> use output_format="urls".
544
+ - Need visible text, html, or URLs on a page -> use get_content.
543
545
  - Need structured information about matching elements ->
544
546
  use find_elements.
545
- - Need to check element presence/visibility -> use check_condition.
546
- - Need to wait for content to appear -> use wait_for.
547
+ - Need to check element presence/visibility -> use check_if_condition.
548
+ - Need to wait for content to appear -> use wait_for_condition.
549
+
550
+ If there's no matching element found within the timeout,
551
+ then @handle_sb_errors returns details from the exception raised.
547
552
  """
548
553
  sb = _get_sb()
549
554
 
@@ -583,21 +588,19 @@ def get_attributes(
583
588
 
584
589
  timeout: Maximum seconds to wait for the target element. Default: 5.
585
590
 
586
- Returns:
587
- The requested attribute(s).
588
-
589
591
  Tool selection:
590
592
  - Need one or more HTML attribute values from a specific element ->
591
593
  use this tool.
592
594
  - Need to discover multiple matching elements or inspect their text ->
593
595
  use 'find_elements'.
594
596
  - Need visible text or HTML content -> use 'get_content'.
595
- - Need to check element presence/visibility -> use 'check_condition'.
597
+ - Need to check element presence/visibility ->
598
+ use 'check_if_condition'.
596
599
 
597
600
  This is a read-only operation.
598
601
 
599
602
  If there's no matching element found within the timeout,
600
- then @handle_sb_errors will return details from the exception raised.
603
+ then @handle_sb_errors returns details from the exception raised.
601
604
  """
602
605
  sb = _get_sb()
603
606
 
@@ -609,7 +612,7 @@ def get_attributes(
609
612
 
610
613
  @mcp.tool()
611
614
  @handle_sb_errors
612
- def check_condition(
615
+ def check_if_condition(
613
616
  check: Literal["present", "visible"] = "visible",
614
617
  selector: str = "body",
615
618
  text: str | None = None,
@@ -618,9 +621,10 @@ def check_condition(
618
621
  for the condition to become true.
619
622
 
620
623
  Use this tool when you need an immediate boolean observation of the current
621
- page state. Use wait_for when the condition may become true later and the
622
- workflow should wait for it. Use assert_condition when the condition is an
623
- expected requirement and failure should be treated as an assertion error.
624
+ page state. Use wait_for_condition when the condition may become true later
625
+ and the workflow should wait for it. Use assert_condition when the
626
+ condition is an expected requirement and failure should be treated as an
627
+ assertion error.
624
628
 
625
629
  Args:
626
630
  check:
@@ -645,8 +649,8 @@ def check_condition(
645
649
  exception. If there's an error, returns a string with error details.
646
650
 
647
651
  Tool selection:
648
- - Immediate boolean observation -> use check_condition.
649
- - Wait for a state/content transition -> use wait_for.
652
+ - Immediate boolean observation -> use check_if_condition.
653
+ - Wait for a state/content transition -> use wait_for_condition.
650
654
  - Verify an expected condition -> use assert_condition.
651
655
  - Need element details of matching elements -> use find_elements.
652
656
  - Need to read page or element content -> use get_content.
@@ -654,7 +658,7 @@ def check_condition(
654
658
  Notes:
655
659
  This tool does not intentionally wait for elements or text to appear.
656
660
  It is intended for checking the current state only. If page timing or
657
- asynchronous loading matters, use wait_for instead.
661
+ asynchronous loading matters, use wait_for_condition instead.
658
662
 
659
663
  When `text` is provided, `check` is ignored.
660
664
  """
@@ -680,7 +684,7 @@ def check_condition(
680
684
 
681
685
  @mcp.tool()
682
686
  @handle_sb_errors
683
- def click(
687
+ def click_element(
684
688
  selector: str,
685
689
  nth: int | None = None,
686
690
  all_matches: bool = False,
@@ -709,7 +713,7 @@ def click(
709
713
  clicks; do not use them with `all_matches=True`.
710
714
 
711
715
  nth: 1-based occurrence to click when multiple elements match.
712
- Must be >= 1. Takes precedence over `all_matches`,
716
+ Must be >= 1 if provided. Takes precedence over `all_matches`,
713
717
  `only_if_visible`, and `parent_selector`.
714
718
 
715
719
  all_matches: If True, click every currently visible matching element
@@ -733,15 +737,18 @@ def click(
733
737
  indexed click. Default: True.
734
738
 
735
739
  Examples:
736
- - Click one element: `click("button.submit")`
737
- - Click the 2nd matching element: `click("button", nth=2)`
738
- - Click all visible matches: `click(".dismiss", all_matches=True)`
739
- - Click only if already visible: `click("#menu", only_if_visible=True)`
740
- - Click inside a container: `click(".item", parent_selector="#result")`
740
+ - Click one element: `click_element("button.submit")`
741
+ - Click the 2nd matching element: `click_element("button", nth=2)`
742
+ - Click all visible matches:
743
+ `click_element(".dismiss", all_matches=True)`
744
+ - Click only if already visible:
745
+ `click_element("#menu", only_if_visible=True)`
746
+ - Click inside a container:
747
+ `click_element(".item", parent_selector="#result")`
741
748
  """
742
749
  sb = _get_sb()
743
750
 
744
- if nth is not None:
751
+ if nth:
745
752
  if nth < 1:
746
753
  return "Error: nth must be >= 1."
747
754
  sb.click_nth_element(selector, nth, scroll=scroll)
@@ -766,13 +773,10 @@ def click(
766
773
  @mcp.tool()
767
774
  @handle_sb_errors
768
775
  def hover_action(
769
- selector1: str,
770
- selector2: str | None = None,
771
- action: Literal[
772
- "none",
773
- "click",
774
- "drag_and_drop",
775
- ] = "none",
776
+ selector: str,
777
+ secondary_selector: str | None = None,
778
+ action: Literal["hover", "hover_and_click", "drag_and_drop"] = "hover",
779
+ timeout: float = 5,
776
780
  ) -> str:
777
781
  """Hover over an element, optionally click another, or drag-and-drop.
778
782
 
@@ -780,62 +784,71 @@ def hover_action(
780
784
  drag-and-drop operations.
781
785
 
782
786
  Args:
783
- selector1:
787
+ selector:
784
788
  The primary element selector.
785
- For action="none", this is the element to hover over.
786
- For action="click", this is the element to hover over before
787
- clicking selector2.
789
+ For action="hover", this is the element to hover over.
790
+ For action="hover_and_click", this is the element to hover over
791
+ before clicking 'secondary_selector'.
788
792
  For action="drag_and_drop", this is the draggable source element.
789
793
 
790
- selector2:
794
+ secondary_selector:
791
795
  The secondary element selector.
792
- Required for action="click", where it identifies the element
793
- revealed or targeted after hovering selector1.
796
+ Required for action="hover_and_click", where it identifies
797
+ the element to click after hovering 'selector'.
794
798
  Required for action="drag_and_drop", where it identifies the
795
799
  destination/drop target.
796
- Not used for action="none".
800
+ Not used for action="hover".
797
801
 
798
802
  action:
799
- - "none": Hover over selector1 only.
800
- - "click": Hover over selector1, then click selector2.
801
- - "drag_and_drop": Drag selector1 and drop it onto selector2.
803
+ - "hover": Hover over 'selector' only.
804
+ - "hover_and_click": Hover over 'selector', then click
805
+ 'secondary_selector' after a short moment has passed.
806
+ - "drag_and_drop": Drag 'selector' and drop it onto
807
+ 'secondary_selector'.
808
+
809
+ timeout: Maximum seconds to wait for 'selector'.
810
+ For drag_and_drop, the same timeout applies to secondary_selector.
811
+ For hover_and_click, SeleniumBase uses its own short wait for
812
+ secondary_selector; this parameter does not extend that secondary
813
+ wait.
802
814
 
803
815
  Returns:
804
- A confirmation message describing the performed operation.
805
-
806
- Tool selection:
807
- - Simple hover -> action="none".
808
- - Hover over one element and then click another -> action="click".
809
- - Drag one element onto another -> action="drag_and_drop".
816
+ A confirmation message describing the performed operation's result.
810
817
 
811
- Notes:
812
- For action="click", selector1 is the hover target and selector2 is
813
- the click target.
818
+ Errors:
819
+ If a required element cannot be found or interacted with within the
820
+ applicable wait period, or if an error occurs during the action, the
821
+ resulting exception message is returned through @handle_sb_errors.
814
822
 
815
- For action="drag_and_drop", selector1 is the source and selector2
816
- is the destination.
817
823
  """
818
824
  sb = _get_sb()
819
825
 
820
- if action == "none":
821
- sb.hover_element(selector1)
822
- return f"Hovered {selector1}"
826
+ if timeout < 0:
827
+ return "Error: timeout must be >= 0."
828
+
829
+ if action == "hover":
830
+ sb.hover_element(selector, timeout=timeout)
831
+ return f"Hovered {selector}"
823
832
 
824
- if action == "click":
825
- if selector2 is None:
826
- return "Error: action='click' requires selector2."
827
- sb.hover_and_click(selector1, selector2)
828
- return f"Hovered {selector1} and clicked {selector2}"
833
+ if action == "hover_and_click":
834
+ if not secondary_selector:
835
+ return (
836
+ "Error: action='hover_and_click' requires secondary_selector."
837
+ )
838
+ sb.hover_and_click(selector, secondary_selector, timeout=timeout)
839
+ return f"Hovered {selector} and clicked {secondary_selector}"
829
840
 
830
841
  if action == "drag_and_drop":
831
- if selector2 is None:
832
- return "Error: action='drag_and_drop' requires selector2."
833
- sb.drag_and_drop(selector1, selector2)
834
- return f"Dragged {selector1} onto {selector2}"
842
+ if not secondary_selector:
843
+ return (
844
+ "Error: action='drag_and_drop' requires secondary_selector."
845
+ )
846
+ sb.drag_and_drop(selector, secondary_selector, timeout=timeout)
847
+ return f"Dragged {selector} onto {secondary_selector}"
835
848
 
836
849
  return (
837
850
  f"Error: unknown action '{action}'. "
838
- "Use 'none', 'click', or 'drag_and_drop'."
851
+ "Use 'hover', 'hover_and_click', or 'drag_and_drop'."
839
852
  )
840
853
 
841
854
 
@@ -934,8 +947,8 @@ def select_option(
934
947
  An error when the dropdown or requested option cannot be found.
935
948
 
936
949
  This tool is for native <select> elements. For custom JavaScript
937
- dropdowns made from div/button/list elements, use click or other
938
- element-interaction tools instead.
950
+ dropdowns made from div/button/list elements, use click_element
951
+ or other element-interaction tools instead.
939
952
  """
940
953
  sb = _get_sb()
941
954
 
@@ -953,7 +966,7 @@ def select_option(
953
966
 
954
967
  @mcp.tool()
955
968
  @handle_sb_errors
956
- def focus(
969
+ def focus_element(
957
970
  selector: str,
958
971
  action: Literal[
959
972
  "scroll_to_element",
@@ -965,7 +978,8 @@ def focus(
965
978
  """Scroll to, focus, or highlight an element.
966
979
 
967
980
  This tool does not click, type, select, hover, or otherwise activate the
968
- element. Use `click`, `type_text`, or `hover_action` for those operations.
981
+ element. Use `click_element`, `type_text`, or `hover_action` for those
982
+ operations.
969
983
 
970
984
  Args:
971
985
  selector: CSS selector or SeleniumBase selector identifying the target.
@@ -980,7 +994,7 @@ def focus(
980
994
  timeout: Maximum seconds to wait for the target element. Default: 5.
981
995
 
982
996
  If there's no matching element found within the timeout,
983
- then @handle_sb_errors will return details from the exception raised.
997
+ then @handle_sb_errors returns details from the exception raised.
984
998
  """
985
999
  sb = _get_sb()
986
1000
 
@@ -1005,7 +1019,7 @@ def focus(
1005
1019
 
1006
1020
  @mcp.tool()
1007
1021
  @handle_sb_errors
1008
- def wait_for(
1022
+ def wait_for_condition(
1009
1023
  state: Literal[
1010
1024
  "present",
1011
1025
  "visible",
@@ -1024,7 +1038,7 @@ def wait_for(
1024
1038
  condition is met or the timeout expires. It does not intentionally scroll,
1025
1039
  click, or otherwise modify the page while waiting.
1026
1040
 
1027
- Use check_condition to inspect the current state without waiting.
1041
+ Use check_if_condition to inspect the current state without waiting.
1028
1042
  Use assert_condition to verify an expected condition rather than
1029
1043
  synchronize with a changing page.
1030
1044
 
@@ -1063,8 +1077,8 @@ def wait_for(
1063
1077
  the tool returns the error produced by its error handler.
1064
1078
 
1065
1079
  Tool selection:
1066
- - Inspect current state immediately -> check_condition.
1067
- - Wait for a state change -> wait_for.
1080
+ - Inspect current state immediately -> check_if_condition.
1081
+ - Wait for a state change -> wait_for_condition.
1068
1082
  - Verify an expectation -> assert_condition.
1069
1083
  """
1070
1084
  sb = _get_sb()
@@ -1139,10 +1153,10 @@ def assert_condition(
1139
1153
  handled by `handle_sb_errors` and returned as a descriptive tool error;
1140
1154
  it is not reported as a successful result.
1141
1155
 
1142
- Unlike check_condition, this tool does not merely return whether a
1156
+ Unlike check_if_condition, this tool does not merely return whether a
1143
1157
  condition is true: a failed expectation is an error.
1144
- Unlike wait_for, its purpose is to verify an expectation, not merely
1145
- synchronize with a changing page.
1158
+ Unlike wait_for_condition, its purpose is to verify an expectation,
1159
+ not merely synchronize with a changing page.
1146
1160
 
1147
1161
  Args:
1148
1162
  check:
@@ -1176,8 +1190,8 @@ def assert_condition(
1176
1190
  instead of a success message.
1177
1191
 
1178
1192
  Tool selection:
1179
- - Inspect a condition without failing -> check_condition.
1180
- - Wait for a condition to become true -> wait_for.
1193
+ - Inspect a condition without failing -> check_if_condition.
1194
+ - Wait for a condition to become true -> wait_for_condition.
1181
1195
  - Verify that an expected condition is true -> assert_condition.
1182
1196
  """
1183
1197
  sb = _get_sb()
@@ -1379,7 +1393,7 @@ def manage_storage(
1379
1393
 
1380
1394
  @mcp.tool()
1381
1395
  @handle_sb_errors
1382
- def scroll(
1396
+ def scroll_page(
1383
1397
  direction: Literal["up", "down", "top", "bottom"] = "down",
1384
1398
  amount: int = 25,
1385
1399
  ) -> str:
@@ -1399,8 +1413,8 @@ def scroll(
1399
1413
  Values greater than 100 for `amount` are allowed.
1400
1414
  For example, 200 means approximately two viewport heights.
1401
1415
 
1402
- Use focus(action="scroll_to_element") when the goal is to reveal a
1403
- specific element rather than scroll the page by a relative amount.
1416
+ Use focus_element(action="scroll_to_element") when the goal is to reveal
1417
+ a specific element rather than scroll the page by a relative amount.
1404
1418
  """
1405
1419
  sb = _get_sb()
1406
1420
 
@@ -1506,7 +1520,7 @@ def manage_tabs(
1506
1520
  """Manage browser tabs, including opening new ones.
1507
1521
 
1508
1522
  Use this for listing, opening, switching, or closing tabs.
1509
- Use `navigate` and `manage_history` for navigation within the active tab.
1523
+ Use `open_url` and `manage_history` for navigation within the active tab.
1510
1524
 
1511
1525
  Args:
1512
1526
  action:
@@ -1603,7 +1617,7 @@ def solve_captcha() -> str:
1603
1617
  1. Inspect the webpage with get_content when you need to
1604
1618
  determine whether CAPTCHA-related controls are present.
1605
1619
  2. Call solve_captcha to attempt the CAPTCHA interaction.
1606
- 3. Use get_page_info, get_content, check_condition,
1620
+ 3. Use get_page_info, get_content, check_if_condition,
1607
1621
  or manage_cookies to inspect resulting page/session state.
1608
1622
 
1609
1623
  Returns:
@@ -1621,7 +1635,7 @@ def solve_captcha() -> str:
1621
1635
 
1622
1636
  @mcp.tool()
1623
1637
  @handle_sb_errors
1624
- def save_output(
1638
+ def save_page(
1625
1639
  format: Literal["screenshot", "html", "pdf"] = "screenshot",
1626
1640
  filename: str | None = None,
1627
1641
  folder: str | None = None,
@@ -1673,7 +1687,7 @@ def save_output(
1673
1687
  - Do not use this tool when you only need page metadata such as the
1674
1688
  URL or title; use get_page_info instead.
1675
1689
  - Do not use this tool to manipulate the page; use the appropriate
1676
- interaction tool such as click, type_text, or select_option.
1690
+ interaction tool such as click_element, type_text, or select_option.
1677
1691
 
1678
1692
  Returns:
1679
1693
  A confirmation message containing the requested output format and
@@ -1713,9 +1727,9 @@ def run_javascript(expression: str) -> Any:
1713
1727
  and other same-origin page resources available to JavaScript.
1714
1728
 
1715
1729
  Tool selection:
1716
- - Prefer click, type_text, select_option, hover_action,
1717
- focus, scroll, and other higher-level tools for normal browser
1718
- interactions.
1730
+ - Prefer click_element, type_text, select_option, hover_action,
1731
+ focus_element, scroll_page, and other higher-level tools for normal
1732
+ browser interactions.
1719
1733
  - Prefer get_content, get_attributes, and find_elements for reading
1720
1734
  page content or element information.
1721
1735
  - Prefer manage_storage for ordinary localStorage/sessionStorage
@@ -139,7 +139,7 @@ def close_browser() -> str:
139
139
 
140
140
  @mcp.tool()
141
141
  @handle_sb_errors
142
- def navigate(url: str) -> str:
142
+ def open_url(url: str) -> str:
143
143
  """Navigate to the given URL in the web browser.
144
144
  If the URL doesn't start with a protocol (eg: `https://`),
145
145
  then `https://` is automatically prefixed in before navigation.
@@ -232,7 +232,7 @@ def is_element_visible(selector: str) -> bool:
232
232
 
233
233
  @mcp.tool()
234
234
  @handle_sb_errors
235
- def click(selector: str, timeout: float = 7) -> str:
235
+ def click_element(selector: str, timeout: float = 7) -> str:
236
236
  """Click an element matched by the given selector.
237
237
  Raises an exception if the element isn't found within the timeout."""
238
238
  d = _get_driver()
@@ -193,7 +193,7 @@ def page_snapshot() -> dict:
193
193
 
194
194
  @mcp.tool()
195
195
  @handle_sb_errors
196
- def navigate(url: str) -> str:
196
+ def open_url(url: str) -> str:
197
197
  """Navigate to the given URL in the web browser.
198
198
  If the URL doesn't start with a protocol (eg: `https://`),
199
199
  then `https://` is automatically prefixed in before navigation.
@@ -342,10 +342,7 @@ def is_selected(selector: str) -> bool | str:
342
342
 
343
343
  @mcp.tool()
344
344
  @handle_sb_errors
345
- def click(
346
- selector: str,
347
- timeout: float = 7,
348
- ) -> str:
345
+ def click_element(selector: str, timeout: float = 7) -> str:
349
346
  """Click an element matched by the given CSS selector.
350
347
  Raises an exception if the element isn't found within the timeout."""
351
348
  _get_sb().click(selector, timeout=timeout)
@@ -391,10 +388,7 @@ def click_link(link_text: str) -> str:
391
388
 
392
389
  @mcp.tool()
393
390
  @handle_sb_errors
394
- def double_click(
395
- selector: str,
396
- timeout: float = 7,
397
- ) -> str:
391
+ def double_click(selector: str, timeout: float = 7) -> str:
398
392
  """Double-click an element.
399
393
  Raises an exception if the element isn't found within the default timeout.
400
394
  """
@@ -439,11 +433,7 @@ def type_text(
439
433
 
440
434
  @mcp.tool()
441
435
  @handle_sb_errors
442
- def set_value(
443
- selector: str,
444
- text: str,
445
- timeout: float = 7,
446
- ) -> str:
436
+ def set_value(selector: str, text: str, timeout: float = 7) -> str:
447
437
  """Set an input's value directly (e.g. for sliders, fast form fills).
448
438
  Raises an exception if the element isn't found within the timeout.
449
439
  """
@@ -453,10 +443,7 @@ def set_value(
453
443
 
454
444
  @mcp.tool()
455
445
  @handle_sb_errors
456
- def clear_input(
457
- selector: str,
458
- timeout: float = 7,
459
- ) -> str:
446
+ def clear_input(selector: str, timeout: float = 7) -> str:
460
447
  """Clear an input field.
461
448
  Raises an exception if the element isn't found within the timeout.
462
449
  """
@@ -466,10 +453,7 @@ def clear_input(
466
453
 
467
454
  @mcp.tool()
468
455
  @handle_sb_errors
469
- def submit(
470
- selector: str,
471
- timeout: float = 7,
472
- ) -> str:
456
+ def submit(selector: str, timeout: float = 7) -> str:
473
457
  """Submit a form via a selector inside it.
474
458
  Raises an exception if the element isn't found within the timeout.
475
459
  """
@@ -560,11 +544,7 @@ def nested_click(parent_selector: str, selector: str) -> str:
560
544
 
561
545
  @mcp.tool()
562
546
  @handle_sb_errors
563
- def choose_file(
564
- selector: str,
565
- file_path: str,
566
- timeout: float = 7,
567
- ) -> str:
547
+ def choose_file(selector: str, file_path: str, timeout: float = 7) -> str:
568
548
  """Set a <input type="file"> element to upload a local file."""
569
549
  _get_sb().choose_file(selector, file_path, timeout=timeout)
570
550
  return f"Set file input {selector} to {file_path}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: seleniumbase-mcp
3
- Version: 1.3.2
3
+ Version: 1.3.4
4
4
  Summary: MCP servers exposing SeleniumBase as tools for MCP clients.
5
5
  Home-page: https://github.com/seleniumbase/seleniumbase-mcp
6
6
  Author: Michael Mintz
@@ -55,7 +55,7 @@ Classifier: Topic :: Utilities
55
55
  Requires-Python: >=3.10
56
56
  Description-Content-Type: text/markdown
57
57
  License-File: LICENSE
58
- Requires-Dist: seleniumbase[mcp]>=4.54.2
58
+ Requires-Dist: seleniumbase[mcp]>=4.54.4
59
59
  Requires-Dist: mcp[cli]<3.0.0,>=2.2.0
60
60
  Provides-Extra: deploy
61
61
  Requires-Dist: build>=1.0.0; extra == "deploy"
@@ -177,7 +177,7 @@ The location of `claude_desktop_config.json` depends on your system:
177
177
  - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
178
178
  - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
179
179
 
180
- Restart Claude Desktop. You should see a 🔨 tools icon indicating the server(s) connected, with tools like `start_browser`, `navigate`, `click`, etc. available. Only keep the entries you actually want. Three separate browser-automation servers is a lot if you only need one.
180
+ Restart Claude Desktop. You should see a 🔨 tools icon indicating the server(s) connected, with tools like `start_browser`, `open_url`, `click_element`, etc. available. Only keep the entries you actually want. Three separate browser-automation servers is a lot if you only need one.
181
181
 
182
182
  ## 4. Connect it to Claude Code
183
183
 
@@ -225,14 +225,14 @@ claude mcp add seleniumbase-sb -- uv run seleniumbase-sb
225
225
  |---|---|
226
226
  | `start_browser(browser, headless, uc, incognito)` | Launch a browser session (headless defaults to `False`) |
227
227
  | `close_browser()` | End the session |
228
- | `navigate(url)` | Go to a URL |
228
+ | `open_url(url)` | Go to a URL |
229
229
  | `go_back()` / `go_forward()` / `refresh_page()` | History navigation |
230
230
  | `get_current_url()` / `get_title()` | Page metadata |
231
231
  | `get_page_source()` | Full HTML |
232
232
  | `get_text(selector)` | Visible text of an element |
233
233
  | `find_elements_count(selector)` | Count matches |
234
234
  | `is_element_visible(selector)` | Visibility check |
235
- | `click(selector, timeout)` | Click (CSS or XPath) |
235
+ | `click_element(selector, timeout)` | Click (CSS or XPath) |
236
236
  | `type_text(selector, text, clear_first, timeout)` | Fill a field |
237
237
  | `select_option_by_text(dropdown_selector, option)` | Choose a dropdown option |
238
238
  | `wait_for_element_present(selector, timeout)` | Explicit wait |
@@ -279,16 +279,16 @@ in the loop at all. Reference:
279
279
  | Group | Tool(s) |
280
280
  | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
281
281
  | Session | `start_browser(url, headless, use_chromium, browser_executable_path, incognito, guest, ad_block, proxy)`, `close_browser` |
282
- | Navigation | `navigate`, `navigate_history(action: back/forward/reload)`, `get_page_info` (running status, url, title, origin, user agent, history in one call) |
283
- | Finding & reading | `find_elements(selector, timeout, include_html)`, `get_content(selector, output_format: text/html/urls, include_shadow_dom)`, `get_attributes`, `check_state(check: present/visible/count/text_visible)` |
284
- | Interacting | `click(selector, nth, all_matches, only_if_visible, parent_selector, timeout, scroll)`, `hover_action(selector1, selector2, action: none/click/drag_and_drop)`, `type_text(mode: fill_input/append/fast_type/set_value/clear_only)`, `select_option(by: text/value/index)`, `focus(action: scroll_to_element/focus/highlight)` |
285
- | Waiting | `wait_for(state: present/visible/not_visible/absent/seconds_passed, text)` |
282
+ | Navigation | `open_url`, `manage_history(action: back/forward/reload/list)`, `get_page_info` (running status, url, title, origin, user agent, history in one call) |
283
+ | Finding & reading | `find_elements(selector, timeout, include_html)`, `get_content(selector, output_format: text/html/urls)`, `get_attributes`, `check_for_condition(check: present/visible/count/text_visible)` |
284
+ | 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)` |
285
+ | Waiting | `wait_for_condition(state: present/visible/not_visible/absent/seconds_passed, text)` |
286
286
  | Assertions | `assert_condition(check: element_present/element_visible/text_visible/title/url/url_contains)` |
287
287
  | Cookies & storage | `manage_cookies(action: get_all/clear/save/load)`, `manage_storage(storage: local/session, action: get/set)` |
288
- | Scrolling | `scroll(direction: up/down/top/bottom, amount)` |
288
+ | Scrolling | `scroll_page(direction: up/down/top/bottom, amount)` |
289
289
  | Windows & tabs | `manage_window(action: get_rect/set_rect/maximize/minimize)`, `manage_tabs(action: list/open/switch/switch_newest/close_active)` |
290
290
  | Captcha | `solve_captcha` |
291
- | Output & misc | `save_output(format: screenshot/html/pdf)`, `run_javascript` |
291
+ | Output & misc | `save_page(format: screenshot/html/pdf)`, `run_javascript` |
292
292
 
293
293
  ### CDP-specific design notes
294
294
 
@@ -306,12 +306,6 @@ in the loop at all. Reference:
306
306
  - **Session teardown.** `sb.quit()` (used by `close_browser`) is the
307
307
  documented way to end a session; the browser also auto-closes if the
308
308
  process exits without it.
309
- - **Not wrapped:** PyAutoGUI-based `gui_*` methods (excluded by design —
310
- see the top-level design notes), low-level plumbing
311
- (`get_websocket_url`, `add_handler`, permission grants, raw
312
- `get_document`/`get_flattened_document`), and exact method aliases
313
- (`open`/`goto` vs `get`) were left out to keep the tool list focused —
314
- add them the same way as any other tool if you need them.
315
309
 
316
310
  ---
317
311
 
@@ -1,4 +1,4 @@
1
- seleniumbase[mcp]>=4.54.2
1
+ seleniumbase[mcp]>=4.54.4
2
2
  mcp[cli]<3.0.0,>=2.2.0
3
3
 
4
4
  [deploy]
@@ -70,7 +70,7 @@ if sys.argv[-1] == "publish":
70
70
 
71
71
  setup(
72
72
  name="seleniumbase-mcp",
73
- version="1.3.2",
73
+ version="1.3.4",
74
74
  description="MCP servers exposing SeleniumBase as tools for MCP clients.",
75
75
  long_description=long_description,
76
76
  long_description_content_type="text/markdown",
@@ -140,7 +140,7 @@ setup(
140
140
  ],
141
141
  python_requires=">=3.10",
142
142
  install_requires=[
143
- "seleniumbase[mcp]>=4.54.2",
143
+ "seleniumbase[mcp]>=4.54.4",
144
144
  "mcp[cli]>=2.2.0,<3.0.0",
145
145
  ],
146
146
  extras_require={
@@ -24,7 +24,7 @@ async def test_server(name: str, command: str) -> None:
24
24
 
25
25
  assert "start_browser" in tools
26
26
  assert "close_browser" in tools
27
- assert "navigate" in tools
27
+ assert "open_url" in tools
28
28
 
29
29
  result = await client.call_tool(
30
30
  "start_browser",
@@ -33,7 +33,7 @@ async def test_server(name: str, command: str) -> None:
33
33
  assert not result.is_error
34
34
 
35
35
  result = await client.call_tool(
36
- "navigate",
36
+ "open_url",
37
37
  {
38
38
  "url": (
39
39
  "data:text/html,"