> ## Documentation Index
> Fetch the complete documentation index at: https://browser-mcp.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Files and secret exports

> Transfer files and captured secrets with explicit, short-lived permissions.

Files and secrets stay on the browser host until an explicit narrow transfer. PostgreSQL and the native v3 control connection receive metadata only. The gateway joins two outbound HTTPS requests with backpressure; it does not spool payloads. This is a **single-replica, in-memory rendezvous**, not restart-transparent or horizontally distributed storage.

## Tools and flow

Tool names have the `browser_` prefix:

* `create_upload {name,size,sha256?}` prepares one exact-length upload (optional lowercase hex SHA-256).
* PUT the bytes using the returned capability. `transfer_status {resourceId}` reports browser-local verification state. Gateway transfer status is separately keyed by `transferId`.
* `upload_files {tabId,fileIds,ref?|selector?|chooserId?,frames?}` explicitly attaches completed staged IDs. No arbitrary filesystem path or inline bytes are accepted. The runtime retains the exact target element and checks its document generation; it never re-resolves a stale chooser. Attachment can immediately submit data to a website. An uncertain attachment must not be retried automatically.
* `list_downloads {}` lists actual browser download files. `create_download {fileId}` grants GET for that exact completed file, never a replay of its URL/request. POST/blob/data/one-use links work through Chrome's actual Download stream.
* `cancel_transfer {resourceId}` cancels a staged data resource. The existing `{tabId,eventId}` chooser/download cancellation has separate runtime semantics. Already attached bytes cannot be recalled; backing files remain until document/session lifecycle ends.
* `capture_secrets {tabId,code,frames?}` admits a bounded transaction. Within that function only, use `await browserMcp.secrets.set('TOKEN', document.querySelector('#token').value)`. The helper is not installed on `window` or as a global Playwright binding. It has no reader.
* `list_secrets {}` returns vault IDs/names/counts/expiry only; `delete_secrets {vaultIds}` deletes selected captures.
* `create_secret_export {vaultId,names,format:'json'|'dotenv'}` explicitly selects names from one capture and creates a short-lived immutable export. No automatic all-secrets export.

Create operations return browser resource metadata; the server issues separate agent/runtime capabilities and privately authorizes the runtime rendezvous. **Only the agent capability may enter MCP results; the runtime bearer must never enter MCP receipts.** Capabilities themselves are sensitive model-visible authority, not magically hidden by structured output.

## HTTP contract

Capability JSON includes `transferId`, `resourceId`, `method`, `url`, `headers.Authorization`, `expiresAt` (epoch ms), and limits. The agent endpoint is `/api/native-data/<opaque-id>`; a distinct bearer on `/runtime` is only for the browser host. Credentials are header-only; query strings, ambient cookies, Origin headers, redirects and ranges are rejected. No cookie authority or CORS permission.

Both sides and all joined streams expire at the absolute 60-second grant deadline (or earlier issuer expiry); attachment never extends it. The server revalidates issuer scope before issuance/redemption and every second during active leases, with a 900 ms fail-closed authorization deadline. **All grants permit exactly one request per side**, including ordinary files. Ranges/resumption/automatic retries are unsupported. After an ambiguous reply, query state rather than repeat the PUT or browser attachment. Request a new grant when needed; secret exports always require a fresh grant after uncertain delivery. Revocation aborts joined streams. Relay restart loses all grants.

Default ceilings: 256 MiB/file; 512 MiB/session; 1 GiB/browser-local spool and gateway browser reservations; 4 GiB/global gateway reservations; 32 concurrent gateway leases and 4 per authenticated session; 1,024 retained gateway lease records (including completed/cancelled metadata, expiring after four minutes); 128 local resources. Gateway queue watermarks are 64 KiB measured in bytes. Incoming HTTP chunks are sliced into 64 KiB writes with awaited backpressure; only one upstream chunk is retained at a time. The HTTP parser's incoming allocation remains bounded by the request/file ceiling and concurrency, not by the gateway queue watermark. Streams use bounded backpressure, not full-file memory buffers. Prepared files expire after five minutes; attached upload backing files survive until document/tab/session cleanup (relay disconnect/pause retains already attached backing files while pages survive). Private directories/files use modes 0700/0600. Only manifest-owned paths are deleted. Crash directories are intentionally retained rather than guessed safe to delete.

Chrome's original temporary spool is guarded by the native lifecycle's CDP download-progress admission: 256 MiB/file, 512 MiB aggregate active downloads, eight concurrent downloads and a ten-minute deadline. Installation fails closed if CDP download admission cannot be enabled. The plugin makes a bounded `Download.createReadStream()` copy, then deletes only that exact Download's original spool (also on failure). Progress cancellation is reactive and can overshoot between events; production needs an OS/filesystem quota for a hard whole-profile disk ceiling. No user's Downloads directory is scanned.

HTTPS is mandatory. Server/plugin constructors can explicitly enable `allowInsecureLoopback` for development-only localhost/127.0.0.1/\[::1] HTTP fixtures; this is not permitted for remote origins. Agent helpers remain HTTPS-only.

## Agent commands

Store capability JSON in a private mode-0600 file (or supply it via stdin), never a literal bearer argument:

```sh theme={null}
browser-mcp files upload --capability upload.cap.json --input ./large.bin
browser-mcp files download --capability download.cap.json --output ./received.bin
browser-mcp secrets export --capability secret.cap.json --format json --output ./secrets.json
browser-mcp secrets exec --capability secret.cap.json --format json -- my-program arg1
# --capability - reads bounded JSON from stdin
```

Output creation is exclusive, non-symlink-following and mode 0600; existing outputs are not overwritten. Helpers do not print secret plaintext. POSIX output protections are implemented; Windows output fails closed until explicit ACL support exists. `exec` invokes an executable with `shell:false`, injecting parsed values directly into its environment. The child can expose those values through its own output; its output is not magically redacted. NUL-containing environment values are rejected.

Curl interoperability uses a **protected header file**, not a token in command arguments:

```sh theme={null}
curl --fail --request PUT --header @upload.headers --data-binary @large.bin 'https://HOST/api/native-data/ID'
curl --fail --header @download.headers --output received.bin 'https://HOST/api/native-data/ID'
```

The header file contains `Authorization: Bearer ...`, must be mode 0600, and must never be committed. Curl output permissions/overwrite protection are the caller's responsibility (prefer helper commands). Do not use `--location` or automatic retries.

## Secret contract and limits

Variable names match `[A-Za-z_][A-Za-z0-9_]*`. Duplicate names within a capture reject the entire transaction; each successful capture creates a separate immutable version/vault ID. Maximum 128 variables/capture and 128 characters/name, 64 KiB UTF-8/value and 1 MiB aggregate runtime vault accounting (including names and per-entry overhead), five-minute TTL. Empty captures are rejected; entry ceilings are 32/session, 64/browser and 128/runtime. Exports recheck revocation and document identity after asynchronous resolution and immediately before resource admission. The capture deadline is 15 seconds. A timed-out page function may still execute, but it cannot commit to the vault; do not blindly re-run it. Diagnostics remain suppressed until its actual evaluation settles.

Capture return values are discarded. Exceptions are replaced with fixed errors; normal metadata contains no plaintext or plaintext-derived digest. Vault scope includes browser instance, authenticated credential/session, tab, origin and document generation. Navigation/tab close/session end/disconnect revoke vaults and exports and abort in-progress browser data requests. JavaScript memory offers no secure-erasure guarantee.

JSON is lossless for arbitrary strings. The documented dotenv dialect is exactly `NAME=<JSON string>` per line, with JSON escaping for newlines/quotes/backslashes/Unicode. The matching parser does no interpolation. This deliberately is **not shell syntax** and is not guaranteed compatible with every third-party dotenv package. **Never source untrusted page-derived text.**

This protects the dedicated capture path from accidental transcript leakage; it is not universal redaction. Arbitrary JavaScript, normal page text, screenshots/live view, malicious same-user processes, authorized client shells and the TLS-terminating server operator remain outside that guarantee. Operator-blind encryption and a trusted non-model capability delivery channel are not implemented.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.