Skip to main content
Glama
mienetic

Ghostvault

by mienetic

πŸ‘» Ghostvault

Source-available MCP server for managing browser sessions on any website through your AI agent β€” powered by Camoufox.

CI License: Apache 2.0 + Commons Clause Python 3.11+ MCP Beta

Let Claude Desktop, Cursor, Cline, or any MCP-compatible agent sign in to any website β€” Google, GitHub, Facebook, your bank, internal apps β€” switch between accounts, scrape pages, call APIs, and automate any login-gated flow. Each account gets a locked anti-detect fingerprint and a persistent session that survives restarts.

Quick start Β· How it works Β· Tools Β· Docs Β· FAQ Β· Contributing


Why Ghostvault

Managing multiple accounts across websites from automation is painful:

  • πŸ”’ Anti-bot detection flags headless browsers, datacenter IPs, and behavioral patterns

  • πŸ” Account hopping requires re-authentication every time

  • 🌐 Login-gated sites don't expose API access

  • πŸ€– Detecting login options (SSO vs form) and choosing the right path is manual

Ghostvault solves this by giving your AI agent a real, anti-detect browser per account β€” with sessions that persist between restarts, fingerprints that don't drift, and a provider system that works with any website (not just Google).

Related MCP server: browser-auth-mcp

Features

  • 🎭 Locked fingerprints β€” each account always looks like the same device (Camoufox C-level spoofing + persisted noise seeds + advanced injection: locale, timezone, fonts, WebGL, WebRTC gate, battery, media devices)

  • 🧩 Presets + advanced config β€” balanced / stealth / minimal presets + 105 Camoufox config keys + 10 device profile templates (macbook, thinkpad, surface, ...)

  • πŸ”Œ Provider-agnostic login β€” built-in providers (google, github, facebook) + create custom providers for any website via gv_create_provider; scan login pages for SSO options with gv_detect_login_options

  • πŸ—οΈ 3 login levels β€” Level 1 (manual), Level 2 (form auto-fill via login_steps), Level 3 (record user's login actions β†’ replay automatically next time)

  • ⌨️ Human-like interaction β€” realistic typing cadence (log-normal distribution), typo+correction, pre-click hover, burst scrolling; 3-layer humanize policy (off / recommended / always)

  • 🌐 Anonymous scraping β€” gv_open_ephemeral opens a throwaway session (no account, no login) for public pages

  • πŸ”Œ API tools β€” gv_api_call (HTTP in browser session), gv_eval_js (run JS in page), gv_get_cookies

  • 🩺 Session health check β€” gv_check_session tells you if login is still valid (cookie + probe URL)

  • πŸ” Persistent sessions β€” sign in once per account, then reuse forever (cookies + localStorage survive restarts)

  • πŸ”„ Multi-account + multi-provider β€” manage unlimited accounts across unlimited websites from one agent

  • πŸ‘οΈ Vision support β€” tools return PNG screenshots so the LLM can see the page

  • πŸ“‹ Self-debugging β€” structured JSONL logs of every action

  • 🏠 Local-first β€” sessions, cookies, and fingerprints live on your machine; nothing is ever sent anywhere

  • πŸ”’ Optional encryption at rest β€” AES-256-GCM + OS keychain

  • ⏱️ Auto-close & auto-lock β€” close + re-encrypt after each task or after N idle minutes

  • πŸ”‘ Private/public profiles β€” password gate + 5-attempt wipe

  • πŸ€– LLM-agnostic β€” Claude, GPT, Gemini, or any MCP-compatible model

How it works

Your AI agent (Claude Desktop / Cursor / Cline)
        β”‚  MCP protocol (stdio or HTTP)
        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Ghostvault MCP Server                           β”‚
β”‚                                                 β”‚
β”‚  42 tools:                                      β”‚
β”‚   gv_create_account, gv_sign_in,        β”‚
β”‚   gv_create_provider, gv_check_session, β”‚
β”‚   gv_detect_login_options, gv_record_login,β”‚
β”‚   gv_open_url, gv_click_element,        β”‚
β”‚   gv_fill_input, gv_api_call,           β”‚
β”‚   gv_open_ephemeral, gv_get_cookies,    β”‚
β”‚   gv_setup_password, gv_unlock, ...     β”‚
β”‚                                                 β”‚
β”‚  Per-account persistent Camoufox profiles:      β”‚
β”‚   profile_A/  ── locked fingerprint A + Google   β”‚
β”‚   profile_B/  ── locked fingerprint B + GitHub   β”‚
β”‚   profile_C/  ── locked fingerprint C + custom   β”‚
β”‚                                                 β”‚
β”‚  Provider recipes:                              β”‚
β”‚   providers.json (shared login recipes)         β”‚
β”‚   google | github | facebook | custom           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚  traffic exits via your IP or proxy
        β–Ό
   Any website (Google, GitHub, your bank, ...)

The agent decides what to do; Ghostvault provides the hands. Each profile is a container β€” it holds sessions for every website equally, not just one provider. Login is data-driven via provider recipes, so any website's login flow can be described as data, not code.

Why fingerprints are locked (critical)

Camoufox generates a fresh random fingerprint on every launch β€” it does not persist one to the profile directory. Without locking, each launch would look like a brand-new device and anti-bot systems would flag the account.

Ghostvault generates one fingerprint per account at creation, serializes it (BrowserForge fingerprint + noise seeds + OS + device profile) to a sidecar JSON, and passes it back on every launch. Result: an account always presents the same identity.


Quick start

Step 1 β€” Install (requires Python 3.11+):

pip install --pre ghostvault
python -m camoufox fetch    # download the browser binary (~120 MB, one-time)

Step 2 β€” Connect your AI agent:

Add Ghostvault to your MCP client config. Find your Python path:

which python3    # use this exact path below

Then add to your client config (see Connect your agent for each client's file location):

{
  "mcpServers": {
    "ghostvault": {
      "command": "/absolute/path/to/python3",
      "args": ["-m", "ghostvault"]
    }
  }
}

Step 3 β€” Try it:

Restart your agent and say: "List available Ghostvault providers."

The agent should respond with the built-in providers (google, github, facebook, generic).

That's it. No server to start, no port to manage β€” Ghostvault runs as a subprocess spawned by your AI client.


Prefer a one-command installer? (installs everything + auto-configures Claude Desktop / Cursor)

macOS / Linux (in a terminal):

curl -fsSL https://raw.githubusercontent.com/mienetic/Ghostvault/main/install.sh | bash

Windows (in PowerShell):

irm https://raw.githubusercontent.com/mienetic/Ghostvault/main/install.ps1 | iex

The installer automatically:

  1. πŸ“₯ Clones Ghostvault into ~/.ghostvault-app (or %USERPROFILE%\.ghostvault-app on Windows)

  2. 🐍 Creates an isolated Python virtualenv (doesn't touch your system Python)

  3. πŸ“¦ Installs Ghostvault + all dependencies

  4. 🦊 Downloads the Camoufox browser binary (~120 MB, one-time)

  5. βš™οΈ Writes the MCP config for Claude Desktop and/or Cursor if they're installed

Then restart Claude Desktop / Cursor β€” Ghostvault's tools appear. That's it. πŸŽ‰

Requirements: Python 3.11+ (download) and git. On macOS, run xcode-select --install first if git isn't installed. On Windows, check "Add Python to PATH" during the Python installer.

Update

# macOS / Linux
~/.ghostvault-app/update.sh

# Windows (PowerShell)
powershell -File "$env:USERPROFILE\.ghostvault-app\update.ps1"

Ghostvault also checks automatically on startup and prints a notice if a new version is available β€” so you'll never be silently out of date.

Uninstall

# macOS / Linux
bash ~/.ghostvault-app/uninstall.sh

On Windows, just delete the install dir and the data dir manually:

Remove-Item -Recurse -Force "$env:USERPROFILE\.ghostvault-app"
Remove-Item -Recurse -Force "$env:USERPROFILE\.ghostvault"   # sessions (optional)

Then remove the ghostvault entry from your Claude Desktop / Cursor config by hand.

Removes the install dir + the Ghostvault entry from your client configs. (On macOS/Linux the script asks before deleting session data, since ~/.ghostvault contains your Google sessions.)


Connect your agent

πŸ’‘ If you ran the one-line installer above, it already wrote the config for Claude Desktop and Cursor. Just restart those apps and you're done β€” skip to Usage. The steps below are only needed if you installed manually, or want to connect a different agent.

Ghostvault is an MCP server, so any MCP-compatible client can connect. Ready-to-copy config files for each client live in examples/ β€” see examples/README.md for the full cheat-sheet of where each file goes and the JSON shape each client expects.

⚠️ Use an absolute path to your Python. Clients run the server as a subprocess and don't inherit your shell PATH, so a bare python won't be found. After installing, find the right interpreter:

  • One-line installer: ~/.ghostvault-app/.venv/bin/python

  • Manual install: run which python in the venv where you installed Ghostvault, or use /usr/bin/python3, /opt/homebrew/bin/python3, etc.

Supported clients

Client

Example file

Config location

Claude Desktop

claude_desktop_config.json

~/Library/Application Support/Claude/ (macOS), %APPDATA%\Claude\ (Windows), ~/.config/Claude/ (Linux)

Cursor

cursor_config.json

~/.cursor/mcp.json (global) or .cursor/mcp.json (per-project)

Cline (VS Code)

cline_mcp_settings.json

~/.cline/data/settings/cline_mcp_settings.json (note extra disabled/autoApprove fields)

VS Code (Agent mode)

vscode_mcp.json

.vscode/mcp.json (note shape is {"servers": {...}} with type: "stdio")

ZCode

zcode_config.json

<repo>/.zcode/config.json (workspace) or ~/.zcode/cli/config.json (note nested mcp.servers)

Continue.dev

continue_dev_config.json

~/.continue/config.json under mcpServers

Claude Code (CLI)

(CLI β€” see below)

claude mcp add ...

Claude Code (CLI)

Claude Code is configured via the claude CLI rather than a JSON file:

claude mcp add --transport stdio -s user \
  -e GHOSTVAULT_HEADLESS=false \
  ghostvault -- /absolute/path/to/python -m ghostvault

Verify: claude mcp list. Scopes: -s user (all projects), -s project (shared via .mcp.json), -s local (default).

Other clients

Any MCP-compatible client works. The universal recipe:

  1. Point command at an absolute Python path that has Ghostvault installed

  2. Set args to ["-m", "ghostvault"]

  3. Optionally set env for any GHOSTVAULT_* variables (see Configuration)

The clients disagree on JSON shape β€” see the shape cheat-sheet in examples/README.md.

Remote / HTTP transport (advanced)

To serve Ghostvault over HTTP instead of stdio (e.g. for a remote client):

GHOSTVAULT_TRANSPORT=http GHOSTVAULT_PORT=8765 python -m ghostvault

Then point your client at http://127.0.0.1:8765/mcp (use the machine's IP for remote access β€” ensure you secure it).


Verify the connection

After connecting any agent, test it with a simple prompt:

"List my Ghostvault accounts."

The agent should call gv_list_accounts and return an empty list on a fresh install. If you get an error instead, check:

  • The Python path in the config is absolute and correct (ls /that/path)

  • Ghostvault is importable from that Python: /that/path/python -c "import ghostvault"

  • The Camoufox browser binary is downloaded: /that/path/python -m camoufox path

  • For stdio clients: check the client's MCP/logs panel β€” startup errors appear there

Just talk to your agent naturally. Example prompts:

  • "Sign in to my Work Google account, then read my latest 5 emails and tell me if any need an urgent reply."

  • "Switch to my Personal account and open Drive β€” list my recent files."

  • "Open Notion using my Work Google login and create a new page called 'Weekly review'."

  • "Take a screenshot of the current page so I can see what's happening."

The agent calls the right tools. On the first sign-in of a new account, a browser window opens for you to complete login (Google will likely ask for 2FA β€” this is normal).

Typical first-time flow

1. You:   "Create a Google account called Work"
   Agent: calls gv_create_account β†’ "Done. Now sign in."

2. You:   "Sign in to Work"
   Agent: calls gv_sign_in β†’ a browser window opens
   You:   complete Google login + 2FA in that window
   Agent: "Signed in as you@gmail.com."

3. You:   "Read my latest emails"
   Agent: calls gv_read_gmail β†’ returns inbox summary

4. You:   "Now switch to Personal and open Drive"
   Agent: calls gv_switch_account + gv_open_url

Tool reference

Anonymous scraping (2 tools) β€” no account needed

Tool

Description

gv_open_ephemeral

Open a throwaway Camoufox session (no profile, no login) β€” url, headless, proxy, block_images

gv_close_ephemeral

Close an ephemeral session + free resources (defaults to active)

Provider management (5 tools) β€” custom login recipes

Tool

Description

gv_create_provider

Create a custom login recipe for any website (Level 1)

gv_list_providers

List all providers (built-in + custom) with capability flags

gv_get_provider

Show one provider's full config

gv_update_provider

Update a custom provider (refuses built-ins)

gv_delete_provider

Delete a custom provider (refuses built-ins)

Login scanning + credentials (3 tools)

Tool

Description

gv_detect_login_options

Scan a page for SSO buttons, form fields, 2FA, captcha β€” returns recommendation

gv_set_credentials

Store credentials (username/password) for Level 2 auto-fill

gv_get_credentials

Show stored credential keys (values masked)

Session health + API (4 tools)

Tool

Description

gv_check_session

Check if session is still authenticated (cookie + probe URL)

gv_api_call

HTTP request using browser session (cookies + TLS fingerprint)

gv_eval_js

Run JavaScript in the page (extract tokens, call site JS)

gv_get_cookies

Read browser cookies (masked values)

Once open, all browser tools work on the ephemeral session unchanged β€” gv_open_url, gv_get_page_content, gv_screenshot, gv_get_page_links, gv_click_element, gv_fill_input, gv_scroll, gv_press_key. The session is set as the active target automatically.

Accounts & lifecycle (18 tools)

Tool

Description

gv_list_accounts

List accounts + which is active + statuses (private hidden when locked)

gv_create_account

Create a slot with a locked fingerprint + advanced config (preset, locale, humanize, ...)

gv_update_account_config

Tweak advanced fingerprint config post-creation (identity stays locked; reopen to apply)

gv_sign_in

Open a login window for the user (handles 2FA)

gv_open_account

Open the browser reusing a saved session (no login window)

gv_switch_account

Change the active account

gv_get_session_status

Check if a session is running/authenticated

gv_close_account

Close a browser context (session saved)

gv_lock_account

Close + re-encrypt (session kept)

gv_sign_out

Sign out of Google (session invalidated; re-login required)

gv_delete_account

Delete account + profile + session + DB row permanently

gv_setup_password

Set a password to enable the private/public gate (browser window)

gv_unlock

Unlock the gate to access private profiles (password or browser window)

gv_logout

Lock the gate + close private contexts + switch to public

gv_get_auth_status

Check whether the gate is active and unlocked

gv_make_private

Mark a profile as private (hidden when locked)

gv_make_public

Mark a profile as public (always accessible)

Browser (9 tools)

Tool

Description

gv_open_url

Open any URL in the active account (incl. SSO-enabled sites)

gv_get_page_content

Read page text (+ optional screenshot via include_screenshot)

gv_screenshot

Capture a PNG (vision) β€” full_page option

gv_get_page_links

List visible links

gv_click_element

Click by visible text or CSS selector β€” humanize, delay_after_ms

gv_fill_input

Fill a form field β€” humanize, typing_speed_wpm, typing_variance, mistake_rate, delay_after_ms

gv_press_key

Press a key or chord (Enter, Tab, Escape, Ctrl+A, ...) β€” hold_ms, delay_after_ms

gv_scroll

Scroll in human-like bursts β€” direction, amount, humanize (good for reCAPTCHA v3)

gv_read_gmail

Read the Gmail inbox (convenience tool)

Debug (1 tool)

Tool

Description

gv_get_logs

Read recent JSONL action log entries

Full tool docstrings (what the agent sees) are in the skill/ directory (modular: 9 files covering all 42 tools).


Configuration

All settings are env vars (prefix GHOSTVAULT_), loadable from a .env file. See .env.example for the full list. Highlights:

Var

Default

Purpose

GHOSTVAULT_DATA_DIR

~/.ghostvault

Profiles, DB, logs

GHOSTVAULT_HEADLESS

false

Open a visible window (recommended for login + 2FA)

GHOSTVAULT_DEFAULT_OS

auto

Default fingerprint OS (auto = host OS, or windows/macos/linux)

GHOSTVAULT_LOGIN_TIMEOUT

300

Seconds to complete login + 2FA

GHOSTVAULT_TRANSPORT

stdio

stdio | http | sse

GHOSTVAULT_PROXY_*

(empty)

Optional global proxy (local-first otherwise)

GHOSTVAULT_LOG_LEVEL

INFO

Console log level

GHOSTVAULT_ENCRYPTION_ENABLED

false

Encrypt profile dirs at rest (see Encryption)

GHOSTVAULT_AUTO_CLOSE_AFTER_TASK

false

Close browser + re-encrypt after each tool call (minimizes exposure window)

GHOSTVAULT_AUTO_LOCK_MINUTES

0

Auto-close idle contexts after N minutes (0 = disabled)

GHOSTVAULT_WINDOW_WIDTH

1280

Browser window width in pixels (0 = let browser decide)

GHOSTVAULT_WINDOW_HEIGHT

800

Browser window height in pixels (0 = let browser decide)

GHOSTVAULT_HUMANIZE

true

Human-like cursor movement (click jitter + bezier path). Strongly recommended for login/SSO work.

GHOSTVAULT_BLOCK_WEBRTC_STRATEGY

auto

WebRTC gate: auto (block only with proxy) | true | false

GHOSTVAULT_DEFAULT_LOCALE

(empty)

Default locale for new accounts, e.g. en-US (empty = geoip/host-decided)

GHOSTVAULT_DEFAULT_TIMEZONE

(empty)

Default IANA timezone for new accounts, e.g. America/New_York (empty = geoip/host-decided)

GHOSTVAULT_HUMANIZE_POLICY

off

Humanize policy: off (agent decides) | recommended (default on, agent can disable) | always (forced on)

GHOSTVAULT_EPHEMERAL_HEADLESS

true

Ephemeral (scraping) sessions are headless by default

GHOSTVAULT_EPHEMERAL_BLOCK_IMAGES

true

Block image loading in ephemeral sessions (faster text scraping)

GHOSTVAULT_EPHEMERAL_AUTO_CLOSE_MINUTES

5

Idle timeout for ephemeral sessions (0 = disabled)

GHOSTVAULT_EPHEMERAL_MAX_CONCURRENT

3

Cap on simultaneous ephemeral sessions

Advanced fingerprint configuration

Camoufox exposes ~15 fingerprint-injection kwargs + 105 config-domain keys (battery, media devices, audio, WebGL params, screen, navigator, ...). Without Ghostvault you'd have to pass them every launch AND remember which go as constructor kwargs vs config dict keys. Ghostvault locks them into each account's fingerprint bundle, so they persist across launches alongside the identity.

The full ~105-key schema is documented at Camoufox config schema in the docs site. Use it to set raw keys like battery:level, mediaDevices:webcams, AudioContext:sampleRate via the device_config param.

Device profile templates fill in ~15 hardware-realistic keys at once β€” screen size, GPU vendor/renderer, media-device counts, battery, audio rate:

await gv.create_account(
    name="Work-MBP",
    device_profile="macbook-pro-14-m2",  # fills screen, GPU, mics, webcam, ...
    device_config={"battery:level": 0.45},  # override one key
)

Available profiles: macbook-pro-14-m2, macbook-air-13-m1, imac-24, windows-desktop-rtx, thinkpad-x1-carbon, surface-laptop-5, linux-workstation, dell-xps-13-ubuntu, generic-laptop, headless-server. See Device profile templates for the full comparison table.

A built-in consistency checker flags impossible combos (e.g. macOS with an NVIDIA GPU) β€” warnings surface in the gv_create_account response.

Presets bundle smart defaults so you don't have to learn all 15 params:

Preset

Use case

What it sets

balanced (default)

Most Google / SSO work

humanize=true, block_webrtc="auto"

stealth

Signups, new IPs, sensitive accounts

humanize=true, block_webrtc=true, disable_coop=true

minimal

Trusted sites, max speed

humanize=false, block_webrtc=false

Any explicit param you pass overrides the preset value.

Available params (all optional, all locked per-account):

Param

Type

Notes

locale

str | list[str]

e.g. "en-US" or ["en-US","en"]. First drives Intl API; rest populate Accept-Language. Overrides geoip when set.

timezone

str

IANA timezone, e.g. "America/New_York". Overrides geoip when set.

humanize

bool | float

true enables cursor humanization; a float sets max move duration in seconds.

block_webrtc

bool | "auto"

"auto" = block only when a proxy is set (prevents IP leak via STUN).

block_webgl

bool

Disable WebGL entirely. Some sites break; use sparingly.

webgl_config

list[str]

[vendor, renderer] pair to spoof, e.g. ["Apple Inc.", "Apple GPU"].

fonts

list[str]

Installed font family names to inject (on top of OS defaults).

addons

list[str]

Paths to extracted Firefox addon dirs (must contain manifest.json).

disable_coop

bool

Disable Cross-Origin-Opener-Policy β€” needed for some captcha/turnstile iframes.

block_images

bool

Block all image loading. Faster but visually inconsistent.

Smart-default rules (applied at launch time):

block_webrtc:
  explicit true/false β†’ use it
  "auto"              β†’ true if proxy present, false otherwise

locale / timezone:
  explicit value      β†’ use it, DISABLE geoip matching for that dimension
  absent + proxy      β†’ geoip=true (auto-match from proxy IP)
  absent + no proxy   β†’ host locale (current behavior)

humanize:
  explicit value      β†’ use it
  absent              β†’ global GHOSTVAULT_HUMANIZE default (true)

Example β€” stealth account in Thailand with a US proxy:

await gv.create_account(
    name="Work-US",
    os="windows",
    proxy={"server": "http://us-residential.example:8080"},
    preset="stealth",
    locale="en-US",              # match the proxy country
    timezone="America/New_York", # match the proxy country
)

Update config after creation (identity stays locked β€” only injection params change):

# Account must be closed first.
await gv.update_account_config(account_id, humanize=False, block_webrtc=True)
await gv.open_account(account_id)  # relaunch to apply

Reset a key back to default:

await gv.call("gv_update_account_config", {
    "account_id": account_id,
    "reset_keys": ["locale", "timezone"],
})

Note on IP: Camoufox (and any browser) cannot change the TCP source IP β€” that's set by the OS kernel, not the browser. Use a proxy or VPN for IP rotation. What the advanced config does lock is everything else: the browser-visible signals (locale, timezone, fonts, WebGL, WebRTC leak gate) that must match the IP's country or the account looks inconsistent. See this discussion for the full IP/fingerprint model.

Encryption at rest (optional)

By default, each account's persistent profile (which holds real Google session cookies) lives on disk as plaintext Firefox profile files. Anyone with read access to ~/.ghostvault/profiles/ can steal your sessions.

Enable encryption to store profiles as AES-256-GCM archives instead:

export GHOSTVAULT_ENCRYPTION_ENABLED=true

Or set it in your client's env block:

"env": { "GHOSTVAULT_ENCRYPTION_ENABLED": "true" }

How it works:

  • The master key is stored in your OS keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service) β€” never on disk. It's auto-generated on first use.

  • When the browser opens, the profile is decrypted to a temp dir (wiped on close).

  • When the browser closes, the profile is re-encrypted to <account_id>.profile.enc.

  • Existing plaintext profiles are auto-migrated on first open after enabling.

Requirements & caveats:

  • Keychain backend required. On headless Linux without D-Bus / Secret Service (e.g. a bare Docker container), encryption can't store the key securely and stays disabled. Run gnome-keyring or kwallet first.

  • Losing the keychain entry = losing the profiles. The key is not derivable from anything else. There is no recovery path by design β€” that's what makes it secure.

  • The browser still sees plaintext while running. Encryption protects data at rest, not against an attacker who compromises the running session.

  • Fingerprint files stay plaintext. They describe the spoofed identity (UA, screen, etc.) but don't contain session secrets, so encrypting them isn't worth the complexity.

Private/public profiles (optional)

Ghostvault can separate profiles into public (accessible without unlocking) and private (hidden behind a password). This is an app-level visibility gate on top of encryption-at-rest.

How it works:

  1. Call gv_setup_password β€” a browser window opens for you to set a password

  2. Mark sensitive profiles as private: gv_make_private({account_id})

  3. When locked, gv_list_accounts hides private profiles; browser tools refuse to open them

  4. Call gv_unlock({password}) to access private profiles (stays unlocked until gv_logout or server restart)

Brute-force protection:

  • 3 wrong passwords β†’ warning with remaining attempts

  • 5 wrong passwords β†’ all private profiles permanently deleted + password reset

  • Public profiles are never affected by failed attempts

This is different from encryption-at-rest: encryption protects the disk (someone steals the laptop); the private/public gate protects access (someone sits at your unlocked machine and tries to use private Google accounts via the agent).

Remote (HTTP transport)

For remote access instead of the default stdio transport:

GHOSTVAULT_TRANSPORT=http GHOSTVAULT_PORT=8765 python -m ghostvault

Point your client at http://127.0.0.1:8765/mcp.

Anonymous scraping (no account needed)

Not every task needs a managed account. gv_open_ephemeral launches a throwaway Camoufox session: no profile, no DB row, no login, random identity per session, tempdir removed on close. Once open, all browser tools work on it unchanged β€” it just becomes the active target.

# Open a throwaway browser + navigate to a public page
await gv.open_ephemeral(url="https://news.ycombinator.com")

# All browser tools work β€” no changes needed
content = await gv.get_page_content(include_screenshot=True)
links = await gv.get_page_links(limit=20)
await gv.scroll(direction="down", amount=3)

# Done β€” close frees the browser + removes the tempdir
await gv.close_ephemeral()

Mix anonymous scraping with managed accounts:

# Scrape a public page anonymously...
await gv.open_ephemeral(url="https://example.com/public-data")
data = await gv.get_page_content()
await gv.close_ephemeral()

# ...then switch to a managed account for authenticated work
await gv.open_account("acc_abc123")
await gv.open_url("https://mail.google.com")

Ephemeral defaults are tuned for scraping (override per call):

Setting

Default

Why

headless

true

Scraping doesn't need a visible window (opposite of managed accounts)

block_images

true

Faster text scraping; turn off if you need screenshots

humanize

false

No cursor movement needed for read-only scraping

auto_close_minutes

5

Short idle timeout β€” abandoned sessions clean themselves up

max_concurrent

3

Cap on simultaneous ephemeral sessions (each is a full Firefox process)

Override via env vars (GHOSTVAULT_EPHEMERAL_*) or per call:

# Visible browser + keep images for screenshot-based scraping
await gv.open_ephemeral(url="...", headless=False, block_images=False)

When to use ephemeral vs managed accounts:

Scenario

Use

Scrape a public page (news, docs, pricing)

gv_open_ephemeral

Login-required site (Gmail, Drive, SSO)

Managed account (gv_create_account + gv_sign_in)

Fill a public form (contact, signup-free download)

gv_open_ephemeral

Read Gmail / access Google services

Managed account

Captcha-protected scrape target

gv_open_ephemeral + humanize=True via the proxy param

See examples/scripts/scrape_public_page.py and scrape_with_pagination.py for complete runnable examples.

Human-like interaction (anti-bot typing + clicks)

Camoufox's humanize=True covers mouse-movement bezier curves at the C++ layer (so isTrusted=true and the cursor path looks human). It does NOT cover:

  • Typing cadence β€” Playwright's fill() pastes the whole string in one input event; keyboard.type(text, delay=N) uses a constant delay between every char, which is itself a bot tell.

  • Inter-keystroke variance β€” real humans speed up on common bigrams ("th", "ing") and slow down on rare ones.

  • Occasional typos + corrections β€” a perfect string with zero Backspaces is suspicious for long inputs.

  • Pre-click hover β€” Playwright's .click() moves + clicks in one gesture; real users hover for 50–500 ms before clicking.

Ghostvault fills these gaps at the Playwright layer. Every interaction tool gains optional humanization params:

Param

Type

Default

Purpose

humanize

bool

false

Type char-by-char (fill) or hover-then-click (click).

typing_speed_wpm

int

90

Target words-per-minute (40=slow, 90=avg, 150=fast).

typing_variance

float

0.35

Cadence spread 0–1 (log-normal sigma). 0=constant, 0.35=realistic, 1=erratic.

mistake_rate

float

0.0

Chance per char to typo-then-correct (0–0.05). Produces realistic Backspace events.

delay_after_ms

int

0

Randomized pause after the action (0.7×–1.3Γ— spread).

Per-call example β€” Google login with humanized typing:

await gv.fill_input(
    target="Email", value="user@gmail.com",
    humanize=True, typing_speed_wpm=85, typing_variance=0.4,
    mistake_rate=0.02, delay_after_ms=800,
)
await gv.click_element(target="Next", humanize=True, delay_after_ms=1500)

Per-account defaults (set once, applies to all calls unless overridden):

await gv.update_account_config(account_id, humanize_typing=True, default_typing_wpm=85)
# Now every gv_fill_input on this account is humanized unless you pass humanize=False

The typing model is a log-normal distribution (the standard HCI model). For wpm=90, variance=0.35, inter-keystroke delays center around ~130 ms with occasional 300–500 ms outliers β€” matching observed human typing. With mistake_rate > 0, a fraction of characters are mistyped to a QWERTY-adjacent key, paused on briefly, then Backspace-corrected.

New tools for richer interaction:

Tool

Use case

gv_press_key

Submit with Enter, Tab between fields, Escape to dismiss, Ctrl+A to select all

gv_scroll

Human-like scroll bursts with reading pauses β€” critical for reCAPTCHA v3, which weights scroll behavior heavily

reCAPTCHA v3 warm-up pattern β€” a page that loads + immediately submits looks like a bot. Scroll, read, click around, THEN act:

await gv.open_url("https://protected-site.com")
await asyncio.sleep(3)                          # let the page settle
await gv.scroll(direction="down", amount=2)     # burst-scroll
await asyncio.sleep(2)                          # reading pause
await gv.get_page_content()                     # "engage" with content
await gv.scroll(direction="up", amount=2)       # round-trip scroll
await gv.fill_input("query", "search term", humanize=True)  # NOW act
await gv.press_key("Enter")

See examples/scripts/human_like_login.py, fill_long_form.py, and captcha_friendly_browsing.py for complete runnable examples.

Humanize policy β€” who decides?

By default, the AI agent decides per-call whether to enable humanize (based on the Decision Guide in each tool's docstring). For sensitive accounts you may want to lock this down. Ghostvault supports a 3-layer policy model:

Policy

Behavior

Use case

off (default)

Agent decides every call; per-account humanize_typing/humanize_clicks is the fallback when the agent omits the arg.

Trusted environments, fast iteration.

recommended

Humanize defaults ON; agent CAN turn it OFF explicitly by passing humanize=false.

Most real-world use β€” safety net without rigidity.

always

Humanize forced ON at the server. The agent cannot disable it, even by passing humanize=false.

Sensitive accounts (ads, payments) where a single mistake = ban.

Resolution order (highest wins):

1. Per-account humanize_policy  (set via gv_update_account_config)
2. Global GHOSTVAULT_HUMANIZE_POLICY  (env var)
3. "off"  (default β€” agent decides)

Set it globally (applies to all accounts):

# In .env or your client's env block:
GHOSTVAULT_HUMANIZE_POLICY=recommended

Set it per-account (overrides global):

# Force humanize on for this sensitive account β€” agent can't disable it.
await gv.update_account_config(account_id, humanize_policy="always")

The tool result includes the effective humanize value so the agent (and you) can verify what actually ran:

{"filled": "Email", "humanize": true, "typing_speed_wpm": 85}

Manual install (alternative)

Ghostvault is on PyPI (beta) β€” install with pip install --pre ghostvault. Requires Python 3.11+.

git clone https://github.com/mienetic/Ghostvault.git
cd Ghostvault
pip install -e .

# Download the Camoufox browser binary (~120 MB, one-time)
python -m camoufox fetch

For development (includes test + lint tooling):

pip install -e ".[dev]"

Then add Ghostvault to your client config manually. Use the Python from your environment as the command β€” for example, the venv python if you installed into one.

Claude Desktop β€” edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or ~/.config/Claude/claude_desktop_config.json (Linux):

{
  "mcpServers": {
    "ghostvault": {
      "command": "/absolute/path/to/your/python",
      "args": ["-m", "ghostvault"],
      "env": {
        "GHOSTVAULT_HEADLESS": "false"
      }
    }
  }
}

Cursor β€” edit .cursor/mcp.json:

{
  "mcpServers": {
    "ghostvault": {
      "command": "/absolute/path/to/your/python",
      "args": ["-m", "ghostvault"]
    }
  }
}

Restart your client after editing.


Programmatic use (SDK)

For scripts that want to call Ghostvault without an LLM in the loop (run inside the cloned repo, after pip install -e . above):

pip install -e ".[sdk]"
import asyncio
from ghostvault_sdk import GhostvaultClient

async def main():
    async with GhostvaultClient() as gv:
        await gv.create_account(name="Work", os="macos")
        accounts = await gv.list_accounts()
        print(accounts)

asyncio.run(main())

See the examples/ directory for comprehensive examples:

Example

What it demonstrates

scripts/sdk_all_tools.py

Every gv_* tool called via SDK (42 tools)

scripts/custom_provider_demo.py

Create a custom provider recipe for any website + list/delete providers

scripts/detect_login_demo.py

Scan a login page for SSO buttons, form fields, 2FA, captcha + get recommendation

scripts/record_login_demo.py

Level 3: record a login flow β†’ replay automatically next time

scripts/session_health_demo.py

Check session health + API call + JS eval + cookie reading

scripts/human_like_login.py

Human-like login (any provider) with realistic typing cadence (85 wpm, 2% typos)

scripts/fill_long_form.py

Multi-field form with per-field typing speeds + Tab navigation + Shift+Tab to go back

scripts/captcha_friendly_browsing.py

reCAPTCHA v3 warm-up pattern: scroll, read, click, THEN act

scripts/scrape_public_page.py

Anonymous one-shot scrape: open_ephemeral β†’ read + screenshot + links β†’ close (no account)

scripts/scrape_with_pagination.py

Multi-page scrape on a persistent ephemeral session: loop {read, scroll, click Next}

scripts/sdk_private_public.py

Private/public gate flow via SDK (setup, lock, unlock, logout)

scripts/check_gmail.py

End-to-end: create + sign in + read Gmail + close

scripts/mcp_e2e_test.py

MCP protocol test: create + sign in + read Gmail

scripts/mcp_security_test.py

Encryption + auto-close + auto-lock + sign_out + delete

agent_prompts.md

Copy-paste prompts for Claude Desktop / Cursor / ZCode (all 42 tools)


FAQ

No. Each profile is a container that holds sessions for any website equally. Use gv_create_account(provider="github") + gv_sign_in to login GitHub directly. Or use gv_create_account(provider="my_custom_site") with a custom provider you created via gv_create_provider. Google is just one of the built-in providers β€” it's not a "parent" that other providers depend on.

The agent can detect what login options a page offers by calling gv_detect_login_options(url) β€” it scans for SSO buttons, form fields, 2FA, and captcha, then recommends a login path.

Ghostvault uses Camoufox, a Firefox fork with C-level fingerprint spoofing. With locked fingerprints + humanized interaction + your home IP, each account looks like a genuine device. That said:

  • First-time login often triggers 2FA β€” the site sees a new device. This is expected.

  • Don't share IPs across many accounts β€” one account per proxy/IP is the safe ratio.

  • Use humanize=true on login forms β€” instant paste typing is the #1 bot tell.

  • No tool is undetectable β€” behavioral ML (reCAPTCHA v3) and IP reputation still apply.

Ghostvault gives you the tools to be safe; how you use them is your responsibility. See LICENSE for the full liability disclaimer.

Yes, but with caveats:

  • You'll need a residential/mobile proxy per account (datacenter IPs get flagged).

  • Login requires a visible window β€” on a headless server, use headless='virtual' (Xvfb) or VNC.

  • Configure the proxy before the first login (the session is tied to the IP + fingerprint).

For most users, running locally is simpler and safer. Remote HTTP transport (GHOSTVAULT_TRANSPORT=http) is available if needed.

Yes β€” any website. Built-in providers: Google, GitHub, Facebook, generic. Custom providers: create via gv_create_provider for any site (your bank, internal apps, SaaS tools). Each profile holds sessions for all websites equally.

Once logged in, call gv_open_url with any URL β€” the agent can navigate, click, fill forms, call APIs, and read pages.

Those are agent frameworks (they provide the LLM↔browser reasoning loop). Ghostvault is a tool provider β€” it exposes browser tools via MCP that any agent framework (or plain Claude Desktop) can call. You can even combine them: use Ghostvault for the stealth Google sessions and let your favorite agent framework drive the pages.

Ghostvault uses Camoufox (Firefox/Juggler), while browser-use 0.13+ requires CDP (Chromium-only) β€” so they don't directly interoperate, but they solve different problems.

Everything stays local under ~/.ghostvault/:

  • profiles/ β€” per-account Camoufox profiles (cookies, localStorage, fingerprint lock)

  • logs/ghostvault.jsonl β€” structured debug log

  • browserver.sqlite β€” account metadata only (no sessions)

Nothing is ever sent to a remote server except the browser traffic itself (which exits via your home IP, or your configured proxy). Ghostvault has no telemetry, no analytics, no phone-home.

You need to sign in first. Tell the agent: "Sign in to [account name]". A browser window opens; complete Google login there. After that, the account is active and the browser tools work. See Typical first-time flow.


Troubleshooting

Symptom

Fix

Login window doesn't appear

Set GHOSTVAULT_HEADLESS=false in .env or your client config env block

gv_read_gmail returns empty

Gmail's DOM changes often β€” fall back to gv_open_url to mail.google.com + gv_get_page_content with include_screenshot=true

"Session not authenticated"

The session expired β€” re-run gv_sign_in for that account

Agent action had no effect

Call gv_get_logs and/or gv_screenshot to see what the browser shows

Install fails on camoufox fetch

Network issue β€” retry with python -m camoufox fetch, or skip and run it later

Two windows for same account

Not possible β€” Ghostvault enforces one context per account. Switch accounts instead.


Important notes

  • First-time login = new device. Google sees a new fingerprint/IP, so expect a 2FA challenge. This is one-time per account.

  • Local-first by default. Traffic exits via your home IP. If you move Ghostvault to a server, add a residential proxy and re-login.

  • One context per account. Ghostvault refuses to open two windows for the same profile (would corrupt it). Switch accounts instead.

  • Gmail scraping is best-effort. Gmail's DOM changes often; if gv_read_gmail returns empty, fall back to gv_open_url + gv_get_page_content with a screenshot.

  • Sessions are sensitive. Anyone with read access to ~/.ghostvault/ has full access to your Google accounts. Protect that directory β€” or enable encryption at rest.

  • Camoufox β‰  Firefox. Ghostvault downloads its own patched Camoufox browser (~120 MB) during install. You don't need to install Firefox separately; the two don't conflict.


Known issues

⚠️ macOS Retina/HiDPI rendering (in progress): On Retina displays, the Camoufox browser window renders UI elements too large and content overflows (requires horizontal scrolling). This is a Camoufox upstream issue β€” it affects the browser directly, not just Ghostvault. We are investigating workarounds. Non-Retina displays are unaffected.

Roadmap

Legend: 🟒 done Β· πŸ”΅ in progress Β· βšͺ planned Β· 🏁 good first issue Β· πŸ’› help wanted Β· πŸ’° needs funding


v0.1-beta (current β€” PyPI 0.1.x)

⚠️ Beta software. All features below are done and shipped. API may change before v1.0. Known issues: Retina rendering + MCP timeout.

  • 🟒 Core: per-account persistent Camoufox profiles + locked fingerprints

  • 🟒 42 MCP tools (accounts, lifecycle, browser, providers, API, scraping, debug, security)

  • 🟒 Published to PyPI β€” pip install --pre ghostvault

  • 🟒 Provider-agnostic login β€” built-in + custom providers, login scan, 3 login levels

  • 🟒 Session health check, API tools, anonymous scraping

  • 🟒 Advanced fingerprint config β€” 105 Camoufox config keys + 10 device profiles

  • 🟒 Human-like interaction β€” log-normal typing, typo+correction, hover, scroll

  • 🟒 Encryption at rest + private/public gate + profile recovery

  • 🟒 SDK client + GitHub Pages docs + one-click installer

  • 🟒 CI: lint + test + build + docs deploy + PyPI publish

v0.2 β€” Stabilize (next β€” when known issues are fixed)

  • πŸ”΅ Fix macOS Retina/HiDPI rendering

  • πŸ”΅ Fix MCP timeout for setup_password

  • βšͺ Community testing feedback β†’ bug fixes

  • βšͺ API freeze (no breaking changes after this)

  • βšͺ gv_export_session / gv_import_session β€” backup/restore

  • βšͺ gv_wait_for_element + gv_wait_for_navigation

  • 🏁 Replace ad-hoc CSS selectors with a tested strategy

v0.3 β€” Ecosystem (planned)

  • βšͺ More built-in providers (Microsoft, Apple, Twitter, LinkedIn)

  • βšͺ Per-site action packs (Gmail, Drive, Calendar, Notion, GitHub)

v1.0 β€” Production (planned)

  • βšͺ Docker image + docker-compose

  • βšͺ Audit log (who did what, when)

  • βšͺ Rate limiting + concurrent account limits

  • βšͺ Plugin system for per-site action packs

  • βšͺ Independent security review πŸ’°

v1.x+ β€” Scale (ideas)

  • βšͺ Vision-based action suggestion (LLM looks at screenshot β†’ proposes next action)

  • βšͺ Cloud-hosted option (managed Ghostvault as a service) πŸ’°

  • βšͺ Mobile device profiles (iPhone Safari, Android Chrome)

  • βšͺ Proxy rotation per account

Contributing to the roadmap

  • Pick anything marked 🏁 (good first issue) or πŸ’› (help wanted) β€” open a PR.

  • Have a use case we're missing? Open a discussion.


Contributing

Contributions welcome! See CONTRIBUTING.md for setup, conventions, and how to add a new tool.

pip install -e ".[dev]"
pytest -q
ruff check .

Adding a tool

  1. Add the input model to src/ghostvault/inputs.py

  2. Add the logic to src/ghostvault/tools.py (raise ToolError for expected failures)

  3. Register it in src/ghostvault/server.py with @mcp.tool(name=..., annotations=...) and a thorough docstring

  4. Add a test under tests/

The fingerprint lock is an invariant β€” any change that breaks it causes every account to look like a new device. tests/test_fingerprint.py guards it; keep it green.


Development

git clone https://github.com/mienetic/Ghostvault.git
cd Ghostvault
pip install -e ".[dev]"
python -m camoufox fetch   # one-time browser download
pytest -q                  # 17 unit tests
ruff check .               # lint

License

Apache 2.0 + Commons Clause β€” free to use, modify, and distribute for personal, research, educational, and internal use. Selling the software as a product or service (SaaS, paid hosting, paid consulting) requires a commercial license.

What's allowed: internal use, research, education, consulting, modifying, forking.

What's not allowed (without commercial license): selling the software itself, offering it as a paid SaaS, bundling it into a paid product.

Disclaimer: The authors are not responsible for any misuse of this software. You are solely responsible for complying with all applicable laws and terms of service. See LICENSE for the full liability disclaimer.


⚠️ Use responsibly. Ghostvault is a tool for managing your own accounts. Don't use it to access accounts you don't own, violate terms of service, or do anything illegal. You are responsible for how you use it.

Install Server
F
license - not found
A
quality
A
maintenance

Maintenance

–Maintainers
20hResponse time
–Release cycle
–Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mienetic/Ghostvault'

If you have feedback or need assistance with the MCP directory API, please join our Discord server