seleniumbase 4.54.5__tar.gz → 4.54.6__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.
- {seleniumbase-4.54.5/seleniumbase.egg-info → seleniumbase-4.54.6}/PKG-INFO +2 -2
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/mcp_servers/server.py +238 -42
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/__version__.py +1 -1
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/undetected/cdp_driver/tab.py +19 -11
- {seleniumbase-4.54.5 → seleniumbase-4.54.6/seleniumbase.egg-info}/PKG-INFO +2 -2
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase.egg-info/requires.txt +1 -1
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/setup.py +1 -1
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/.gitignore +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/LICENSE +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/MANIFEST.in +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/README.md +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/install.sh +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/mcp_servers/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/pyproject.toml +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/pytest.ini +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/requirements.txt +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/sbase/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/sbase/__main__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/sbase/steps.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/__main__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/behave/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/behave/behave_helper.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/behave/behave_sb.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/behave/steps.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/common/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/common/decorators.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/common/encryption.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/common/exceptions.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/common/obfuscate.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/common/unobfuscate.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/config/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/config/ad_block_list.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/config/proxy_list.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/config/settings.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/console_scripts/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/console_scripts/logo_helper.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/console_scripts/rich_helper.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/console_scripts/run.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/console_scripts/sb_behave_gui.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/console_scripts/sb_caseplans.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/console_scripts/sb_commander.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/console_scripts/sb_install.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/console_scripts/sb_mkchart.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/console_scripts/sb_mkdir.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/console_scripts/sb_mkfile.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/console_scripts/sb_mkpres.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/console_scripts/sb_mkrec.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/console_scripts/sb_objectify.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/console_scripts/sb_print.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/console_scripts/sb_recorder.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/application_manager.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/browser_launcher.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/capabilities_parser.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/colored_traceback.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/create_db_tables.sql +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/detect_b_ver.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/download_helper.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/encoded_images.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/jqc_helper.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/log_helper.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/mysql.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/nest_asyncio.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/proxy_helper.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/recorder_helper.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/report_helper.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/s3_manager.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/sb_cdp.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/sb_driver.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/session_helper.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/settings_parser.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/style_sheet.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/testcase_manager.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/tour_helper.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/core/visual_helper.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/drivers/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/drivers/brave_drivers/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/drivers/cft_drivers/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/drivers/chromium_drivers/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/drivers/chs_drivers/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/drivers/comet_drivers/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/drivers/opera_drivers/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/extensions/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/extensions/ad_block.zip +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/extensions/disable_csp.zip +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/extensions/recorder.zip +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/extensions/sbase_ext.zip +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/fixtures/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/fixtures/base_case.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/fixtures/constants.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/fixtures/css_to_xpath.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/fixtures/errors.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/fixtures/js_utils.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/fixtures/page_actions.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/fixtures/page_utils.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/fixtures/shared_utils.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/fixtures/unittest_helper.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/fixtures/words.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/fixtures/xpath_to_css.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/js_code/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/js_code/active_css_js.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/js_code/live_js.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/js_code/recorder_js.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/masterqa/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/masterqa/master_qa.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/plugins/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/plugins/base_plugin.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/plugins/basic_test_info.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/plugins/db_reporting_plugin.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/plugins/driver_manager.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/plugins/page_source.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/plugins/pytest_plugin.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/plugins/s3_logging_plugin.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/plugins/sb_manager.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/plugins/screen_shots.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/plugins/selenium_plugin.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/resources/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/translate/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/translate/chinese.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/translate/dutch.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/translate/french.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/translate/italian.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/translate/japanese.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/translate/korean.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/translate/master_dict.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/translate/portuguese.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/translate/russian.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/translate/spanish.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/translate/translator.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/undetected/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/undetected/cdp.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/undetected/cdp_driver/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/undetected/cdp_driver/_contradict.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/undetected/cdp_driver/browser.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/undetected/cdp_driver/cdp_util.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/undetected/cdp_driver/config.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/undetected/cdp_driver/connection.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/undetected/cdp_driver/element.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/undetected/dprocess.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/undetected/options.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/undetected/patcher.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/undetected/reactor.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/undetected/webelement.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/utilities/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/utilities/selenium_grid/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/utilities/selenium_grid/download_selenium_server.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/utilities/selenium_grid/font_color +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/utilities/selenium_grid/grid-hub +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/utilities/selenium_grid/grid-node +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/utilities/selenium_grid/grid_hub.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/utilities/selenium_grid/grid_node.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/utilities/selenium_grid/register-grid-node.bat +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/utilities/selenium_grid/register-grid-node.sh +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/utilities/selenium_grid/start-grid-hub.bat +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/utilities/selenium_grid/start-grid-hub.sh +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/utilities/selenium_ide/__init__.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase/utilities/selenium_ide/convert_ide.py +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase.egg-info/SOURCES.txt +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase.egg-info/dependency_links.txt +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase.egg-info/entry_points.txt +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/seleniumbase.egg-info/top_level.txt +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/setup.cfg +0 -0
- {seleniumbase-4.54.5 → seleniumbase-4.54.6}/virtualenv_install.sh +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: seleniumbase
|
|
3
|
-
Version: 4.54.
|
|
3
|
+
Version: 4.54.6
|
|
4
4
|
Summary: SeleniumBase is a framework for web crawling, scraping, and testing. Supports pytest. CDP Mode adds stealth. Includes many tools.
|
|
5
5
|
Home-page: https://github.com/seleniumbase/SeleniumBase
|
|
6
6
|
Author: Michael Mintz
|
|
@@ -155,7 +155,7 @@ Requires-Dist: pyee>=13.0.1; extra == "playwright"
|
|
|
155
155
|
Provides-Extra: pyautogui
|
|
156
156
|
Requires-Dist: PyAutoGUI>=0.9.54; platform_system != "Linux" and extra == "pyautogui"
|
|
157
157
|
Provides-Extra: uv
|
|
158
|
-
Requires-Dist: uv>=0.12.
|
|
158
|
+
Requires-Dist: uv>=0.12.14; extra == "uv"
|
|
159
159
|
Dynamic: author
|
|
160
160
|
Dynamic: author-email
|
|
161
161
|
Dynamic: classifier
|
|
@@ -51,6 +51,17 @@ Tool-selection philosophy:
|
|
|
51
51
|
- Use 'focus_element' for element positioning and visual focus.
|
|
52
52
|
- Use 'solve_captcha' for clicking the checkbox of a CAPTCHA on the page.
|
|
53
53
|
- Use 'save_page' for saving page output as a PNG, a PDF, or an HTML file.
|
|
54
|
+
|
|
55
|
+
Tool annotations:
|
|
56
|
+
Where a tool has one consistent behavior, it declares MCP tool annotations
|
|
57
|
+
(title + read_only_hint/destructive_hint/idempotent_hint/open_world_hint)
|
|
58
|
+
so clients can make informed UX/confirmation decisions without calling it.
|
|
59
|
+
Several tools here consolidate multiple related actions behind a single
|
|
60
|
+
`action`/`mode` parameter (e.g. manage_cookies: get_all/clear/save/load).
|
|
61
|
+
Where those actions genuinely differ in kind -- some read-only, some
|
|
62
|
+
destructive, some writing to disk -- no single annotation value would be
|
|
63
|
+
honest for the whole tool, so annotations are intentionally omitted for
|
|
64
|
+
those (title is still provided). See the per-tool comments below.
|
|
54
65
|
"""
|
|
55
66
|
from __future__ import annotations
|
|
56
67
|
import atexit
|
|
@@ -59,6 +70,7 @@ from functools import wraps
|
|
|
59
70
|
from typing import Any, Literal
|
|
60
71
|
from mcp.server import MCPServer
|
|
61
72
|
from mcp.server.mcpserver.exceptions import ToolError
|
|
73
|
+
from mcp.types import ToolAnnotations
|
|
62
74
|
from seleniumbase import sb_cdp
|
|
63
75
|
|
|
64
76
|
mcp = MCPServer("seleniumbase-mcp")
|
|
@@ -99,7 +111,17 @@ def handle_sb_errors(func):
|
|
|
99
111
|
# Session lifecycle
|
|
100
112
|
# ---------------------------------------------------------------------------
|
|
101
113
|
|
|
102
|
-
@mcp.tool(
|
|
114
|
+
@mcp.tool(
|
|
115
|
+
title="Start Browser",
|
|
116
|
+
annotations=ToolAnnotations(
|
|
117
|
+
# Single, consistent behavior: launches (or no-ops if already
|
|
118
|
+
# running) a persistent browser session.
|
|
119
|
+
read_only_hint=False,
|
|
120
|
+
destructive_hint=False,
|
|
121
|
+
idempotent_hint=True, # No-ops with the same message if already up.
|
|
122
|
+
open_world_hint=True, # Launches a real browser onto the open web.
|
|
123
|
+
),
|
|
124
|
+
)
|
|
103
125
|
def start_browser(
|
|
104
126
|
url: str | None = None,
|
|
105
127
|
headless: Literal[False, True, None] = None,
|
|
@@ -245,7 +267,17 @@ def start_browser(
|
|
|
245
267
|
)
|
|
246
268
|
|
|
247
269
|
|
|
248
|
-
@mcp.tool(
|
|
270
|
+
@mcp.tool(
|
|
271
|
+
title="Close Browser",
|
|
272
|
+
annotations=ToolAnnotations(
|
|
273
|
+
# Single, consistent behavior: Ends the persistent browser session
|
|
274
|
+
# (or no-ops if already stopped).
|
|
275
|
+
read_only_hint=False,
|
|
276
|
+
idempotent_hint=True, # Once closed, repeated calls have no further
|
|
277
|
+
# effect.
|
|
278
|
+
open_world_hint=False, # Local teardown of a server-owned resource.
|
|
279
|
+
),
|
|
280
|
+
)
|
|
249
281
|
def close_browser() -> str:
|
|
250
282
|
"""Close the active browser session and release browser resources.
|
|
251
283
|
|
|
@@ -278,7 +310,15 @@ def close_browser() -> str:
|
|
|
278
310
|
# Page information
|
|
279
311
|
# ---------------------------------------------------------------------------
|
|
280
312
|
|
|
281
|
-
@mcp.tool(
|
|
313
|
+
@mcp.tool(
|
|
314
|
+
title="Get Page Info",
|
|
315
|
+
annotations=ToolAnnotations(
|
|
316
|
+
read_only_hint=True,
|
|
317
|
+
destructive_hint=False,
|
|
318
|
+
idempotent_hint=True,
|
|
319
|
+
open_world_hint=True,
|
|
320
|
+
),
|
|
321
|
+
)
|
|
282
322
|
@handle_sb_errors
|
|
283
323
|
def get_page_info() -> dict[str, Any]:
|
|
284
324
|
"""Get current browser session and page metadata.
|
|
@@ -287,7 +327,7 @@ def get_page_info() -> dict[str, Any]:
|
|
|
287
327
|
is after navigation, clicks, form submissions, redirects, reloads, or
|
|
288
328
|
tab switches.
|
|
289
329
|
|
|
290
|
-
This is a
|
|
330
|
+
This is a read-only metadata operation: It does not inspect arbitrary
|
|
291
331
|
page content, find elements, check visibility, wait for conditions, or
|
|
292
332
|
assert expected values.
|
|
293
333
|
|
|
@@ -337,7 +377,15 @@ def get_page_info() -> dict[str, Any]:
|
|
|
337
377
|
# Navigation
|
|
338
378
|
# ---------------------------------------------------------------------------
|
|
339
379
|
|
|
340
|
-
@mcp.tool(
|
|
380
|
+
@mcp.tool(
|
|
381
|
+
title="Open URL",
|
|
382
|
+
annotations=ToolAnnotations(
|
|
383
|
+
read_only_hint=False,
|
|
384
|
+
destructive_hint=False,
|
|
385
|
+
idempotent_hint=False,
|
|
386
|
+
open_world_hint=True,
|
|
387
|
+
),
|
|
388
|
+
)
|
|
341
389
|
@handle_sb_errors
|
|
342
390
|
def open_url(url: str) -> str:
|
|
343
391
|
"""Navigate the current browser tab to the URL provided.
|
|
@@ -372,15 +420,18 @@ def open_url(url: str) -> str:
|
|
|
372
420
|
return f"Navigated to {url}"
|
|
373
421
|
|
|
374
422
|
|
|
375
|
-
@mcp.tool()
|
|
423
|
+
@mcp.tool(title="Manage History")
|
|
424
|
+
# Annotations intentionally omitted: 'list' is a pure read, while
|
|
425
|
+
# 'back'/'forward'/'reload' each navigate and modify browser state -- no
|
|
426
|
+
# single read_only_hint value would be accurate for the whole tool.
|
|
376
427
|
@handle_sb_errors
|
|
377
428
|
def manage_history(
|
|
378
429
|
action: Literal["back", "forward", "reload", "list"] = "list",
|
|
379
430
|
) -> str | dict[str, Any]:
|
|
380
431
|
"""Manage or inspect the current browser tab's navigation history.
|
|
381
432
|
|
|
382
|
-
Use
|
|
383
|
-
|
|
433
|
+
Use "back", "forward", or "reload" actions for history navigation.
|
|
434
|
+
Use "list" to inspect history. (This one is read-only.)
|
|
384
435
|
Use 'open_url' for navigation to an arbitrary URL.
|
|
385
436
|
|
|
386
437
|
Args:
|
|
@@ -391,7 +442,7 @@ def manage_history(
|
|
|
391
442
|
- "list": Return the current history position and entries.
|
|
392
443
|
|
|
393
444
|
Navigation actions can trigger page loads or redirects.
|
|
394
|
-
Use get_page_info afterward to verify the resulting URL or title.
|
|
445
|
+
Use 'get_page_info' afterward to verify the resulting URL or title.
|
|
395
446
|
"""
|
|
396
447
|
sb = _get_sb()
|
|
397
448
|
|
|
@@ -433,7 +484,15 @@ def manage_history(
|
|
|
433
484
|
# Finding & reading
|
|
434
485
|
# ---------------------------------------------------------------------------
|
|
435
486
|
|
|
436
|
-
@mcp.tool(
|
|
487
|
+
@mcp.tool(
|
|
488
|
+
title="Find Elements",
|
|
489
|
+
annotations=ToolAnnotations(
|
|
490
|
+
read_only_hint=True,
|
|
491
|
+
destructive_hint=False,
|
|
492
|
+
idempotent_hint=True,
|
|
493
|
+
open_world_hint=True,
|
|
494
|
+
),
|
|
495
|
+
)
|
|
437
496
|
@handle_sb_errors
|
|
438
497
|
def find_elements(
|
|
439
498
|
selector: str,
|
|
@@ -514,7 +573,15 @@ def find_elements(
|
|
|
514
573
|
}
|
|
515
574
|
|
|
516
575
|
|
|
517
|
-
@mcp.tool(
|
|
576
|
+
@mcp.tool(
|
|
577
|
+
title="Get Content",
|
|
578
|
+
annotations=ToolAnnotations(
|
|
579
|
+
read_only_hint=True,
|
|
580
|
+
destructive_hint=False,
|
|
581
|
+
idempotent_hint=True,
|
|
582
|
+
open_world_hint=True,
|
|
583
|
+
),
|
|
584
|
+
)
|
|
518
585
|
@handle_sb_errors
|
|
519
586
|
def get_content(
|
|
520
587
|
selector: str = "body",
|
|
@@ -567,18 +634,24 @@ def get_content(
|
|
|
567
634
|
)
|
|
568
635
|
|
|
569
636
|
|
|
570
|
-
@mcp.tool(
|
|
637
|
+
@mcp.tool(
|
|
638
|
+
title="Get Attributes",
|
|
639
|
+
annotations=ToolAnnotations(
|
|
640
|
+
read_only_hint=True,
|
|
641
|
+
destructive_hint=False,
|
|
642
|
+
idempotent_hint=True,
|
|
643
|
+
open_world_hint=True,
|
|
644
|
+
),
|
|
645
|
+
)
|
|
571
646
|
@handle_sb_errors
|
|
572
647
|
def get_attributes(
|
|
573
648
|
selector: str,
|
|
574
649
|
attribute: str | None = None,
|
|
575
650
|
timeout: float = 5,
|
|
576
651
|
) -> str | dict[str, Any] | None:
|
|
577
|
-
"""
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
or all HTML attributes of an element. Attributes could be something
|
|
581
|
-
such as href, src, value, class, id, name, type, aria-label, etc.
|
|
652
|
+
"""Get a specific HTML attribute (or all attributes) from the
|
|
653
|
+
first-matching element. Examples of possible attributes include
|
|
654
|
+
href, src, value, class, id, name, type, aria-label, etc.
|
|
582
655
|
|
|
583
656
|
Args:
|
|
584
657
|
selector: CSS selector or SeleniumBase-supported XPath selector.
|
|
@@ -597,7 +670,8 @@ def get_attributes(
|
|
|
597
670
|
- Need to check element presence/visibility ->
|
|
598
671
|
use 'check_if_condition'.
|
|
599
672
|
|
|
600
|
-
This is a read-only operation
|
|
673
|
+
This is a read-only operation: It finds elements to get the requested data,
|
|
674
|
+
but it does not make any modifications to those elements.
|
|
601
675
|
|
|
602
676
|
If there's no matching element found within the timeout,
|
|
603
677
|
then @handle_sb_errors returns details from the exception raised.
|
|
@@ -610,7 +684,15 @@ def get_attributes(
|
|
|
610
684
|
return sb.get_element_attributes(selector, timeout=timeout)
|
|
611
685
|
|
|
612
686
|
|
|
613
|
-
@mcp.tool(
|
|
687
|
+
@mcp.tool(
|
|
688
|
+
title="Check Condition",
|
|
689
|
+
annotations=ToolAnnotations(
|
|
690
|
+
read_only_hint=True,
|
|
691
|
+
destructive_hint=False,
|
|
692
|
+
idempotent_hint=True,
|
|
693
|
+
open_world_hint=True,
|
|
694
|
+
),
|
|
695
|
+
)
|
|
614
696
|
@handle_sb_errors
|
|
615
697
|
def check_if_condition(
|
|
616
698
|
check: Literal["present", "visible"] = "visible",
|
|
@@ -659,8 +741,6 @@ def check_if_condition(
|
|
|
659
741
|
This tool does not intentionally wait for elements or text to appear.
|
|
660
742
|
It is intended for checking the current state only. If page timing or
|
|
661
743
|
asynchronous loading matters, use wait_for_condition instead.
|
|
662
|
-
|
|
663
|
-
When `text` is provided, `check` is ignored.
|
|
664
744
|
"""
|
|
665
745
|
sb = _get_sb()
|
|
666
746
|
|
|
@@ -682,7 +762,20 @@ def check_if_condition(
|
|
|
682
762
|
# Interacting with elements
|
|
683
763
|
# ---------------------------------------------------------------------------
|
|
684
764
|
|
|
685
|
-
@mcp.tool(
|
|
765
|
+
@mcp.tool(
|
|
766
|
+
title="Click Element",
|
|
767
|
+
annotations=ToolAnnotations(
|
|
768
|
+
# These settings are consistent across all click modes. The tool
|
|
769
|
+
# always performs a browser interaction, regardless of which matching
|
|
770
|
+
# element(s) are selected.
|
|
771
|
+
read_only_hint=False, # Clicking can modify browser/page state.
|
|
772
|
+
destructive_hint=False, # The generic click operation is not
|
|
773
|
+
# inherently destructive; the target may be.
|
|
774
|
+
idempotent_hint=False, # Repeating a click can produce a different
|
|
775
|
+
# result or trigger another action.
|
|
776
|
+
open_world_hint=True, # The tool operates on external webpages.
|
|
777
|
+
),
|
|
778
|
+
)
|
|
686
779
|
@handle_sb_errors
|
|
687
780
|
def click_element(
|
|
688
781
|
selector: str,
|
|
@@ -699,12 +792,12 @@ def click_element(
|
|
|
699
792
|
clicking all visible matches, conditional clicks, or clicks scoped to a
|
|
700
793
|
parent element.
|
|
701
794
|
|
|
702
|
-
Selection behavior:
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
795
|
+
Selection behavior and priority:
|
|
796
|
+
`nth` is 1-based and takes precedence over every other click mode.
|
|
797
|
+
Otherwise, `all_matches=True` clicks every currently visible match.
|
|
798
|
+
Otherwise, `only_if_visible=True` clicks only if a match is visible.
|
|
799
|
+
Otherwise, `parent_selector` scopes the click to a nested element.
|
|
800
|
+
If none of the above are set, then a regular click is performed.
|
|
708
801
|
|
|
709
802
|
Args:
|
|
710
803
|
selector: CSS selector, XPath selector, or supported SeleniumBase
|
|
@@ -779,7 +872,11 @@ def click_element(
|
|
|
779
872
|
return f"Clicked {selector}"
|
|
780
873
|
|
|
781
874
|
|
|
782
|
-
@mcp.tool()
|
|
875
|
+
@mcp.tool(title="Hover / Click / Drag")
|
|
876
|
+
# Annotations intentionally omitted: 'hover' alone is a near-harmless
|
|
877
|
+
# observation-adjacent action, while 'hover_and_click' and 'drag_and_drop'
|
|
878
|
+
# can modify or reorder page/data state (like click_element) -- no single
|
|
879
|
+
# destructive_hint value would be accurate for the whole tool.
|
|
783
880
|
@handle_sb_errors
|
|
784
881
|
def hover_action(
|
|
785
882
|
selector: str,
|
|
@@ -865,7 +962,19 @@ def hover_action(
|
|
|
865
962
|
)
|
|
866
963
|
|
|
867
964
|
|
|
868
|
-
@mcp.tool(
|
|
965
|
+
@mcp.tool(
|
|
966
|
+
title="Type Text",
|
|
967
|
+
annotations=ToolAnnotations(
|
|
968
|
+
# idempotent_hint is deliberately omitted: fill_input/set_value/
|
|
969
|
+
# clear_only converge to the same end state on repeat calls, but
|
|
970
|
+
# mode="append" compounds text on each call, so no single value
|
|
971
|
+
# would be accurate for every mode.
|
|
972
|
+
read_only_hint=False,
|
|
973
|
+
destructive_hint=False,
|
|
974
|
+
open_world_hint=True, # Since "\n" can perform the "Enter" action,
|
|
975
|
+
# which includes form submissions.
|
|
976
|
+
),
|
|
977
|
+
)
|
|
869
978
|
@handle_sb_errors
|
|
870
979
|
def type_text(
|
|
871
980
|
selector: str,
|
|
@@ -935,7 +1044,17 @@ def type_text(
|
|
|
935
1044
|
return f"type_text(mode={mode!r}) done for {selector}"
|
|
936
1045
|
|
|
937
1046
|
|
|
938
|
-
@mcp.tool(
|
|
1047
|
+
@mcp.tool(
|
|
1048
|
+
title="Select Option",
|
|
1049
|
+
annotations=ToolAnnotations(
|
|
1050
|
+
read_only_hint=False,
|
|
1051
|
+
destructive_hint=False,
|
|
1052
|
+
idempotent_hint=False, # Selecting an option can trigger arbitrary
|
|
1053
|
+
# page-side behavior/events.
|
|
1054
|
+
open_world_hint=True, # Selecting an option can change browser
|
|
1055
|
+
# state and can trigger arbitrary page-side behavior.
|
|
1056
|
+
),
|
|
1057
|
+
)
|
|
939
1058
|
@handle_sb_errors
|
|
940
1059
|
def select_option(
|
|
941
1060
|
dropdown_selector: str,
|
|
@@ -977,7 +1096,13 @@ def select_option(
|
|
|
977
1096
|
return f"Selected ({by}={value!r}) in {dropdown_selector}"
|
|
978
1097
|
|
|
979
1098
|
|
|
980
|
-
@mcp.tool(
|
|
1099
|
+
@mcp.tool(
|
|
1100
|
+
title="Focus Element",
|
|
1101
|
+
annotations=ToolAnnotations(
|
|
1102
|
+
read_only_hint=False,
|
|
1103
|
+
destructive_hint=False,
|
|
1104
|
+
),
|
|
1105
|
+
)
|
|
981
1106
|
@handle_sb_errors
|
|
982
1107
|
def focus_element(
|
|
983
1108
|
selector: str,
|
|
@@ -1030,7 +1155,17 @@ def focus_element(
|
|
|
1030
1155
|
# Waiting & assertions
|
|
1031
1156
|
# ---------------------------------------------------------------------------
|
|
1032
1157
|
|
|
1033
|
-
@mcp.tool(
|
|
1158
|
+
@mcp.tool(
|
|
1159
|
+
title="Wait For Condition",
|
|
1160
|
+
annotations=ToolAnnotations(
|
|
1161
|
+
# Consistent across every state: This tool only observes/blocks,
|
|
1162
|
+
# and it never modifies the page itself.
|
|
1163
|
+
read_only_hint=True,
|
|
1164
|
+
destructive_hint=False,
|
|
1165
|
+
idempotent_hint=True,
|
|
1166
|
+
open_world_hint=False,
|
|
1167
|
+
),
|
|
1168
|
+
)
|
|
1034
1169
|
@handle_sb_errors
|
|
1035
1170
|
def wait_for_condition(
|
|
1036
1171
|
state: Literal[
|
|
@@ -1138,7 +1273,17 @@ def wait_for_condition(
|
|
|
1138
1273
|
return f"Element {selector} reached state '{state}'."
|
|
1139
1274
|
|
|
1140
1275
|
|
|
1141
|
-
@mcp.tool(
|
|
1276
|
+
@mcp.tool(
|
|
1277
|
+
title="Assert Condition",
|
|
1278
|
+
annotations=ToolAnnotations(
|
|
1279
|
+
# Consistent across every check: Purely a verification/read
|
|
1280
|
+
# operation, and never modifies the page.
|
|
1281
|
+
read_only_hint=True,
|
|
1282
|
+
destructive_hint=False,
|
|
1283
|
+
idempotent_hint=True,
|
|
1284
|
+
open_world_hint=False,
|
|
1285
|
+
),
|
|
1286
|
+
)
|
|
1142
1287
|
@handle_sb_errors
|
|
1143
1288
|
def assert_condition(
|
|
1144
1289
|
check: Literal[
|
|
@@ -1256,7 +1401,11 @@ def assert_condition(
|
|
|
1256
1401
|
# Cookies & storage
|
|
1257
1402
|
# ---------------------------------------------------------------------------
|
|
1258
1403
|
|
|
1259
|
-
@mcp.tool()
|
|
1404
|
+
@mcp.tool(title="Manage Cookies")
|
|
1405
|
+
# Annotations intentionally omitted: 'get_all' is a pure read, 'clear' is
|
|
1406
|
+
# destructive, and 'save'/'load' are file/session I/O -- no single
|
|
1407
|
+
# read_only_hint or destructive_hint value would be accurate for the whole
|
|
1408
|
+
# tool.
|
|
1260
1409
|
@handle_sb_errors
|
|
1261
1410
|
def manage_cookies(
|
|
1262
1411
|
action: Literal["get_all", "clear", "save", "load"] = "get_all",
|
|
@@ -1328,7 +1477,10 @@ def manage_cookies(
|
|
|
1328
1477
|
)
|
|
1329
1478
|
|
|
1330
1479
|
|
|
1331
|
-
@mcp.tool()
|
|
1480
|
+
@mcp.tool(title="Manage Storage")
|
|
1481
|
+
# Annotations intentionally omitted: 'get' is a pure read while 'set'
|
|
1482
|
+
# modifies storage -- no single read_only_hint value would be accurate
|
|
1483
|
+
# for the whole tool.
|
|
1332
1484
|
@handle_sb_errors
|
|
1333
1485
|
def manage_storage(
|
|
1334
1486
|
key: str,
|
|
@@ -1404,7 +1556,20 @@ def manage_storage(
|
|
|
1404
1556
|
# Scrolling
|
|
1405
1557
|
# ---------------------------------------------------------------------------
|
|
1406
1558
|
|
|
1407
|
-
@mcp.tool(
|
|
1559
|
+
@mcp.tool(
|
|
1560
|
+
title="Scroll Page",
|
|
1561
|
+
annotations=ToolAnnotations(
|
|
1562
|
+
# Consistent across up/down/top/bottom: a harmless, local,
|
|
1563
|
+
# non-destructive scroll-position change.
|
|
1564
|
+
# idempotent_hint is deliberately omitted: 'top'/'bottom' are
|
|
1565
|
+
# idempotent (repeating lands you in the same place), but 'up'/
|
|
1566
|
+
# 'down' compound with each call, so no single value would be
|
|
1567
|
+
# accurate for every direction.
|
|
1568
|
+
read_only_hint=False,
|
|
1569
|
+
destructive_hint=False,
|
|
1570
|
+
open_world_hint=False,
|
|
1571
|
+
),
|
|
1572
|
+
)
|
|
1408
1573
|
@handle_sb_errors
|
|
1409
1574
|
def scroll_page(
|
|
1410
1575
|
direction: Literal["up", "down", "top", "bottom"] = "down",
|
|
@@ -1460,7 +1625,10 @@ def scroll_page(
|
|
|
1460
1625
|
# Windows & tabs
|
|
1461
1626
|
# ---------------------------------------------------------------------------
|
|
1462
1627
|
|
|
1463
|
-
@mcp.tool()
|
|
1628
|
+
@mcp.tool(title="Manage Window")
|
|
1629
|
+
# Annotations intentionally omitted: 'get_rect' is a pure read while
|
|
1630
|
+
# 'set_rect'/'maximize'/'minimize' modify window state -- no single
|
|
1631
|
+
# read_only_hint value would be accurate for the whole tool.
|
|
1464
1632
|
@handle_sb_errors
|
|
1465
1633
|
def manage_window(
|
|
1466
1634
|
action: Literal[
|
|
@@ -1520,7 +1688,11 @@ def manage_window(
|
|
|
1520
1688
|
)
|
|
1521
1689
|
|
|
1522
1690
|
|
|
1523
|
-
@mcp.tool()
|
|
1691
|
+
@mcp.tool(title="Manage Tabs")
|
|
1692
|
+
# Annotations intentionally omitted: 'list_tabs' is a pure read while
|
|
1693
|
+
# 'open_new_tab'/'switch_to_tab'/'switch_to_newest_tab' modify state and
|
|
1694
|
+
# 'close_active_tab' is destructive -- no single read_only_hint or
|
|
1695
|
+
# destructive_hint value would be accurate for the whole tool.
|
|
1524
1696
|
@handle_sb_errors
|
|
1525
1697
|
def manage_tabs(
|
|
1526
1698
|
action: Literal[
|
|
@@ -1621,7 +1793,16 @@ def manage_tabs(
|
|
|
1621
1793
|
# Captcha solving
|
|
1622
1794
|
# ---------------------------------------------------------------------------
|
|
1623
1795
|
|
|
1624
|
-
@mcp.tool(
|
|
1796
|
+
@mcp.tool(
|
|
1797
|
+
title="Solve CAPTCHA",
|
|
1798
|
+
annotations=ToolAnnotations(
|
|
1799
|
+
read_only_hint=False,
|
|
1800
|
+
destructive_hint=False,
|
|
1801
|
+
idempotent_hint=False, # A 2nd attempt on an already-handled or
|
|
1802
|
+
# rotated CAPTCHA widget isn't guaranteed to be a no-op.
|
|
1803
|
+
open_world_hint=True, # Interacts with a 3rd-party CAPTCHA widget.
|
|
1804
|
+
),
|
|
1805
|
+
)
|
|
1625
1806
|
@handle_sb_errors
|
|
1626
1807
|
def solve_captcha() -> str:
|
|
1627
1808
|
"""Attempt a SeleniumBase CDP-based CAPTCHA interaction, such as clicking
|
|
@@ -1661,7 +1842,17 @@ def solve_captcha() -> str:
|
|
|
1661
1842
|
# Output & misc
|
|
1662
1843
|
# ---------------------------------------------------------------------------
|
|
1663
1844
|
|
|
1664
|
-
@mcp.tool(
|
|
1845
|
+
@mcp.tool(
|
|
1846
|
+
title="Save Page",
|
|
1847
|
+
annotations=ToolAnnotations(
|
|
1848
|
+
# Consistent across screenshot/html/pdf: All three read the current
|
|
1849
|
+
# (unmodified) page and write a new local file, which may silently
|
|
1850
|
+
# overwrite an existing file of the same name.
|
|
1851
|
+
read_only_hint=False,
|
|
1852
|
+
idempotent_hint=False,
|
|
1853
|
+
open_world_hint=False,
|
|
1854
|
+
),
|
|
1855
|
+
)
|
|
1665
1856
|
@handle_sb_errors
|
|
1666
1857
|
def save_page(
|
|
1667
1858
|
format: Literal["screenshot", "html", "pdf"] = "screenshot",
|
|
@@ -1741,7 +1932,12 @@ def save_page(
|
|
|
1741
1932
|
return f"Saved {format} as {name}"
|
|
1742
1933
|
|
|
1743
1934
|
|
|
1744
|
-
@mcp.tool()
|
|
1935
|
+
@mcp.tool(title="Run JavaScript")
|
|
1936
|
+
# Annotations intentionally omitted: arbitrary JavaScript can read, write,
|
|
1937
|
+
# navigate, or destroy data, or do nothing at all -- no annotation value
|
|
1938
|
+
# would be more informative than the MCP spec's own conservative defaults
|
|
1939
|
+
# for an unannotated tool (not read-only, potentially destructive,
|
|
1940
|
+
# non-idempotent, open-world).
|
|
1745
1941
|
@handle_sb_errors
|
|
1746
1942
|
def run_javascript(expression: str) -> Any:
|
|
1747
1943
|
"""Evaluate a JavaScript expression in the current page context.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# seleniumbase package
|
|
2
|
-
__version__ = "4.54.
|
|
2
|
+
__version__ = "4.54.6"
|
|
@@ -222,14 +222,15 @@ class Tab(Connection):
|
|
|
222
222
|
except (Exception, TypeError):
|
|
223
223
|
pass
|
|
224
224
|
while not item:
|
|
225
|
-
item = await self.find_element_by_text(
|
|
226
|
-
text, best_match, return_enclosing_element
|
|
227
|
-
)
|
|
228
225
|
if loop.time() - start_time > timeout:
|
|
229
226
|
raise asyncio.TimeoutError(
|
|
230
227
|
"Time ran out while waiting for: {%s}" % text
|
|
231
228
|
)
|
|
229
|
+
await self
|
|
232
230
|
await self.sleep(0.5)
|
|
231
|
+
item = await self.find_element_by_text(
|
|
232
|
+
text, best_match, return_enclosing_element
|
|
233
|
+
)
|
|
233
234
|
return item
|
|
234
235
|
|
|
235
236
|
async def select(
|
|
@@ -273,13 +274,13 @@ class Tab(Connection):
|
|
|
273
274
|
except (Exception, TypeError):
|
|
274
275
|
pass
|
|
275
276
|
while not items:
|
|
276
|
-
await self
|
|
277
|
-
items = await self.find_elements_by_text(text)
|
|
278
277
|
if loop.time() - now > timeout:
|
|
279
278
|
raise asyncio.TimeoutError(
|
|
280
279
|
"Time ran out while waiting for: {%s}" % text
|
|
281
280
|
)
|
|
281
|
+
await self
|
|
282
282
|
await self.sleep(0.5)
|
|
283
|
+
items = await self.find_elements_by_text(text)
|
|
283
284
|
return items
|
|
284
285
|
|
|
285
286
|
async def select_all(
|
|
@@ -311,13 +312,13 @@ class Tab(Connection):
|
|
|
311
312
|
items.extend(await fr.query_selector_all(selector))
|
|
312
313
|
items.extend(await self.query_selector_all(selector))
|
|
313
314
|
while not items:
|
|
314
|
-
await self
|
|
315
|
-
items = await self.query_selector_all(selector)
|
|
316
315
|
if loop.time() - now > timeout:
|
|
317
316
|
raise asyncio.TimeoutError(
|
|
318
317
|
"Time ran out while waiting for: {%s}" % selector
|
|
319
318
|
)
|
|
319
|
+
await self
|
|
320
320
|
await self.sleep(0.5)
|
|
321
|
+
items = await self.query_selector_all(selector)
|
|
321
322
|
return items
|
|
322
323
|
|
|
323
324
|
async def get(
|
|
@@ -1098,25 +1099,32 @@ class Tab(Connection):
|
|
|
1098
1099
|
"""
|
|
1099
1100
|
loop = asyncio.get_running_loop()
|
|
1100
1101
|
now = loop.time()
|
|
1102
|
+
item = None
|
|
1101
1103
|
if selector:
|
|
1102
|
-
|
|
1103
|
-
while not item:
|
|
1104
|
+
with suppress(Exception):
|
|
1104
1105
|
item = await self.query_selector(selector)
|
|
1106
|
+
while not item:
|
|
1105
1107
|
if loop.time() - now > timeout:
|
|
1106
1108
|
raise asyncio.TimeoutError(
|
|
1107
1109
|
"Time ran out while waiting for: {%s}" % selector
|
|
1108
1110
|
)
|
|
1111
|
+
await self
|
|
1109
1112
|
await self.sleep(0.068)
|
|
1113
|
+
with suppress(Exception):
|
|
1114
|
+
item = await self.query_selector(selector)
|
|
1110
1115
|
return item
|
|
1111
1116
|
if text:
|
|
1112
|
-
|
|
1113
|
-
while not item:
|
|
1117
|
+
with suppress(Exception):
|
|
1114
1118
|
item = await self.find_element_by_text(text)
|
|
1119
|
+
while not item:
|
|
1115
1120
|
if loop.time() - now > timeout:
|
|
1116
1121
|
raise asyncio.TimeoutError(
|
|
1117
1122
|
"Time ran out while waiting for: {%s}" % text
|
|
1118
1123
|
)
|
|
1124
|
+
await self
|
|
1119
1125
|
await self.sleep(0.068)
|
|
1126
|
+
with suppress(Exception):
|
|
1127
|
+
item = await self.find_element_by_text(text)
|
|
1120
1128
|
return item
|
|
1121
1129
|
|
|
1122
1130
|
async def set_attributes(self, selector, attribute, value):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: seleniumbase
|
|
3
|
-
Version: 4.54.
|
|
3
|
+
Version: 4.54.6
|
|
4
4
|
Summary: SeleniumBase is a framework for web crawling, scraping, and testing. Supports pytest. CDP Mode adds stealth. Includes many tools.
|
|
5
5
|
Home-page: https://github.com/seleniumbase/SeleniumBase
|
|
6
6
|
Author: Michael Mintz
|
|
@@ -155,7 +155,7 @@ Requires-Dist: pyee>=13.0.1; extra == "playwright"
|
|
|
155
155
|
Provides-Extra: pyautogui
|
|
156
156
|
Requires-Dist: PyAutoGUI>=0.9.54; platform_system != "Linux" and extra == "pyautogui"
|
|
157
157
|
Provides-Extra: uv
|
|
158
|
-
Requires-Dist: uv>=0.12.
|
|
158
|
+
Requires-Dist: uv>=0.12.14; extra == "uv"
|
|
159
159
|
Dynamic: author
|
|
160
160
|
Dynamic: author-email
|
|
161
161
|
Dynamic: classifier
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|