Ghostvault
Enables driving Canva.com through Google SSO after signing in with a Google account.
Provides tools to read Gmail messages from signed-in Google accounts.
Allows managing multiple Google accounts, signing in/out, switching accounts, reading Gmail, and driving any website that supports Sign in with Google through a persistent anti-detect browser.
Allows driving Notion.so through Google SSO after signing in with a Google account.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@GhostvaultSign in to my personal Google account and show unread emails from today."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
π» Ghostvault
Source-available MCP server for managing browser sessions on any website through your AI agent β powered by Camoufox.
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/minimalpresets + 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 withgv_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_ephemeralopens 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_sessiontells 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 belowThen 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 | bashWindows (in PowerShell):
irm https://raw.githubusercontent.com/mienetic/Ghostvault/main/install.ps1 | iexThe installer automatically:
π₯ Clones Ghostvault into
~/.ghostvault-app(or%USERPROFILE%\.ghostvault-appon Windows)π Creates an isolated Python virtualenv (doesn't touch your system Python)
π¦ Installs Ghostvault + all dependencies
π¦ Downloads the Camoufox browser binary (~120 MB, one-time)
βοΈ 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, runxcode-select --installfirst ifgitisn'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.shOn 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 barepythonwon't be found. After installing, find the right interpreter:
One-line installer:
~/.ghostvault-app/.venv/bin/pythonManual install: run
which pythonin 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 |
| |
Cursor |
| |
Cline (VS Code) |
| |
VS Code (Agent mode) |
| |
ZCode |
| |
Continue.dev |
| |
Claude Code (CLI) | (CLI β see below) |
|
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 ghostvaultVerify: 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:
Point
commandat an absolute Python path that has Ghostvault installedSet
argsto["-m", "ghostvault"]Optionally set
envfor anyGHOSTVAULT_*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 ghostvaultThen 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 pathFor 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_urlTool reference
Anonymous scraping (2 tools) β no account needed
Tool | Description |
| Open a throwaway Camoufox session (no profile, no login) β |
| Close an ephemeral session + free resources (defaults to active) |
Provider management (5 tools) β custom login recipes
Tool | Description |
| Create a custom login recipe for any website (Level 1) |
| List all providers (built-in + custom) with capability flags |
| Show one provider's full config |
| Update a custom provider (refuses built-ins) |
| Delete a custom provider (refuses built-ins) |
Login scanning + credentials (3 tools)
Tool | Description |
| Scan a page for SSO buttons, form fields, 2FA, captcha β returns recommendation |
| Store credentials (username/password) for Level 2 auto-fill |
| Show stored credential keys (values masked) |
Session health + API (4 tools)
Tool | Description |
| Check if session is still authenticated (cookie + probe URL) |
| HTTP request using browser session (cookies + TLS fingerprint) |
| Run JavaScript in the page (extract tokens, call site JS) |
| 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 |
| List accounts + which is active + statuses (private hidden when locked) |
| Create a slot with a locked fingerprint + advanced config ( |
| Tweak advanced fingerprint config post-creation (identity stays locked; reopen to apply) |
| Open a login window for the user (handles 2FA) |
| Open the browser reusing a saved session (no login window) |
| Change the active account |
| Check if a session is running/authenticated |
| Close a browser context (session saved) |
| Close + re-encrypt (session kept) |
| Sign out of Google (session invalidated; re-login required) |
| Delete account + profile + session + DB row permanently |
| Set a password to enable the private/public gate (browser window) |
| Unlock the gate to access private profiles (password or browser window) |
| Lock the gate + close private contexts + switch to public |
| Check whether the gate is active and unlocked |
| Mark a profile as private (hidden when locked) |
| Mark a profile as public (always accessible) |
Browser (9 tools)
Tool | Description |
| Open any URL in the active account (incl. SSO-enabled sites) |
| Read page text (+ optional screenshot via |
| Capture a PNG (vision) β |
| List visible links |
| Click by visible text or CSS selector β |
| Fill a form field β |
| Press a key or chord (Enter, Tab, Escape, Ctrl+A, ...) β |
| Scroll in human-like bursts β |
| Read the Gmail inbox (convenience tool) |
Debug (1 tool)
Tool | Description |
| 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 |
|
| Profiles, DB, logs |
|
| Open a visible window (recommended for login + 2FA) |
|
| Default fingerprint OS ( |
|
| Seconds to complete login + 2FA |
|
|
|
| (empty) | Optional global proxy (local-first otherwise) |
|
| Console log level |
|
| Encrypt profile dirs at rest (see Encryption) |
|
| Close browser + re-encrypt after each tool call (minimizes exposure window) |
|
| Auto-close idle contexts after N minutes (0 = disabled) |
|
| Browser window width in pixels (0 = let browser decide) |
|
| Browser window height in pixels (0 = let browser decide) |
|
| Human-like cursor movement (click jitter + bezier path). Strongly recommended for login/SSO work. |
|
| WebRTC gate: |
| (empty) | Default locale for new accounts, e.g. |
| (empty) | Default IANA timezone for new accounts, e.g. |
|
| Humanize policy: |
|
| Ephemeral (scraping) sessions are headless by default |
|
| Block image loading in ephemeral sessions (faster text scraping) |
|
| Idle timeout for ephemeral sessions (0 = disabled) |
|
| 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 |
| Most Google / SSO work |
|
| Signups, new IPs, sensitive accounts |
|
| Trusted sites, max speed |
|
Any explicit param you pass overrides the preset value.
Available params (all optional, all locked per-account):
Param | Type | Notes |
|
| e.g. |
|
| IANA timezone, e.g. |
|
|
|
|
|
|
|
| Disable WebGL entirely. Some sites break; use sparingly. |
|
|
|
|
| Installed font family names to inject (on top of OS defaults). |
|
| Paths to extracted Firefox addon dirs (must contain |
|
| Disable Cross-Origin-Opener-Policy β needed for some captcha/turnstile iframes. |
|
| 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 applyReset 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=trueOr 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-keyringorkwalletfirst.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:
Call
gv_setup_passwordβ a browser window opens for you to set a passwordMark sensitive profiles as private:
gv_make_private({account_id})When locked,
gv_list_accountshides private profiles; browser tools refuse to open themCall
gv_unlock({password})to access private profiles (stays unlocked untilgv_logoutor 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 ghostvaultPoint 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 |
|
| Scraping doesn't need a visible window (opposite of managed accounts) |
|
| Faster text scraping; turn off if you need screenshots |
|
| No cursor movement needed for read-only scraping |
|
| Short idle timeout β abandoned sessions clean themselves up |
|
| 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) |
|
Login-required site (Gmail, Drive, SSO) | Managed account ( |
Fill a public form (contact, signup-free download) |
|
Read Gmail / access Google services | Managed account |
Captcha-protected scrape target |
|
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 oneinputevent;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 |
|
|
| Type char-by-char (fill) or hover-then-click (click). |
|
|
| Target words-per-minute (40=slow, 90=avg, 150=fast). |
|
|
| Cadence spread 0β1 (log-normal sigma). 0=constant, 0.35=realistic, 1=erratic. |
|
|
| Chance per char to typo-then-correct (0β0.05). Produces realistic Backspace events. |
|
|
| 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=FalseThe 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 |
| Submit with Enter, Tab between fields, Escape to dismiss, Ctrl+A to select all |
| 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 |
| Agent decides every call; per-account | Trusted environments, fast iteration. |
| Humanize defaults ON; agent CAN turn it OFF explicitly by passing | Most real-world use β safety net without rigidity. |
| Humanize forced ON at the server. The agent cannot disable it, even by passing | 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=recommendedSet 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 fetchFor 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 |
Every | |
Create a custom provider recipe for any website + list/delete providers | |
Scan a login page for SSO buttons, form fields, 2FA, captcha + get recommendation | |
Level 3: record a login flow β replay automatically next time | |
Check session health + API call + JS eval + cookie reading | |
Human-like login (any provider) with realistic typing cadence (85 wpm, 2% typos) | |
Multi-field form with per-field typing speeds + Tab navigation + Shift+Tab to go back | |
reCAPTCHA v3 warm-up pattern: scroll, read, click, THEN act | |
Anonymous one-shot scrape: open_ephemeral β read + screenshot + links β close (no account) | |
Multi-page scrape on a persistent ephemeral session: loop {read, scroll, click Next} | |
Private/public gate flow via SDK (setup, lock, unlock, logout) | |
End-to-end: create + sign in + read Gmail + close | |
MCP protocol test: create + sign in + read Gmail | |
Encryption + auto-close + auto-lock + sign_out + delete | |
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=trueon 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 logbrowserver.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 |
| Gmail's DOM changes often β fall back to |
"Session not authenticated" | The session expired β re-run |
Agent action had no effect | Call |
Install fails on | Network issue β retry with |
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_gmailreturns empty, fall back togv_open_url+gv_get_page_contentwith 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
Add the input model to
src/ghostvault/inputs.pyAdd the logic to
src/ghostvault/tools.py(raiseToolErrorfor expected failures)Register it in
src/ghostvault/server.pywith@mcp.tool(name=..., annotations=...)and a thorough docstringAdd 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 . # lintLicense
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.
Maintenance
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
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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