MCP server
The PrivacyFlow MCP server — install it in Claude Desktop, Cursor, or OpenCode, and let an LLM poll and send encrypted messages as tools.
The PrivacyFlow MCP server is a Model Context Protocol server that exposes the public API as four tools, two prompts, and two resources to any MCP-compatible LLM client — Claude Desktop, Cursor, or OpenCode. It runs as a subprocess launched by the LLM client over stdio.
Install
Two options:
npm install -g privacyflow-mcp-server
# or run on demand without installing:
npx -y privacyflow-mcp-server
Requires Node 18 or newer and a PrivacyFlow API key (see Credentials).
Configure
Three environment variables. Only PRIVACYFLOW_API_KEY is required.
| Variable | Required | Default | Purpose |
|---|---|---|---|
PRIVACYFLOW_API_KEY | yes | — | Your PrivacyFlow API key (starts pf_live_…). |
PRIVACYFLOW_BASE_URL | no | https://privacyflow.app | Override for self-hosted instances. |
PRIVACYFLOW_API_KEY_HEADER | no | authorization | Set to x-api-key to authenticate via the X-API-Key header instead of Bearer. |
Note
Older privacyflow-mcp-server npm releases ship with https://api.privacyflow.app as the library default for PRIVACYFLOW_BASE_URL. The canonical host is https://privacyflow.app — set PRIVACYFLOW_BASE_URL explicitly in your config as shown in every example below, until a future MCP server release updates the default. Verifying which version you have: run npm ls -g privacyflow-mcp-server and check the changelog on GitHub.
Add to your LLM client
Claude Desktop
~/Library/Application Support/Claude/claude_desktop_config.json on macOS, or %APPDATA%\Claude\claude_desktop_config.json on Windows. Add the privacyflow entry:
{
"mcpServers": {
"privacyflow": {
"command": "npx",
"args": ["-y", "privacyflow-mcp-server"],
"env": {
"PRIVACYFLOW_API_KEY": "pf_live_your_key_here",
"PRIVACYFLOW_BASE_URL": "https://privacyflow.app"
}
}
}
}
Restart Claude Desktop. The four privacyflow_* tools become available in any chat where tools are on.
Cursor
~/.cursor/mcp.json:
{
"mcpServers": {
"privacyflow": {
"command": "npx",
"args": ["-y", "privacyflow-mcp-server"],
"env": {
"PRIVACYFLOW_API_KEY": "pf_live_your_key_here"
}
}
}
}
OpenCode
.opencode.json in your project root:
{
"mcp": {
"privacyflow": {
"type": "local",
"enabled": true,
"command": "npx",
"args": ["-y", "privacyflow-mcp-server"],
"env": {
"PRIVACYFLOW_API_KEY": "pf_live_your_key_here"
}
}
}
}
Tools exposed
The server registers four tools — one per public API endpoint.
| Tool | Args | Backend call | Notes |
|---|---|---|---|
privacyflow_check_health | none | GET /api/v1/health | Unauthenticated. Returns {status, version}. |
privacyflow_verify_api_key | none | GET /api/v1/auth/verify | Confirms the configured key and lists its appIds[]. No side effects. |
privacyflow_poll_messages | limit?: number (1–50, default 10) | GET /api/v1/messages/poll?limit=N | Destructive read. Returns the same PolledMessage shape as the poll endpoint. |
privacyflow_send_messages | messages: SendMessage[] (1–50) | POST /api/v1/messages/send | Each SendMessage requires appId, contactId, message, messenger; optional groupId. Validates locally with the same rules as the API. |
Resources exposed
| URI | Title | Content |
|---|---|---|
privacyflow://docs/api | API Documentation | An embedded summary of the four endpoints, auth methods, and limits. Useful for the LLM to look up a path without fetching. |
privacyflow://docs/contact-formats | Contact ID Formats | The per-messenger contactId formats (Signal E.164, SimpleX numeric, Session 66-char hex starting 05). |
Prompts exposed
| Prompt | Args | Output |
|---|---|---|
privacyflow_reply_to_message | polledMessage, replyText | A user-role message instructing the LLM to call privacyflow_send_messages with the routing fields lifted from the polled JSON. |
privacyflow_broadcast | appId, messenger, contactIds (CSV), message | A user-role message instructing the LLM to call privacyflow_send_messages with one message per recipient, batch ≤ 50. |
The prompts themselves don’t call the backend — they emit the instructions the LLM then fulfills by calling privacyflow_send_messages.
Example: verify → poll → reply
You (in Claude Desktop):
Check my PrivacyFlow key, then poll once, and if there’s a message asking about shipping, reply that it left today.
Claude calls privacyflow_verify_api_key:
{ "valid": true, "appIds": ["app_123"] }
Then privacyflow_poll_messages({ limit: 10 }):
{
"messages": [{
"appId": "app_123",
"messenger": "signal",
"contactId": "+12025550104",
"messageId": "5dd6…",
"content": "Where's my order?",
"isGroupMessage": false,
"isCommand": false
}],
"count": 1,
"queue": "poll:app_123"
}
Claude calls privacyflow_send_messages({ messages: [{ appId: "app_123", contactId: "+12025550104", messenger: "signal", message: "It left today — you'll have it tomorrow." }] }):
{
"successfulMessages": [{ "messageId": "8a5b…", "appId": "app_123", "contactId": "+12025550104", "messenger": "signal" }],
"failedMessages": [],
"totalAccepted": 1,
"totalFailed": 0
}
Claude replies with a one-liner summary. You didn’t touch curl.
Example: broadcast
Ask Claude:
Use the privacyflow_broadcast prompt to send “Service window starts in 10 minutes” to three Signal contacts: +12025550104, +12025550105, +12025550106, on app_123.
Claude invokes the prompt, which expands into the instruction “build 3 message objects and call privacyflow_send_messages.” Claude then makes the call with one messages[] entry per recipient and confirms.
Inspect locally
The MCP Inspector is the fastest way to verify your config before pointing an LLM at it:
npx @modelcontextprotocol/inspector node build/index.js
It opens a local web UI where you can call each tool, view each resource, and see the JSON-RPC traffic. Useful when you’re rotating keys or testing a new client config.
Warning
The MCP server is launched with your PRIVACYFLOW_API_KEY in its environment. If you commit your Claude Desktop or Cursor config to a repo, use a secrets manager or environment substitution rather than pasting the key literally. Each config example above shows the key inline for clarity — replace it.