Instances & isolation¶
justpen-browser-mcp manages named instances up to a configured capacity. Each instance
is its own Camoufox process — a separate stealth-patched Firefox — with its own
BrowserForge fingerprint and separate browser session state.
Why instances matter¶
A single server process can drive:
- Parallel logged-in sessions — one instance per user / tenant, no cookie bleed.
- Clean-slate flows — use an ephemeral instance and destroy it after a
test to discard its session state. A persistent
profile_dirsurvives destruction; choose a fresh profile directory when you need a new session. - Fingerprint diversity — each instance rolls a fresh BrowserForge fingerprint at launch, making parallel sessions look like different real browsers to fingerprinting detectors.
- Per-instance proxies — route different instances through different outbound proxies without shared state.
Isolation boundaries¶
Each instance has its own:
| Boundary | What it covers |
|---|---|
| OS process | Camoufox runs in a separate process; a crash in one instance does not affect others. |
| BrowserForge fingerprint | Canvas, WebGL, font list, timezone, language, and dozens of other signals are independently generated per launch. |
| Cookies & storage | Cookies, localStorage, sessionStorage, and cache are isolated from every other instance. |
| Optional proxy | The proxy parameter scopes a SOCKS5/HTTP proxy to this instance only. |
| Optional persistent profile | The profile_dir parameter pins a Firefox-style profile directory; omit it for an ephemeral instance. |
Naming¶
Instances are identified by a string name of your choice. Names are
case-sensitive. Creation and destruction use the name parameter; other tools
scoped to an instance use instance.
See the Lifecycle tools page for creation
and teardown.
Ephemeral vs. persistent¶
profile_dir=None (the default) creates an ephemeral instance without a
reusable persistent profile. Its session is discarded when the instance closes.
The browser can still create temporary profile files; ephemeral mode does not
guarantee that no files are written to disk.
profile_dir="/path/to/dir" creates a persistent instance. Cookies,
localStorage, saved passwords, and other profile data survive across
browser_destroy_instance / browser_create_instance cycles. The directory
persists on disk even after the instance is destroyed.
Fingerprint re-roll on restart
BrowserForge generates a fresh fingerprint on every Camoufox launch, even
for persistent instances. This means the fingerprint will differ between
runs of the same profile_dir. The stored profile data (cookies, storage)
is still preserved; only the fingerprint signals change.
Instance cap¶
BROWSER_MCP_MAX_INSTANCES (default 10) sets the maximum number of
reserved instances, including launches, live browsers, and unfinished teardown. Attempting to create an instance beyond the cap
returns an instance_limit_exceeded error. Invalid values (non-integer, zero,
or negative) fall back to 10 with a warning logged to stderr.
Crash detection¶
Camoufox runs as a separate OS process per instance (see Isolation
boundaries), and that process can disconnect or crash
independently of the server. The manager listens for that disconnect and
flips the instance's internal status to "crashed" — it does not evict the
instance immediately.
Eviction happens lazily, on the next tool call that resolves the
instance: that call frees the crashed instance's resources asynchronously
and returns an instance_crashed error (see envelope error
codes) instead of operating
on a dead browser. Until that next call happens, browser_list_instances
and browser_health will show
the instance with status: "crashed".
browser_destroy_instance
is the exception to lazy eviction: it works on a crashed instance directly,
tearing it down cleanly and returning success, so you don't need to trigger
eviction with another tool first.
If the crashed instance was created with a profile_dir, that persistent
profile directory survives on disk — a crash does not delete stored cookies
or other profile data, same as a clean browser_destroy_instance.
Idle reaper¶
A background task can automatically close instances that have been idle too long, so long-running servers don't accumulate abandoned browser processes. "Idle" is measured as time since the last tool operation on that instance — the clock is refreshed when serialized work starts and finishes. Busy instances and queued operations are skipped, and the reaper uses monotonic elapsed time.
The reaper is controlled by two settings (see Configuration):
| Setting | CLI flag | Default | Description |
|---|---|---|---|
BROWSER_MCP_IDLE_TTL_SECONDS |
--idle-ttl |
0 |
Idle threshold in seconds. 0 disables the idle reaper entirely. |
BROWSER_MCP_REAPER_INTERVAL_SECONDS |
--reaper-interval |
30 |
How often (in seconds) the reaper checks for idle/crashed instances. |
Disabled by default
The idle reaper only runs when BROWSER_MCP_IDLE_TTL_SECONDS is set above
0. With the default of 0, instances are never closed for being idle —
only explicit browser_destroy_instance calls (or a crash) remove them.
When enabled, each reaper pass also closes any lingering "crashed"
instances as a backstop — instances usually get evicted the moment a caller
touches them again (see crash detection above), but one
that nobody calls after crashing would otherwise sit in the registry
indefinitely. The crashed-instance backstop always runs when the reaper is
active, independent of the idle TTL value.
Reaping only closes the underlying browser process; a persistent instance's
profile_dir is left untouched on disk, exactly like browser_destroy_instance.
Why this is stronger than a shared process model¶
Separate browser processes improve fault containment and let each launch use its own fingerprint and session data. They share the host, network resources, filesystem permissions, and the Python MCP server process. This is not an OS security boundary between untrusted tenants, and it does not promise immunity to timing or fingerprint correlation. Camoufox uses Firefox's JavaScript engine. Use external process/container supervision when stronger containment is needed.
Lifecycle tools¶
Use these tools to manage instance lifetimes:
browser_create_instance— launch a new instance.browser_destroy_instance— shut down an instance and release its resources.browser_list_instances— inspect all currently live instances.browser_health— check server status without launching a browser.
Single active page assumption¶
Within an instance, the MCP surface currently operates on a single active page. Opening a second tab is supported, but most tools target the active page; see Page tools for switching.
Identity, concurrency and teardown¶
Each launch has a new instance_id; each tab has a stable page_id until it
closes. A reused name or tab index does not reuse that identity. The active tab
is tracked by its page object, so an unrelated popup or tab removal does not
silently retarget subsequent operations.
Actions serialize within an instance; different instances can run concurrently.
Launch and teardown do not hold the registry lock while waiting on the browser.
BROWSER_MCP_OPERATION_TIMEOUT_SECONDS bounds cooperative operations including
queue time. A timeout after execution starts leaves side effects uncertain; use
operation metadata before retrying.
Destroy removes an instance from active listings, waits for work to drain, then
cancels blocked work and closes resources within BROWSER_MCP_CLOSE_TIMEOUT_SECONDS.
Names, capacity slots, and profile directories stay reserved until cleanup is
confirmed. Failed or timed-out teardown remains close_failed in browser_health;
failed launch rollback appears in failed_launches. Inspect and stop any surviving
browser through your process supervisor before restarting the server. Repeated
destroy calls do not pretend that an incomplete cleanup succeeded.
Shutdown stops admission permanently for that manager. Calling destroy or shutdown
from the instance's own browser_run_code operation is rejected to prevent a
self-wait. See process limits.
Explicit page targets¶
Use page_id from browser_tabs to address a particular live page. Supported
page actions resolve it after acquiring the instance lock. They do not change
selected-tab state or create a replacement page. A foreign, closed, or unknown ID
returns page_not_found, including when a page closes while the action is queued.
Omitting the ID retains selected-page behavior and existing automatic page creation.
Closing an explicitly targeted unselected page preserves the selected page.
Frame-capable tools also accept frame_id from browser_frames. A frame must
belong to the resolved page; see frame refs.
Coordinate mouse, screenshot, resize, navigation, and keyboard tools remain
page-level. Keyboard input follows actual focus, including focus inside an iframe.