30
30
import uvicorn
31
31
32
32
# Browser-use library imports
33
- from browser_use import Agent
33
+ from browser_use import Agent , BrowserSession , BrowserProfile
34
34
from browser_use .browser .browser import Browser , BrowserConfig
35
- from browser_use .browser .context import BrowserContext , BrowserContextConfig
36
35
from dotenv import load_dotenv
37
36
from langchain_core .language_models import BaseLanguageModel
38
37
45
44
from pythonjsonlogger import jsonlogger
46
45
from starlette .applications import Starlette
47
46
from starlette .routing import Mount , Route
47
+ from utils .twofa import controller
48
48
49
49
# Configure logging
50
50
logger = logging .getLogger ()
@@ -138,16 +138,16 @@ def init_configuration() -> Dict[str, Any]:
138
138
task_store : Dict [str , Dict [str , Any ]] = {}
139
139
140
140
141
- async def create_browser_context_for_task (
141
+ async def create_browser_session_for_task (
142
142
chrome_path : Optional [str ] = None ,
143
143
window_width : int = CONFIG ["DEFAULT_WINDOW_WIDTH" ],
144
144
window_height : int = CONFIG ["DEFAULT_WINDOW_HEIGHT" ],
145
145
locale : str = CONFIG ["DEFAULT_LOCALE" ],
146
- ) -> Tuple [ Browser , BrowserContext ] :
146
+ ) -> BrowserSession :
147
147
"""
148
- Create a fresh browser and context for a task.
148
+ Create a fresh browser and session for a task.
149
149
150
- This function creates an isolated browser instance and context
150
+ This function creates an isolated browser instance and session
151
151
with proper configuration for a single task.
152
152
153
153
Args:
@@ -157,42 +157,48 @@ async def create_browser_context_for_task(
157
157
locale: Browser locale
158
158
159
159
Returns:
160
- A tuple containing the browser instance and browser context
160
+ A tuple containing the browser instance and browser session
161
161
162
162
Raises:
163
- Exception: If browser or context creation fails
163
+ Exception: If browser or session creation fails
164
164
"""
165
165
try :
166
- # Create browser configuration
167
- browser_config = BrowserConfig (
168
- extra_chromium_args = CONFIG ["BROWSER_ARGS" ],
169
- )
170
-
171
- # Set chrome path if provided
172
- if chrome_path :
173
- browser_config .chrome_instance_path = chrome_path
174
-
175
- # Create browser instance
176
- browser = Browser (config = browser_config )
177
-
178
- # Create context configuration
179
- context_config = BrowserContextConfig (
166
+ # Create session configuration
167
+ browser_profile = BrowserProfile (
180
168
wait_for_network_idle_page_load_time = 0.6 ,
181
169
maximum_wait_page_load_time = 1.2 ,
182
170
minimum_wait_page_load_time = 0.2 ,
183
- browser_window_size = {"width" : window_width , "height" : window_height },
171
+ window_size = {"width" : window_width , "height" : window_height },
172
+ viewport = {"width" : window_width , "height" : window_height },
184
173
locale = locale ,
185
174
user_agent = CONFIG ["DEFAULT_USER_AGENT" ],
186
175
highlight_elements = True ,
187
176
viewport_expansion = 0 ,
177
+ chromium_sandbox = False ,
178
+ )
179
+
180
+
181
+ # Create session with the browser
182
+ session = BrowserSession (
183
+ browser_profile = browser_profile ,
184
+ headless = True ,
185
+ browser_args = [
186
+ '--no-sandbox' ,
187
+ '--disable-setuid-sandbox' ,
188
+ '--no-first-run' ,
189
+ '--disable-default-apps' ,
190
+ '--disable-extensions-except=' ,
191
+ '--disable-background-timer-throttling' ,
192
+ '--disable-backgrounding-occluded-windows' ,
193
+ '--disable-renderer-backgrounding' ,
194
+ '--disable-features=TranslateUI' ,
195
+ '--disable-ipc-flooding-protection'
196
+ ]
188
197
)
189
198
190
- # Create context with the browser
191
- context = BrowserContext (browser = browser , config = context_config )
192
-
193
- return browser , context
199
+ return session
194
200
except Exception as e :
195
- logger .error (f"Error creating browser context : { str (e )} " )
201
+ logger .error (f"Error creating browser session : { str (e )} " )
196
202
raise
197
203
198
204
@@ -201,6 +207,8 @@ async def run_browser_task_async(
201
207
url : str ,
202
208
action : str ,
203
209
llm : BaseLanguageModel ,
210
+ sensitive_data : Dict [str , str ] | None = None ,
211
+
204
212
window_width : int = CONFIG ["DEFAULT_WINDOW_WIDTH" ],
205
213
window_height : int = CONFIG ["DEFAULT_WINDOW_HEIGHT" ],
206
214
locale : str = CONFIG ["DEFAULT_LOCALE" ],
@@ -218,13 +226,13 @@ async def run_browser_task_async(
218
226
task_id: Unique identifier for the task
219
227
url: URL to navigate to
220
228
action: Action to perform after navigation
229
+ sensitive_data: Sensitive data to use for the task
221
230
llm: Language model to use for browser agent
222
231
window_width: Browser window width
223
232
window_height: Browser window height
224
233
locale: Browser locale
225
234
"""
226
- browser = None
227
- context = None
235
+ session = None
228
236
229
237
try :
230
238
# Update task status to running
@@ -278,19 +286,33 @@ async def done_callback(history: Any) -> None:
278
286
# Get Chrome path from environment if available
279
287
chrome_path = os .environ .get ("CHROME_PATH" )
280
288
281
- # Create a fresh browser and context for this task
282
- browser , context = await create_browser_context_for_task (
289
+ # Create a fresh browser and session for this task
290
+ session = await create_browser_session_for_task (
283
291
chrome_path = chrome_path ,
284
292
window_width = window_width ,
285
293
window_height = window_height ,
286
294
locale = locale ,
287
295
)
288
296
289
- # Create agent with the fresh context
297
+ action = f"""
298
+ { action } \n \n \n
299
+ Considerations:
300
+ - NEVER hallucinate login credentials.
301
+ - ALWAYS use the get_otp_2fa action to retrieve the 2FA code if needed.
302
+ - NEVER skip the 2FA step if the page requires it.
303
+ - NEVER extract the code from the page.
304
+ - NEVER use a code that is not generated by the get_otp_2fa action.
305
+ - NEVER hallucinate the 2FA code, always use the get_otp_2fa action to get it.
306
+ """
307
+
308
+ # Create agent with the fresh session
290
309
agent = Agent (
291
310
task = f"First, navigate to { url } . Then, { action } " ,
292
311
llm = llm ,
293
- browser_context = context ,
312
+ sensitive_data = sensitive_data ,
313
+ use_vision = False ,
314
+ browser_session = session ,
315
+ controller = controller ,
294
316
register_new_step_callback = step_callback ,
295
317
register_done_callback = done_callback ,
296
318
)
@@ -349,10 +371,8 @@ async def done_callback(history: Any) -> None:
349
371
finally :
350
372
# Clean up browser resources
351
373
try :
352
- if context :
353
- await context .close ()
354
- if browser :
355
- await browser .close ()
374
+ if session :
375
+ await session .close ()
356
376
logger .info (f"Browser resources for task { task_id } cleaned up" )
357
377
except Exception as e :
358
378
logger .error (
@@ -467,6 +487,7 @@ async def call_tool(
467
487
url = arguments ["url" ],
468
488
action = arguments ["action" ],
469
489
llm = llm ,
490
+ sensitive_data = arguments .get ("sensitive_data" , None ),
470
491
window_width = window_width ,
471
492
window_height = window_height ,
472
493
locale = locale ,
@@ -608,6 +629,13 @@ async def list_tools() -> list[types.Tool]:
608
629
"type" : "string" ,
609
630
"description" : "Action to perform in the browser" ,
610
631
},
632
+ "sensitive_data" : {
633
+ "type" : "object" ,
634
+ "description" : "Dictionary of sensitive data to use for the task (e.g. credentials)" ,
635
+ "additionalProperties" : {
636
+ "type" : "string"
637
+ }
638
+ },
611
639
},
612
640
},
613
641
),
@@ -643,6 +671,13 @@ async def list_tools() -> list[types.Tool]:
643
671
"type" : "string" ,
644
672
"description" : "Action to perform in the browser" ,
645
673
},
674
+ "sensitive_data" : {
675
+ "type" : "object" ,
676
+ "description" : "Dictionary of sensitive data to use for the task (e.g. credentials)" ,
677
+ "additionalProperties" : {
678
+ "type" : "string"
679
+ }
680
+ },
646
681
},
647
682
},
648
683
),
@@ -656,7 +691,14 @@ async def list_tools() -> list[types.Tool]:
656
691
"task_id" : {
657
692
"type" : "string" ,
658
693
"description" : "ID of the task to get results for" ,
659
- }
694
+ },
695
+ "sensitive_data" : {
696
+ "type" : "object" ,
697
+ "description" : "Dictionary of sensitive data to use for the task (e.g. credentials)" ,
698
+ "additionalProperties" : {
699
+ "type" : "string"
700
+ }
701
+ },
660
702
},
661
703
},
662
704
),
@@ -772,7 +814,7 @@ def main(
772
814
Run the browser-use MCP server.
773
815
774
816
This function initializes the MCP server and runs it with the SSE transport.
775
- Each browser task will create its own isolated browser context .
817
+ Each browser task will create its own isolated browser session .
776
818
777
819
The server can run in two modes:
778
820
1. Direct SSE mode (default): Just runs the SSE server
0 commit comments