6565"""
6666from __future__ import annotations
6767import atexit
68+ import os
6869import sys
6970from functools import wraps
71+ from pathlib import Path
7072from typing import Any , Literal
7173from mcp .server import MCPServer
7274from mcp .server .mcpserver .exceptions import ToolError
@@ -1016,6 +1018,15 @@ def type_text(
10161018 Returns:
10171019 A confirmation message after the operation succeeds;
10181020 otherwise the error handler returns the resulting failure.
1021+
1022+ Notes:
1023+ Including "\\ n" in your `text` (except in "set_value" mode) will
1024+ simulate pressing the "Enter" key, which is useful for submitting
1025+ forms or triggering search inputs without needing a separate click.
1026+
1027+ Tool selection:
1028+ - Need to update text that appears in a text field -> use this tool.
1029+ - Need to update the value of a <select> element -> use select_option.
10191030 """
10201031 sb = _get_sb ()
10211032
@@ -1398,11 +1409,13 @@ def assert_condition(
13981409# Cookies & storage
13991410# ---------------------------------------------------------------------------
14001411
1401- @mcp .tool (title = "Manage Cookies" )
1402- # Annotations intentionally omitted: 'get_all' is a pure read, 'clear' is
1403- # destructive, and 'save'/'load' are file/session I/O -- no single
1404- # read_only_hint or destructive_hint value would be accurate for the whole
1405- # tool.
1412+ @mcp .tool (
1413+ title = "Manage Cookies" ,
1414+ annotations = ToolAnnotations (
1415+ idempotent_hint = True ,
1416+ open_world_hint = True ,
1417+ ),
1418+ )
14061419@handle_sb_errors
14071420def manage_cookies (
14081421 action : Literal ["get_all" , "clear" , "save" , "load" ] = "get_all" ,
@@ -1417,16 +1430,16 @@ def manage_cookies(
14171430
14181431 Args:
14191432 action:
1420- - "get_all": Return all cookies currently available to the browser,
1421- including attributes such as name, value, domain, path, expiry ,
1422- and security flags.
1433+ - "get_all": Return all cookies currently available to the
1434+ browser, including attributes such as name, value, domain,
1435+ path, expiry, and security flags.
14231436 - "clear": Delete all cookies from the current browser session.
1424- - "save": Save current cookies to filename. The file may be
1425- created or overwritten.
1437+ - "save": Save current cookies to filename.
14261438 - "load": Load cookies from filename into the current browser
14271439 session.
14281440
1429- filename: Filesystem path used by save/load.
1441+ filename: The name of the file to save/load cookies from.
1442+ Will be sanitized and saved in a restricted directory.
14301443 Ignored for get_all and clear.
14311444
14321445 Returns:
@@ -1440,36 +1453,54 @@ def manage_cookies(
14401453 identifiers, and other private information. Only inspect, save,
14411454 load, or share cookies when explicitly authorized.
14421455
1443- `filename` is passed to SeleniumBase's cookie persistence methods and
1444- can access the filesystem available to the MCP server. Use only
1445- trusted, authorized paths. The save action may overwrite an existing
1446- file.
1447-
14481456 Notes:
14491457 Loading saved cookies does not guarantee restoration of a login.
14501458 Cookies may be expired, invalidated, domain/path restricted, or
1451- dependent on other browser state.
1459+ dependent on other browser state. Navigate to the relevant site when
1460+ necessary so the browser has the appropriate origin for the cookies.
14521461
1453- When not to use:
1454- - Do not use this tool to load cookies if the cookie origin does
1455- not match the origin of the current page.
1462+ Tool selection:
1463+ - Need cookies or authentication cookies -> use this tool.
1464+ - Need localStorage/sessionStorage -> use manage_storage.
1465+ - Need arbitrary JavaScript or storage operations not covered here ->
1466+ use run_javascript.
1467+ - Need visible page content or HTML -> use get_content.
1468+ - Need an element's HTML attributes -> use get_attributes.
14561469 """
14571470 sb = _get_sb ()
14581471
1472+ # Define a safe sandbox directory for cookies
1473+ cookie_dir = Path ("./saved_cookies" )
1474+ cookie_dir .mkdir (parents = True , exist_ok = True )
1475+
14591476 if action == "get_all" :
14601477 return sb .get_all_cookies ()
14611478
14621479 if action == "clear" :
14631480 sb .clear_cookies ()
14641481 return "Cookies cleared."
14651482
1483+ # Security: Force isolation to prevent path traversal
1484+ # (e.g., "../../../etc/passwd")
1485+ safe_filename = os .path .basename (filename )
1486+ if not safe_filename .endswith (".txt" ):
1487+ safe_filename += ".txt"
1488+
1489+ # Use pathlib's division operator to join paths
1490+ safe_path = cookie_dir / safe_filename
1491+
14661492 if action == "save" :
1467- sb .save_cookies (name = filename )
1468- return f"Cookies saved to { filename } "
1493+ sb .save_cookies (name = str ( safe_path ) )
1494+ return f"Cookies saved safely to { safe_path . name } "
14691495
14701496 if action == "load" :
1471- sb .load_cookies (name = filename )
1472- return f"Cookies loaded from { filename } "
1497+ if not safe_path .exists ():
1498+ return (
1499+ f"Error: Could not load. { safe_path .name } does not "
1500+ "exist in the cookie directory."
1501+ )
1502+ sb .load_cookies (name = str (safe_path ))
1503+ return f"Cookies loaded from { safe_path .name } "
14731504
14741505 return (
14751506 f"Error: unknown action '{ action } '. "
0 commit comments