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.

VariableRequiredDefaultPurpose
PRIVACYFLOW_API_KEYyesYour PrivacyFlow API key (starts pf_live_…).
PRIVACYFLOW_BASE_URLnohttps://privacyflow.appOverride for self-hosted instances.
PRIVACYFLOW_API_KEY_HEADERnoauthorizationSet 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.appset 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.

ToolArgsBackend callNotes
privacyflow_check_healthnoneGET /api/v1/healthUnauthenticated. Returns {status, version}.
privacyflow_verify_api_keynoneGET /api/v1/auth/verifyConfirms the configured key and lists its appIds[]. No side effects.
privacyflow_poll_messageslimit?: number (1–50, default 10)GET /api/v1/messages/poll?limit=NDestructive read. Returns the same PolledMessage shape as the poll endpoint.
privacyflow_send_messagesmessages: SendMessage[] (1–50)POST /api/v1/messages/sendEach SendMessage requires appId, contactId, message, messenger; optional groupId. Validates locally with the same rules as the API.

Resources exposed

URITitleContent
privacyflow://docs/apiAPI DocumentationAn embedded summary of the four endpoints, auth methods, and limits. Useful for the LLM to look up a path without fetching.
privacyflow://docs/contact-formatsContact ID FormatsThe per-messenger contactId formats (Signal E.164, SimpleX numeric, Session 66-char hex starting 05).

Prompts exposed

PromptArgsOutput
privacyflow_reply_to_messagepolledMessage, replyTextA user-role message instructing the LLM to call privacyflow_send_messages with the routing fields lifted from the polled JSON.
privacyflow_broadcastappId, messenger, contactIds (CSV), messageA 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.

Last updated: