"""Tool-name prefixing for the MCP surface. Hosts differ in how they namespace MCP tools. Hosts that already prefix tool names with the server name turn the built-in ``browser_`` prefix into stutter (``browser_cli_testing_browser_tabs_list``), while hosts that expose raw names need the prefix to keep ``navigate`` or ``screenshot`` unambiguous. The prefix is therefore configurable per MCP server process. """ from __future__ import annotations import os import re TOOL_PREFIX_ENV = "BROWSER_CLI_MCP_TOOL_PREFIX" DEFAULT_TOOL_PREFIX = "browser_" _VALID_PREFIX = re.compile(r"\A[a-z][a-z0-9_]*\Z") def resolve_tool_prefix(environ: dict[str, str] | None = None) -> str: """Return the configured tool-name prefix, defaulting to ``browser_``. An empty value disables prefixing for hosts that namespace tools themselves. """ configured = (environ if environ is not None else os.environ).get(TOOL_PREFIX_ENV) if configured is None: return DEFAULT_TOOL_PREFIX prefix = configured.strip() if not prefix: return "" if not _VALID_PREFIX.match(prefix): raise ValueError( f"{TOOL_PREFIX_ENV} must be lowercase letters, digits, and underscores starting " f"with a letter, or empty to disable prefixing; got {configured!r}" ) return prefix if prefix.endswith("_") else f"{prefix}_" def tool_name(base: str, prefix: str) -> str: """Apply *prefix* to a bare tool name such as ``tabs_list``.""" return f"{prefix}{base}"