
Research
/Security News
737 Chrome VPN Extensions Linked to Brand Impersonation and Browser Traffic Redirection
The campaign amassed more than 75,000 installs by targeting Russian-speaking users seeking access to blocked services.
@fetchproxy/cli
Advanced tools
One-shot CLI for the fetchproxy bridge: authenticated fetches and session reads through the user's signed-in browser tab, scoped by per-service profiles.
fpx— a one-shot CLI for the fetchproxy bridge: authenticated fetches and session reads through the user's signed-in browser tab, straight from a shell prompt or a skill.
@fetchproxy/server and @fetchproxy/bootstrap are libraries an MCP server embeds. fpx is the same bridge wrapped as a standalone binary — no Node process to write, no MCP server to run. Point it at a URL, get the response on stdout; point it at a storage bucket, get JSON back. Useful anywhere a skill or shell script needs one authenticated request and doesn't want to carry a whole MCP.
npm install -g @fetchproxy/cli
Or run it without installing:
npx @fetchproxy/cli profile list
Either way, the user also needs the fetchproxy browser extension (Transporter) installed — see the top-level README.
fpx scopes every command to a named profile — a small JSON record describing one service: its declared domains, and (optionally) the cookie keys, storage keys, capture-headers, and IndexedDB scopes it's allowed to read. Profiles live at $FETCHPROXY_CLI_HOME/profiles.json, or ~/.fetchproxy/cli/profiles.json if that variable is unset.
fpx profile add opentable --domain opentable.com
fpx profile list
# opentable opentable.com
Each profile gets its own long-term identity, keyed by name: profile opentable connects to the bridge as fpx-opentable, with its identity keypair persisted at ~/.fetchproxy/identity/fpx-opentable.json. This mirrors how a real opentable-mcp would identify itself — the extension's trust store, pair history, and capability grants are all keyed off that per-service identity, not off fpx itself. Running fpx against ten services looks, from the extension's point of view, like ten independent MCPs.
The first time any verb connects under a given profile, the extension doesn't auto-trust it. fpx prints a 6-digit pair code to stderr:
$ fpx health -p opentable
fetchproxy pair code: 482-913 — approve in the Transporter extension popup
Open the Transporter popup, confirm the code matches, click Approve. Every subsequent command against that profile — from any verb — reuses the same trust record and skips the prompt.
fpx profile declare widens a profile's scope (more cookie keys, a new capture-header, etc.). Because the extension's trust is keyed to (identity, domains, capabilities), widening the scope changes the hello the next connection sends, and the extension treats that as a diff worth re-confirming:
fpx profile declare opentable --cookie oaid --capture-header x-csrf-token@www.opentable.com
# profile "opentable" scope updated — the next connect will ask you to re-pair (scope diff)
The next command against opentable prints a fresh pair code even though the identity is unchanged.
fpx profile remove <name> deletes the local profile entry and its identity file:
fpx profile remove opentable
# profile "opentable" removed — also revoke fpx-opentable in the Transporter extension popup
That only cleans up the CLI's side. The extension still holds a trust row for fpx-opentable until the user opens the Transporter popup and revokes it there — removing the profile does not reach into the browser.
Every verb takes -p/--profile <name> (except the profile subcommands themselves, which take the name as a positional).
| Command | What it does | Example |
|---|---|---|
fpx profile add <name> --domain <apex>… | Create a profile with one or more declared domains. | fpx profile add opentable --domain opentable.com |
fpx profile declare <name> [--cookie k]… [--local-storage k]… [--session-storage k]… [--capture-header name@host[/path]]… [--dom-selector handle=css]… [--allow-download] | Widen a profile's scope. Merges with the existing declaration; forces a re-pair. | fpx profile declare opentable --cookie oaid |
fpx profile list | List all profiles and their domains (tab-separated, one per line). | fpx profile list |
fpx profile show <name> | Print a profile's full JSON record. | fpx profile show opentable |
fpx profile remove <name> | Delete the profile and its identity file. | fpx profile remove opentable |
fpx pair -p <name> [--domain <apex>] | Force a pairing round-trip against one declared domain (defaults to the only one, if there's exactly one). | fpx pair -p opentable |
fpx health -p <name> | Print the bridge's health snapshot (host/peer role, connection state). | fpx health -p opentable |
fpx get <url> -p <name> [--json] [-H 'K: V']… | GET a URL through the profile's tab. | fpx get https://www.opentable.com/ -p opentable |
fpx post-json <url> <body|@file> -p <name> [--json] [-H 'K: V']… | POST a JSON body (literal or @file); sets Content-Type: application/json unless overridden. | fpx post-json https://www.opentable.com/dapi/fe/gql '{"operationName":"Autocomplete"}' -p opentable |
fpx request <url> -p <name> [-X METHOD] [-H 'K: V']… [-d body|@file] [--json] | Arbitrary method/headers/body. | fpx request https://www.opentable.com/x -p opentable -X DELETE |
fpx cookies [keys…] -p <name> | Read declared cookies (all declared keys if none given). | fpx cookies -p opentable |
fpx local-storage [keys…] -p <name> | Read declared localStorage keys. | fpx local-storage authToken -p opentable |
fpx session-storage [keys…] -p <name> | Read declared sessionStorage keys. | fpx session-storage csrfToken -p opentable |
fpx indexeddb -p <name> | Read all declared IndexedDB scopes (no key arguments — scopes come from the profile). | fpx indexeddb -p opentable |
fpx session -p <name> [--storage-domain d] [--storage-subdomain s] | Bootstrap-parity one-shot: pair (if needed), read every declared bucket, close, print the combined session JSON. | fpx session -p opentable |
fpx dom <name…> -p <name> [--storage-domain d] [--storage-subdomain s] | Read declared DOM selector values (all declared selectors if no names given). Requires --dom-selector declarations. | fpx dom title -p opentable |
fpx download <url> -p <name> [--filename f] | Download a URL through the browser's own network stack (chrome.downloads — real cookies + TLS fingerprint); prints {path, bytes, mime?, finalUrl?} for the saved local file. Requires --allow-download. | fpx download https://www.opentable.com/f.pdf -p opentable |
fpx --version (or -v) | Print the CLI version to stdout. The version also appears in the fpx / fpx --help header. | fpx --version |
--storage-domain / --storage-subdomain (on the storage-read verbs, session, and dom) select which declared domain to read from when a profile declares more than one — required only in that case, same as the underlying library.
--dom-selector <handle>=<css> (on profile declare) declares a named DOM read: <handle> is the logical name fpx dom references, <css> is the document.querySelector CSS selector the extension reads (first match only, no page-JS execution). --allow-download grants the profile the download capability, letting fpx download save a declared-domain URL through the browser's own network stack.
--json envelopes, storage-read JSON, profile list/profile show output.profile "x" created …, paired ✓ …), hints, and error messages.This split means fpx get … | jq . or fpx cookies -p x > cookies.json never picks up incidental noise.
| Code | Meaning |
|---|---|
0 | Success. |
1 | Usage error — bad flags, unknown command, unknown profile, undeclared scope, malformed body. |
2 | Bridge unavailable — extension not connected, pairing still pending, or an unexpected bridge-level failure. |
3 | Bot wall detected in the response (Akamai/Cloudflare-style interstitial). |
4 | Upstream HTTP error — the request reached the site but got a non-2xx response. |
Exit codes 3 and 4 are emitted only by the fetch verbs (get, post-json, request); the pair, health, session, read verbs (cookies/local-storage/session-storage/indexeddb), dom, and download all return 0 on a successful bridge round-trip regardless of upstream status.
FETCHPROXY_CLI_HOMEProfiles are stored at $FETCHPROXY_CLI_HOME/profiles.json if that environment variable is set, otherwise at ~/.fetchproxy/cli/profiles.json. Set it to isolate fpx state per-shell, per-CI-job, or for a smoke test:
FETCHPROXY_CLI_HOME=$(mktemp -d) fpx profile add scratch --domain example.com
Per-service identity files are unaffected by this variable — they always live at ~/.fetchproxy/identity/fpx-<name>.json.
Every verb — get, post-json, request, cookies, local-storage, session-storage, indexeddb, dom, download, even health and pair — derives its hello frame from the full profile record via the same serverOptsFor() helper, not just the fields that particular verb happens to touch. That's deliberate: the extension's trust is keyed to (identity, domains, capabilities), so if fpx get sent a narrower hello than fpx cookies, alternating between the two verbs on the same profile would look like a capability change and force a re-pair every time. Sending the same hello for every verb means you can freely interleave fpx get, fpx cookies, fpx dom, etc. against one profile and only ever pair once — a re-pair only happens when fpx profile declare actually changes the stored scope.
One exception: fpx session goes through @fetchproxy/bootstrap directly, not serverOptsFor(), and bootstrap has no concept of domSelectors/download — those two fields only exist for fpx's own dom/download verbs. So a profile that declares --dom-selector/--allow-download sends a wider hello on the direct verbs than fpx session does. In practice this costs nothing but a one-time, non-blocking re-pair the first time you alternate between fpx session and fpx dom/fpx download on such a profile — the same self-healing behavior already accepted for the storage-pointer scopes.
fpx is designed to be the thing a skill shells out to when it needs one authenticated read, without embedding a bridge client. A typical pattern:
# One-time setup (pairs interactively):
fpx profile add opentable --domain opentable.com
fpx pair -p opentable
# From then on, any skill script can do:
fpx get -p opentable 'https://www.opentable.com/dapi/fe/gql?...' --json | jq .body
Or, scoped to a declared cookie for a lightweight auth check:
fpx cookies oaid -p opentable | jq -r .oaid
Because pairing is per-profile and persists across invocations, a skill can call fpx repeatedly across a session — once per tool call, even — without re-triggering the pair prompt after the first approval.
FAQs
One-shot CLI for the fetchproxy bridge: authenticated fetches and session reads through the user's signed-in browser tab, scoped by per-service profiles.
The npm package @fetchproxy/cli receives a total of 424 weekly downloads. As such, @fetchproxy/cli popularity was classified as not popular.
We found that @fetchproxy/cli demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
The campaign amassed more than 75,000 installs by targeting Russian-speaking users seeking access to blocked services.

Company News
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.

Security News
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.