Repository navigation
Added
-
MCP server.
browser-profiles mcp(also the binbrowser-profiles-mcp) speaks the Model
Context Protocol over stdio, so Claude Code, Claude Desktop and Cursor can manage profiles and
open protected browsers. Twelve tools, one per command:profile_list,profile_get,
profile_create,profile_update,profile_delete,profile_duplicate,browser_open,
browser_launch,browser_close,browser_close_all,browser_status,storage_path.claude mcp add browser-profiles -- npx -y @aitofy/browser-profiles mcp
-
Command registry. Every user-facing operation is one definition in
src/commands/; the CLI
and the MCP server are generated from it, so they cannot drift. Exported ascommands,
getCommand(),createCommandContext()andrunCommand()for in-process use. See
docs/adr/0001-command-registry.md. -
--jsonon every CLI command. Prints exactly the command's output object on stdout, with no
logs mixed in. -
browser status(aliasstatus,ps) lists running browsers with their CDP endpoints and
clears lock files left behind by crashed browsers. -
profile updateandprofile duplicatein the CLI, matching the library methods. -
BROWSER_PROFILES_HOMEoverrides the storage path. Precedence:--storage-path>
BROWSER_PROFILES_HOME>~/.aitofy/browser-profiles. -
Per-tab protection. New page targets opened over
wsEndpointby an external client
(Playwright MCP, Puppeteerconnect) get the same injections before the page runs, not only the
first tab. -
Pure User-Agent helpers exported:
buildUserAgent,buildBrands,buildUserAgentMetadata,
parseChromeVersion,resolveUserAgent. WebGL and worker helpers:createWebGLScript,
createWorkerSpoofScript,pickWebGLForPlatform. -
Unit tests (vitest) for UA/fingerprint consistency and WebGL/worker scripts, plus a headless
integration test opted into withBROWSER_PROFILES_E2E=1. -
GitHub Actions CI on Ubuntu and macOS, Node 20 and 22.
Changed
- CLI reorganised into a command tree (
profile create,browser open,storage path). The old
short forms are kept as top-level aliases:list,ls,info,create,open,launch,
close,delete,rm,path. - All diagnostics moved to stderr and are silent unless
DEBUG=browser-profiles*or--verbose.
stdout now belongs to--jsonand to the MCP protocol. browser-profiles pathreports the configured storage path instead of the hardcoded default.- WebGL vendor/renderer is chosen once per profile, consistent with its platform, and persisted in
fingerprint.webglinstead of being random per page load. - Removed the hardcoded
USER_AGENTSlist; the User-Agent is built from the running Chrome.
Fixed
- User-Agent now matches the running Chrome. The UA and Client Hints (
Sec-CH-UA,
navigator.userAgentData) were pinned to Chrome 119-121; current Chrome is 152, and detectors
compare the two. The launcher reads the real version viaBrowser.getVersionand builds the UA
from it. An explicitfingerprint.userAgentstill wins and logs a warning when its major
version differs. - WebGL vendor/renderer no longer leaks the real GPU on the Puppeteer and Playwright paths.
Protection scripts are injected through the automation library's own API, and the launcher
attaches at the browser target so pages opened later are covered too. - Web workers now see the spoofed navigator and WebGL (#1).
WorkerandSharedWorkerare
wrapped so the spoof runs before the worker script. Module workers and service workers are
passed through untouched. - Fingerprint injection never ran:
Page.addScriptToEvaluateOnNewDocumentwas sent before
Page.enable, so navigator overrides (platform, cores, memory) were silently ignored. - Every tab is now protected, not only the first. New tabs opened by Playwright MCP, Puppeteer or
the user are auto-attached and receive the same injections before any script runs. - The
Emulation.setTimezoneOverridetimezone now matches theTZChrome was started with
(profile, else proxy-detected, else host) instead of falling back toAmerica/New_York. DEBUG=browser-profiles*stays effective after Chrome launch (chrome-launcherrewrites
process.env.DEBUG).- Proxy URL parsing: an explicit default port (
http://host:80) is no longer dropped, a missing
port is rejected with an actionable message,socksandsocks5hnormalise tosocks5, and
percent-encoded credentials (p%40ss) are decoded correctly. - Profile cookies are installed once at the browser level (
Storage.setCookies), so every tab and
every browser context sees them.