The MCP client can set namespace, idleTimeout, headed, restore* and caCert on every tool call. extraArgs also still accepts --namespace, --idle-timeout, --restore and --headed (#2181 blocked --profile and --executable-path, but not these). So when the host starts agent-browser mcp with its own AGENT_BROWSER_NAMESPACE, AGENT_BROWSER_IDLE_TIMEOUT_MS and a clean profile, it cannot keep them. An agent passes idleTimeout: "0" or another namespace, and the host's idle cleanup does not reach that browser anymore.
We run many LLM agents in parallel on one MCP server and hit this: about 50 headless Chromes left over, 40 GB RSS on a 16 GB Mac. --allowed-domains blocks some launch options, but it needs a domain list, so it does not fit open-web research.
Repro
Server: AGENT_BROWSER_NAMESPACE=agents AGENT_BROWSER_IDLE_TIMEOUT_MS=600000 agent-browser mcp
{"name": "agent_browser_open", "arguments": {"url": "https://example.com", "idleTimeout": "0"}}
{"name": "agent_browser_open", "arguments": {"url": "https://example.com", "namespace": "other"}}
{"name": "agent_browser_snapshot", "arguments": {"extraArgs": ["--idle-timeout", "0"]}}All three are accepted. The daemon runs with idle shutdown off, or in a namespace the host does not clean.
What this changes
New opt-in agent-browser mcp --lock-launch (or AGENT_BROWSER_MCP_LOCK_LAUNCH=1):
- tool schemas drop
namespace,idleTimeout,restore*,caCert,clearCaCert,useSystemCa,headed,webgpu,webmcp. A call that still sends them gets invalid-params with a clear message. extraArgsalso rejects--namespace,--idle-timeout,--restore*,--headed,--webgpu,--no-webmcp,--engine. Same check style as #2181, only a longer list.agent_browser_batchrejects inner commands (typedcommands, and positionalextraArgs, which the CLI runs instead of them) that runconnector carry those flags. Today batch inner commands ignore global flags, butconnectworks there, and #1268 may add inline flags later.agent_browser_connect,agent_browser_plugin_addandagent_browser_chatare hidden. connect attaches another browser, plugin_add can write alaunch.mutateorbrowser.providerplugin into the config, and chat runs its own commands (connect is in its allow list).agent_browser_tools_profilescounts and restart hints follow the lock.sessionstill works, so each agent keeps its own browser inside the host's namespace and idle timeout.
Without the flag nothing changes. I did not do it like allowedDomains in #2181 (reject when env already sets it), because a per-call headed override of AGENT_BROWSER_HEADED is documented and tested, so that would break people. If you prefer another name or a different list, I can change it.
Not covered here: like the #2181 guard, a typed value that looks like a flag (#1997) can still pass one through, for example url: "--idle-timeout" with extraArgs: ["0"]. #2040 works on that. Also this is not a sandbox: the debug profile still has install, upgrade, doctor --fix and dashboard, so do not give that profile to agents you do not trust.
Docs: --help, README, docs site (commands, configuration), core skill and its reference. No changelog entry, since AGENTS.md says it is written at release.
Tests
- new unit tests in
cli/src/mcp.rs: flag and env parsing, locked schemas (connect, plugin_add, chat hidden), locked fields /extraArgsflags / hidden tools rejected, batch withconnector locked flags rejected, profile counts and hints,sessionand normalextraArgs/ batch still pass cargo fmt --check,cargo clippy -- -D warnings,cargo test --profile ci: pass (1486 passed, main was 1480). One run hitnative::actions::tests::test_execute_unknown_commandfailing with "Invalid CDP target: invalid-cdp-target": it readsAGENT_BROWSER_CDPwithout the env guard while the next test sets it. Not related to this change: it also fails with only thenative::actions::tests::test_execute*tests selected, and reruns are green.pnpm --filter docs test,type-check,build,test:routesfor production and preview: passpnpm run test:launcher,check-version-sync.js: pass- by hand, built binary over stdio with
--lock-launch:tools/listhas no locked fields, the repro calls above, connect, and batch[["connect","9222"]]get invalid-params, no daemon starts
macOS arm64, Rust 1.99.1, Node 26 (CI uses 24). I did not run the ignored e2e tests, this does not touch the daemon.
@Nyarlathoteppppp is attempting to deploy a commit to the Vercel Labs Team on Vercel.
A member of the Team first needs to authorize it.