iflow-mcp_janspoerer-mcp_browser_use 0.1.0__py3-none-any.whl

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.
Files changed (50) hide show
  1. iflow_mcp_janspoerer_mcp_browser_use-0.1.0.dist-info/METADATA +26 -0
  2. iflow_mcp_janspoerer_mcp_browser_use-0.1.0.dist-info/RECORD +50 -0
  3. iflow_mcp_janspoerer_mcp_browser_use-0.1.0.dist-info/WHEEL +5 -0
  4. iflow_mcp_janspoerer_mcp_browser_use-0.1.0.dist-info/entry_points.txt +2 -0
  5. iflow_mcp_janspoerer_mcp_browser_use-0.1.0.dist-info/licenses/LICENSE +201 -0
  6. iflow_mcp_janspoerer_mcp_browser_use-0.1.0.dist-info/top_level.txt +1 -0
  7. mcp_browser_use/__init__.py +2 -0
  8. mcp_browser_use/__main__.py +1347 -0
  9. mcp_browser_use/actions/__init__.py +1 -0
  10. mcp_browser_use/actions/elements.py +173 -0
  11. mcp_browser_use/actions/extraction.py +864 -0
  12. mcp_browser_use/actions/keyboard.py +43 -0
  13. mcp_browser_use/actions/navigation.py +73 -0
  14. mcp_browser_use/actions/screenshots.py +85 -0
  15. mcp_browser_use/browser/__init__.py +1 -0
  16. mcp_browser_use/browser/chrome.py +150 -0
  17. mcp_browser_use/browser/chrome_executable.py +204 -0
  18. mcp_browser_use/browser/chrome_launcher.py +330 -0
  19. mcp_browser_use/browser/chrome_process.py +104 -0
  20. mcp_browser_use/browser/devtools.py +230 -0
  21. mcp_browser_use/browser/driver.py +322 -0
  22. mcp_browser_use/browser/process.py +133 -0
  23. mcp_browser_use/cleaners.py +530 -0
  24. mcp_browser_use/config/__init__.py +30 -0
  25. mcp_browser_use/config/environment.py +155 -0
  26. mcp_browser_use/config/paths.py +97 -0
  27. mcp_browser_use/constants.py +68 -0
  28. mcp_browser_use/context.py +150 -0
  29. mcp_browser_use/context_pack.py +85 -0
  30. mcp_browser_use/decorators/__init__.py +13 -0
  31. mcp_browser_use/decorators/ensure.py +84 -0
  32. mcp_browser_use/decorators/envelope.py +83 -0
  33. mcp_browser_use/decorators/locking.py +172 -0
  34. mcp_browser_use/helpers.py +173 -0
  35. mcp_browser_use/helpers_context.py +261 -0
  36. mcp_browser_use/locking/__init__.py +1 -0
  37. mcp_browser_use/locking/action_lock.py +190 -0
  38. mcp_browser_use/locking/file_mutex.py +139 -0
  39. mcp_browser_use/locking/window_registry.py +178 -0
  40. mcp_browser_use/tools/__init__.py +59 -0
  41. mcp_browser_use/tools/browser_management.py +260 -0
  42. mcp_browser_use/tools/debugging.py +195 -0
  43. mcp_browser_use/tools/extraction.py +58 -0
  44. mcp_browser_use/tools/interaction.py +323 -0
  45. mcp_browser_use/tools/navigation.py +84 -0
  46. mcp_browser_use/tools/screenshots.py +116 -0
  47. mcp_browser_use/utils/__init__.py +1 -0
  48. mcp_browser_use/utils/diagnostics.py +85 -0
  49. mcp_browser_use/utils/html_utils.py +118 -0
  50. mcp_browser_use/utils/retry.py +57 -0
@@ -0,0 +1 @@
1
+ """High-level browser actions."""
@@ -0,0 +1,173 @@
1
+ """Element finding and interaction."""
2
+
3
+ import time
4
+ from typing import Optional
5
+ from selenium import webdriver
6
+ from selenium.webdriver.common.by import By
7
+ from selenium.webdriver.support.ui import WebDriverWait
8
+ from selenium.webdriver.support import expected_conditions as EC
9
+ from selenium.common.exceptions import (
10
+ TimeoutException,
11
+ StaleElementReferenceException,
12
+ ElementClickInterceptedException,
13
+ )
14
+
15
+ from ..context import get_context
16
+
17
+
18
+ def _wait_clickable_element(el, driver, timeout: float = 10.0):
19
+ """Wait for an element to be clickable (displayed and enabled)."""
20
+ WebDriverWait(driver, timeout).until(lambda d: el.is_displayed() and el.is_enabled())
21
+ return el
22
+
23
+ def get_by_selector(selector_type: str):
24
+ return {
25
+ 'css': By.CSS_SELECTOR,
26
+ 'xpath': By.XPATH,
27
+ 'id': By.ID,
28
+ 'name': By.NAME,
29
+ 'tag': By.TAG_NAME,
30
+ 'class': By.CLASS_NAME,
31
+ 'link_text': By.LINK_TEXT,
32
+ 'partial_link_text': By.PARTIAL_LINK_TEXT
33
+ }.get(selector_type.lower())
34
+
35
+
36
+ def find_element(
37
+ driver: webdriver.Chrome,
38
+ selector: str,
39
+ selector_type: str = "css",
40
+ timeout: int = 10,
41
+ visible_only: bool = False,
42
+ iframe_selector: Optional[str] = None,
43
+ iframe_selector_type: str = "css",
44
+ shadow_root_selector: Optional[str] = None,
45
+ shadow_root_selector_type: str = "css",
46
+ stay_in_context: bool = False, # <-- added
47
+ ):
48
+ """
49
+ Locate an element with optional iframe and shadow DOM support.
50
+
51
+ - If stay_in_context is True and an iframe was entered, we do NOT switch back
52
+ to default_content. This is needed for actions (click/type) inside iframes.
53
+ - If stay_in_context is False (default), we restore to default_content() so
54
+ callers aren't left in an iframe.
55
+ """
56
+ original_driver = driver
57
+ switched_iframe = False
58
+ try:
59
+ if iframe_selector:
60
+ by_iframe = get_by_selector(iframe_selector_type)
61
+ if not by_iframe:
62
+ raise ValueError(f"Unsupported iframe selector type: {iframe_selector_type}")
63
+ iframe = WebDriverWait(driver, timeout).until(
64
+ EC.presence_of_element_located((by_iframe, iframe_selector))
65
+ )
66
+ driver.switch_to.frame(iframe)
67
+ switched_iframe = True
68
+
69
+ search_context = driver
70
+ if shadow_root_selector:
71
+ by_shadow_host = get_by_selector(shadow_root_selector_type)
72
+ if not by_shadow_host:
73
+ raise ValueError(f"Unsupported shadow root selector type: {shadow_root_selector_type}")
74
+ shadow_host = WebDriverWait(driver, timeout).until(
75
+ EC.presence_of_element_located((by_shadow_host, shadow_root_selector))
76
+ )
77
+ shadow_root = shadow_host.shadow_root
78
+ search_context = shadow_root
79
+
80
+ by_selector = get_by_selector(selector_type)
81
+ if not by_selector:
82
+ raise ValueError(f"Unsupported selector type: {selector_type}")
83
+
84
+ wait = WebDriverWait(search_context, timeout)
85
+ if visible_only:
86
+ element = wait.until(EC.visibility_of_element_located((by_selector, selector)))
87
+ else:
88
+ element = wait.until(EC.presence_of_element_located((by_selector, selector)))
89
+
90
+ return element
91
+
92
+ except TimeoutException:
93
+ if switched_iframe and not stay_in_context:
94
+ try:
95
+ original_driver.switch_to.default_content()
96
+ except Exception:
97
+ pass
98
+ raise
99
+ except Exception:
100
+ if switched_iframe and not stay_in_context:
101
+ try:
102
+ original_driver.switch_to.default_content()
103
+ except Exception:
104
+ pass
105
+ raise
106
+ finally:
107
+ if switched_iframe and not stay_in_context:
108
+ try:
109
+ original_driver.switch_to.default_content()
110
+ except Exception:
111
+ pass
112
+
113
+
114
+
115
+ def click_element(selector: str, selector_type: str = "css") -> dict:
116
+ """Click an element."""
117
+ ctx = get_context()
118
+ if not ctx.driver:
119
+ return {"ok": False, "error": "No driver available"}
120
+ try:
121
+ el = find_element(driver=ctx.driver, selector=selector, selector_type=selector_type, timeout=10.0)
122
+ if not el:
123
+ return {"ok": False, "error": "Element not found"}
124
+ el.click()
125
+ return {"ok": True}
126
+ except Exception as e:
127
+ return {"ok": False, "error": str(e)}
128
+
129
+
130
+ def fill_text(selector: str, text: str, selector_type: str = "css") -> dict:
131
+ """Fill text into an element."""
132
+ ctx = get_context()
133
+ if not ctx.driver:
134
+ return {"ok": False, "error": "No driver available"}
135
+ try:
136
+ el = find_element(driver=ctx.driver, selector=selector, selector_type=selector_type, timeout=10.0)
137
+ if not el:
138
+ return {"ok": False, "error": "Element not found"}
139
+ el.clear()
140
+ el.send_keys(text)
141
+ return {"ok": True}
142
+ except Exception as e:
143
+ return {"ok": False, "error": str(e)}
144
+
145
+
146
+ def debug_element(selector: str, selector_type: str = "css") -> dict:
147
+ """Debug element information."""
148
+ ctx = get_context()
149
+ if not ctx.driver:
150
+ return {"ok": False, "error": "No driver available"}
151
+ try:
152
+ el = find_element(driver=ctx.driver, selector=selector, selector_type=selector_type, timeout=5.0)
153
+ if not el:
154
+ return {"ok": False, "error": "Element not found"}
155
+ return {
156
+ "ok": True,
157
+ "tag": el.tag_name,
158
+ "text": el.text,
159
+ "visible": el.is_displayed(),
160
+ "enabled": el.is_enabled(),
161
+ }
162
+ except Exception as e:
163
+ return {"ok": False, "error": str(e)}
164
+
165
+
166
+ __all__ = [
167
+ 'find_element',
168
+ '_wait_clickable_element',
169
+ 'get_by_selector',
170
+ 'click_element',
171
+ 'fill_text',
172
+ 'debug_element',
173
+ ]