|
| 1 | +# Vault Unsealing |
| 2 | + |
| 3 | +> If you got here from a "Vault locked" error, jump to [Recovery](#recovery). |
| 4 | +
|
| 5 | +## Overview |
| 6 | + |
| 7 | +The Perplexity MCP server stores authentication cookies encrypted at rest in `~/.perplexity-mcp/profiles/<name>/vault.enc`. To use the file, the server must unlock ("unseal") the encryption key. There are three unseal paths, tried in order: |
| 8 | + |
| 9 | +1. **OS keychain** (preferred) — Windows Credential Manager, macOS Keychain, Linux libsecret/gnome-keyring. The server stores a 32-byte random key under service `perplexity-user-mcp`, account `vault-master-key`. |
| 10 | +2. **Env var** — `PERPLEXITY_VAULT_PASSPHRASE` (fallback for headless Linux, sandboxed runtimes, or when the keychain is unavailable). |
| 11 | +3. **TTY prompt** — interactive only (CLI use). Skipped when running as an stdio MCP server (no TTY). |
| 12 | + |
| 13 | +The vault file is encrypted with AES-256-GCM. The KDF for passphrase-derived keys is scrypt (logN=17, r=8, p=1). Format details live in inline comments at the top of [`packages/mcp-server/src/vault.js`](../packages/mcp-server/src/vault.js). |
| 14 | + |
| 15 | +## Standalone CLI vs. VS Code extension |
| 16 | + |
| 17 | +- **Standalone `perplexity-user-mcp`** (npm package) uses the chain above directly. If you need to set a passphrase, run `npx perplexity-user-mcp setup-vault` — it generates a strong 256-bit base64url passphrase and prints per-platform persistence snippets. |
| 18 | +- **VS Code extension** uses the same chain in its login runner, but ALSO stores a SecretStorage-backed passphrase if the keychain probe fails. Starting with **0.8.41**, the extension passes that passphrase to the long-running daemon at spawn time via a narrowly-scoped env builder, so external IDE clients (Claude Code, Antigravity, Codex CLI, Cursor) routed through the daemon don't need their own vault credentials. |
| 19 | + |
| 20 | +## Per-platform notes |
| 21 | + |
| 22 | +### Windows |
| 23 | + |
| 24 | +Windows Credential Manager works out of the box for the extension's bundled `keytar` under VS Code's Electron runtime. If you see "Vault locked" in an external client's launcher (Claude Code on Node 24+, Antigravity, sandboxed Codex CLI), the issue is almost certainly that the launcher's runtime can't load `keytar` — but the **extension-managed daemon** still owns the credentials. Fix: ensure your extension is **0.8.41 or later**, then reload VS Code. |
| 25 | + |
| 26 | +### macOS |
| 27 | + |
| 28 | +Same as Windows — macOS Keychain works under the bundled keytar. |
| 29 | + |
| 30 | +### Linux |
| 31 | + |
| 32 | +Headless Linux has no libsecret by default. Two options: |
| 33 | +1. Install libsecret + gnome-keyring (or kwallet) so keytar succeeds. |
| 34 | +2. Set `PERPLEXITY_VAULT_PASSPHRASE` in your IDE's MCP env block. Run `npx perplexity-user-mcp setup-vault` for a strong generated passphrase + persistence snippet. |
| 35 | + |
| 36 | +## Recovery |
| 37 | + |
| 38 | +If you see one of these errors: |
| 39 | + |
| 40 | +- `Vault decrypt failed: wrong passphrase or corrupted ciphertext` |
| 41 | +- `Vault locked: no keychain, no env var, no TTY` |
| 42 | + |
| 43 | +The vault was written under unseal material that is no longer available (rotated keychain key, changed `PERPLEXITY_VAULT_PASSPHRASE`, lost SecretStorage entry). There is **no recovery without the original material** — AES-256-GCM is authenticated and refuses to decrypt under the wrong key, by design. |
| 44 | + |
| 45 | +Recovery flow: |
| 46 | + |
| 47 | +1. Quarantine and discard the unreadable vault: |
| 48 | + ```bash |
| 49 | + npx perplexity-user-mcp logout --purge --profile <name> |
| 50 | + ``` |
| 51 | + (replace `<name>` with your profile name; default is `default`) |
| 52 | +2. Log in again from the VS Code dashboard, or: |
| 53 | + ```bash |
| 54 | + npx perplexity-user-mcp login --profile <name> |
| 55 | + ``` |
| 56 | +3. The new vault is written under whatever unseal material is currently available. |
| 57 | + |
| 58 | +## Vault format versions |
| 59 | + |
| 60 | +| Version | Status | KDF | Notes | |
| 61 | +|---|---|---|---| |
| 62 | +| v1 | legacy, decrypt-only | HKDF-SHA256 (static salt) | 0.6.x and earlier | |
| 63 | +| v2 | legacy, decrypt-only | HKDF-SHA256 (per-blob salt) | 0.7.x | |
| 64 | +| v3 | current | scrypt logN=17 | 0.8.x; per-blob salt + KDF params | |
| 65 | + |
| 66 | +Reads never mutate the file. Writes always emit the latest supported version. |
| 67 | + |
| 68 | +## Related |
| 69 | + |
| 70 | +- [Troubleshooting external MCP clients](troubleshooting/external-mcp-clients.md) — Claude Code, Antigravity, Codex CLI specifics |
| 71 | +- [Codex CLI setup](codex-cli-setup.md) — Codex CLI configuration walkthrough |
0 commit comments