Privilio MCP
by seanmartin91
README.md
<p align="center"><img src="assets/logo.png" width="96" alt="Privilio"></p>
# Privilio MCP: your encrypted contacts, available to your AI assistant
A **local, read-only [MCP](https://modelcontextprotocol.io) server** for [Privilio](https://privilio.ca), the end-to-end encrypted contacts app. It lets Claude, Grok Bot, Grok Build or any MCP client answer questions like *"Who do I know at Northwind?"* or *"What did I last discuss with Tom?"* using your own Privilio contacts.
It runs **on your computer**. It downloads your *encrypted* contacts from Privilio with a read-only access token, decrypts them locally with your passphrase, and returns only what a tool call asks for.
## What it can do
| Tool | What it does |
|---|---|
| `search_contacts` | Search by name, company, role, email, tag or note text (multiple words are AND-ed) |
| `get_contact` | One contact, with recent notes |
| `list_tags` | Your tags with counts |
| `recent_contacts` | Who you talked to most recently |
All four tools are annotated read-only. There is no tool that edits, deletes or sends anything.
## Privacy and security
- **Your passphrase never leaves your device.** It is read from an environment variable (or a file) when the server starts, used to derive the decryption key locally, and never sent over the network or logged. Privilio's servers cannot read your contacts and never see your passphrase.
- **Read-only.** The server only makes `GET` requests, and the Privilio access token is read-only on Privilio's side too. A token can fetch encrypted data only; it cannot change or delete anything, and it is useless without your passphrase.
- **The Vault is excluded.** Contacts you put in the Privilio Vault are never returned by any tool. (Today the Vault is a flag inside your encrypted data rather than a separate key, so this is enforced by this software, not by cryptography. Details: https://privilio.ca/security.)
- **Optional limits:** share only contacts with chosen tags (`PRIVILIO_ALLOWED_TAGS`; other tags are hidden too) and hide fields such as phone or email (`PRIVILIO_REDACT_FIELDS`).
- **Your AI provider sees what the tools return.** When you ask a question, the matching contacts are decrypted on your computer and sent to the assistant you are using (Anthropic, xAI, OpenAI, …) as part of the conversation. That provider's privacy policy applies to that text. Privilio's zero-knowledge guarantee covers Privilio's servers, not the assistant. Use the tag allow-list if you only want to expose part of your address book.
- **Contact text is untrusted.** Notes can contain anything, including instructions aimed at an AI. Tool output carries a notice telling the assistant to treat it as data, and there are no tools that can act on instructions anyway.
- **Revoke at any time:** Privilio > Settings > AI connections. Tokens are also revoked automatically when you change your passphrase.
- Rate limit: Privilio allows 60 requests per minute per token. This server syncs incrementally and at most once a minute.
## Requirements
- A Privilio account (web: https://app.privilio.ca, or the iOS app).
- Node.js 20 or newer (not needed for the `.mcpb` install in Claude Desktop, which uses its own runtime).
## 1. Create an access token
1. Sign in at https://app.privilio.ca.
2. Open **Settings > AI connections** and create a token. Give it a name (for example "Claude Desktop") and an expiry.
3. Copy the token (it starts with `pvl_`). It is shown **once**.
You will also need your Privilio **contacts passphrase** (the one you unlock the app with).
## 2a. Claude Desktop (extension, `.mcpb`)
1. Download `privilio-contacts.mcpb` from the [Releases page](../../releases) (or build it yourself: `npm install && npm run build && npm run mcpb`, which writes `out/privilio-contacts.mcpb`).
2. Double-click it, or in Claude Desktop open **Settings > Extensions** and drag it in.
3. Paste your access token and passphrase when asked. Claude Desktop stores them in the operating system's secure storage.
4. Ask: *"Who do I know at Northwind?"*
## 2b. Claude Desktop (manual config)
Edit `claude_desktop_config.json` (macOS: `~/Library/Application Support/Claude/`, Windows: `%APPDATA%\Claude\`):
```json
{
"mcpServers": {
"privilio": {
"command": "npx",
"args": ["-y", "github:seanmartin91/privilio-mcp"],
"env": {
"PRIVILIO_TOKEN": "pvl_...",
"PRIVILIO_PASSPHRASE": "your passphrase"
}
}
}
}
```
(Or clone this repo, run `npm install && npm run build`, and use `"command": "node", "args": ["/absolute/path/to/privilio-mcp/dist/cli.js"]`.)
To avoid keeping secrets in a config file, point at files only you can read instead: `PRIVILIO_TOKEN_FILE=/path/to/token` and `PRIVILIO_PASSPHRASE_FILE=/path/to/passphrase`.
## 3. Grok Bot, Grok Build and other stdio clients
Any client that can launch a stdio MCP server works. With the Grok Build CLI:
```bash
grok mcp add privilio \
--env PRIVILIO_TOKEN=pvl_... \
--env PRIVILIO_PASSPHRASE='your passphrase' \
-- npx -y github:seanmartin91/privilio-mcp
```
For Grok Bot, Cursor and similar apps, add a stdio server with command `npx`, args `-y github:seanmartin91/privilio-mcp` and the two environment variables above. (Exact menus differ by client; see its MCP documentation.)
## Configuration
| Variable | Meaning |
|---|---|
| `PRIVILIO_TOKEN` / `PRIVILIO_TOKEN_FILE` | Access token (`pvl_...`), required |
| `PRIVILIO_PASSPHRASE` / `PRIVILIO_PASSPHRASE_FILE` | Contacts passphrase, required. Removed from the process environment after it is read |
| `PRIVILIO_ALLOWED_TAGS` | e.g. `work,investor`: only contacts with one of these tags are visible; other tags are hidden |
| `PRIVILIO_REDACT_FIELDS` | e.g. `phone,email`, or `notes`: never returned |
| `PRIVILIO_MAX_NOTES` | Notes returned per contact (default 20, max 200) |
| `PRIVILIO_REFRESH_SECONDS` | Minimum seconds between syncs (default 60) |
| `PRIVILIO_API_URL` | Defaults to `https://app.privilio.ca`. Must be https (http only for localhost) |
## Troubleshooting
- **"Privilio rejected the access token"**: it is expired or revoked (this also happens after a passphrase change). Create a new one.
- **"Wrong passphrase"**: the passphrase is your Privilio contacts passphrase, not your sign-in password.
- **"has no encrypted contacts set up"**: open Privilio and finish setup first.
- **Token shows `__encrypted__:`** (some Claude Desktop versions): use `PRIVILIO_TOKEN_FILE` in the manual config, or re-enter the token in the extension settings.
- Logs go to stderr only (your client's MCP log). They never contain your token, passphrase or contacts.
## How it works
1. `GET /api/privilio/contacts/keys` returns your salt, a verifier and your wrapped data key. Your passphrase is stretched with scrypt (N=2^15) and checked against the verifier **locally**, then used to unwrap the data key.
2. `GET /api/privilio/contacts/records?limit=&since=&afterId=` returns encrypted records (XChaCha20-Poly1305) page by page. They are decrypted in memory; later syncs only fetch what changed.
3. Vault contacts and deleted contacts are dropped; the optional tag and field policies are applied; the tools search that in-memory set.
Nothing is written to disk and no analytics or telemetry of any kind is sent.
## Development
```bash
npm install
npm test # generates a synthetic encrypted fixture, runs unit + end-to-end tests against a local mock of the Privilio API
npm run build
```
The tests use only synthetic data and a mock server; no real account or network is needed. To try the server without an account: `PRIVILIO_SOURCE=fixture PRIVILIO_FIXTURE=fixtures/fixture.json PRIVILIO_PASSPHRASE=synthetic-test-passphrase-NOT-REAL npx tsx src/cli.ts` (after `npm run fixture`).
`src/crypto.ts` is a copy of the Privilio client crypto so this server decrypts exactly what the apps produce. The apps' optional breached-passphrase check is deliberately left out: this server never makes a network request using anything derived from your passphrase.
## License and contact
MIT, copyright Adapting Services Limited. Support: https://privilio.ca/contact. Privacy: https://privilio.ca/privacy. Security reports: see [SECURITY.md](SECURITY.md).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues