Skip to main content
Glama
alpharomercoma

proton-bridge-mcp

README.md
# proton-bridge-mcp

An [MCP](https://modelcontextprotocol.io) server that lets AI assistants (Claude Code, Claude Desktop, and other MCP clients) read, search, organize, and send Proton Mail through [Proton Mail Bridge](https://proton.me/mail/bridge).

Unofficial, community project. Not affiliated with or endorsed by Proton AG.

## Why Bridge, and why this exists

Proton Mail doesn't expose a public IMAP/SMTP API directly — Proton Mail Bridge runs locally, decrypts your mail, and re-exposes it as standard IMAP/SMTP on `127.0.0.1`. That's the only supported way to speak IMAP to a Proton Mail account programmatically.

Bridge's local IMAP/SMTP listener uses a **self-signed TLS certificate** generated per install. Most quick-start IMAP MCP servers handle this by disabling certificate verification (`rejectUnauthorized: false`) — which defeats the purpose of TLS. This server instead **pins the exact certificate** Bridge presents at setup time and validates every connection against it, so a certificate swap (e.g. from another process impersonating Bridge on your machine) is still detected and rejected.

## Features

- `list_mailboxes` — list all folders/labels
- `list_messages` — list recent messages in a mailbox
- `search_messages` — search by sender, subject, or body text
- `get_message` — fetch headers, plain-text body, flags, and attachment metadata for a message by UID (does not mark it read). All read tools label returned mail as untrusted data, since a hostile email could try to instruct the model
- `move_messages` — move messages to another mailbox: trash, archive, restore to inbox, mark as spam, or file into any folder
- `flag_messages` — star/unstar or mark read/unread
- `delete_messages` — permanently delete (expunge); irreversible in Trash/Spam/Drafts, elsewhere Bridge turns it into a move to Trash
- `manage_mailbox` — create, rename, or delete a folder (`Folders/...`) or label (`Labels/...`)
- `send_message` — send an email via Bridge SMTP, optionally as a threaded reply to a UID
- `create_draft` — compose the same way but save to Drafts instead of sending

The first four tools are read-only and carry `readOnlyHint`. The rest modify your mailbox or send mail and are annotated as writes (`readOnlyHint: false`, plus `destructiveHint` on everything except `send_message` and `create_draft`, since clearing a flag or moving/deleting mail undoes existing state), so MCP clients that gate on annotations will prompt before running them.

Every `mailbox` argument (and `move_messages`'s `destination`, and `reply_mailbox`) accepts either an alias (`inbox`, `trash`, `archive`, `spam`, `sent`, `drafts`) or an exact mailbox path from `list_mailboxes`. Aliases resolve through the IMAP special-use attributes Bridge advertises (`\Trash`, `\Archive`, ...), with a fallback to the conventional folder name. `flag_messages` takes `flag: "starred" | "read"` and a boolean `value`; Proton's star is the IMAP `\Flagged` flag. `move_messages`, `flag_messages`, and `delete_messages` accept a list of up to 100 UIDs (from `list_messages` or `search_messages`), so you can act on many messages in one call.

`send_message` and `create_draft` take `to`/`cc`/`bcc` (string or array), `subject`, `text`, and optional `html`. A recipient is required to send but optional for a draft. Pass `reply_to_uid` (and `reply_mailbox` if not INBOX) to reply: the recipient defaults to the original's Reply-To/From, the subject to `Re: ...`, and `In-Reply-To`/`References` are set so the reply threads correctly. Sending goes through Bridge's SMTP listener (default port `1025`, STARTTLS) validated against the same pinned certificate as IMAP.

## Prerequisites

- A Proton Mail plan that supports Bridge (Unlimited, Business, or legacy Professional/Visionary — Bridge requires a paid plan)
- [Proton Mail Bridge](https://proton.me/mail/bridge) installed, running, and logged in
- Node.js 18+
- An MCP client: [Claude Code](https://claude.com/claude-code), Claude Desktop, or any other MCP-compatible client

## Setup

### 1. Install

```bash
git clone https://github.com/alpharomercoma/proton-bridge-mcp.git
cd proton-bridge-mcp
npm install
```

(Once published to npm, this step will be optional — see [Using via npx](#using-via-npx) below.)

### 2. Run the setup wizard

```bash
npm run setup
```

You'll be asked for:

- Bridge IMAP host/port (defaults: `127.0.0.1` / `1143`) and SMTP port (default `1025`)
- Your Proton Mail address
- Your **Bridge password** — this is a Bridge-generated password shown in the Bridge app under your account, *not* your normal Proton account password

The wizard then:

1. Connects to Bridge and performs the real IMAP `STARTTLS` upgrade to fetch its certificate (no `openssl` dependency — a portable Node-native handshake)
2. Prints the certificate's SHA-256 fingerprint for your own awareness
3. Verifies login actually works, validated strictly against that same pinned certificate
4. Writes `~/.config/proton-bridge-mcp/credentials.json` and `bridge-ca.pem`, both `chmod 600`, inside a `chmod 700` directory

Nothing is written until login has been verified.

### 3. Register with your MCP client

**Claude Code:**

```bash
claude mcp add proton-mail -s user -- node /path/to/proton-bridge-mcp/bin/proton-bridge-mcp.mjs
```

(Use `-- npx -y @alpharomercoma/proton-bridge-mcp` instead — see [Using via npx](#using-via-npx) below.)

**Claude Desktop / other MCP clients** — add to your MCP config file:

```json
{
  "mcpServers": {
    "proton-mail": {
      "command": "node",
      "args": ["/path/to/proton-bridge-mcp/bin/proton-bridge-mcp.mjs"]
    }
  }
}
```

### Using via npx

Published on npm as [`@alpharomercoma/proton-bridge-mcp`](https://www.npmjs.com/package/@alpharomercoma/proton-bridge-mcp) — skip the local clone entirely:

```bash
npx -y -p @alpharomercoma/proton-bridge-mcp proton-bridge-mcp-setup
claude mcp add proton-mail -s user -- npx -y @alpharomercoma/proton-bridge-mcp
```

**Codex CLI:**

Tested end-to-end against Codex CLI 0.146.0 (`codex mcp add`, real Bridge connection, real tool calls). Two things are Codex-specific and easy to miss:

1. Codex's MCP support is behind an under-development feature flag as of 0.146.0. Enable it once:

   ```bash
   codex features enable mcp_2026_07_28
   ```

2. Register the server with an **exact, pinned version** — not a bare `npx -y @alpharomercoma/proton-bridge-mcp`:

   ```bash
   codex mcp add proton-mail -- npx -y @alpharomercoma/proton-bridge-mcp@1.1.0
   ```

   Reason: if you've ever run `npm install -g @alpharomercoma/proton-bridge-mcp` on the same machine, an unpinned `npx` invocation will silently prefer that stale global install over fetching the current version from the registry — no error, it just quietly runs old code. Pinning the version sidesteps this entirely. Bump the pinned version here when you upgrade.

Once registered, `codex mcp get proton-mail` should show `enabled: true`, and the read-only tools (`list_mailboxes`, `list_messages`, `search_messages`, `get_message`) work in both the interactive `codex` session and non-interactive `codex exec` runs without triggering an approval prompt — they're tagged with `readOnlyHint` annotations for exactly this reason. The write tools (everything after `get_message`) are not read-only, so expect an approval prompt for those depending on your client's policy.

## Configuration reference

By default, config lives at `~/.config/proton-bridge-mcp/`. Override the location or individual values with environment variables (useful for multiple accounts or containers):

| Variable | Purpose | Default |
|---|---|---|
| `PROTON_BRIDGE_MCP_HOME` | Config directory | `~/.config/proton-bridge-mcp` |
| `PROTON_BRIDGE_HOST` | Bridge IMAP/SMTP host | value from `credentials.json` |
| `PROTON_BRIDGE_PORT` | Bridge IMAP port | value from `credentials.json` (default `1143`) |
| `PROTON_BRIDGE_SMTP_PORT` | Bridge SMTP port (sending) | value from `credentials.json` (default `1025`) |
| `PROTON_BRIDGE_USER` | Proton Mail address | value from `credentials.json` |
| `PROTON_BRIDGE_PASSWORD` | Bridge password | value from `credentials.json` |
| `PROTON_BRIDGE_CA_PATH` | Path to pinned cert PEM | `<config dir>/bridge-ca.pem` |

Environment variables always take precedence over the credentials file.

## Security model

- **No disabled TLS verification.** The server validates every connection against the certificate pinned during setup (`tls.ca`), not `rejectUnauthorized: false`.
- **Trust-on-first-use, like SSH.** The one moment we can't validate against anything is fetching the certificate itself during setup — the same bootstrap problem SSH solves by showing you a host-key fingerprint on first connect. Bridge only listens on `127.0.0.1`, so this step can't be intercepted over the network; only another process already running as you on the same machine could tamper with it, and at that point your credentials file is equally exposed regardless of TLS.
- **Credentials never touch the MCP client's own config.** Rather than passing `-e PROTON_BRIDGE_PASSWORD=...` to `claude mcp add` (which lands in `~/.claude.json` and your shell history), the password lives only in `credentials.json`, `chmod 600`, outside any repo or synced config.
- **Rotate the Bridge password if it's ever been pasted into a chat, terminal share, or committed by accident.** Bridge passwords are cheap to regenerate (Bridge app → account → "Generate new password") and don't touch your actual Proton account password.

## Troubleshooting

**`Missing Proton Bridge "host"` / `"user"` / `"password"`** — run `npm run setup` (or `npx -p @alpharomercoma/proton-bridge-mcp proton-bridge-mcp-setup`) first, or set the `PROTON_BRIDGE_*` env vars.

**`No pinned Bridge certificate found`** — same as above; the setup wizard writes `bridge-ca.pem` alongside the credentials.

**Login fails during setup** — double check you're using the Bridge-generated password (visible in the Bridge app), not your Proton account password. Also confirm Bridge is running and unlocked.

**Certificate fingerprint changes unexpectedly** — this happens if you reinstall Bridge or reset its config (it regenerates its cert). Re-run `npm run setup` to re-pin. If you didn't reinstall Bridge and the fingerprint changed anyway, treat that as suspicious and investigate before continuing.

## Contributing

Issues and PRs welcome. Run `npm run lint`, `npm test`, and `npm run build` (syntax check plus a dry-run `npm pack`) before opening a PR; CI runs the same three on Node 18/20/22. Keep changes scoped. Anything that widens what the server can do to your mailbox (new write tools, attachments, bulk operations) should come with tests and a README note on its safety annotations.

## License

MIT — see [LICENSE](LICENSE).

TDQS

A3.9/5.0

Scored across 4 tools

Disambiguation5/5

Each tool targets a distinct action: listing mailboxes, listing messages, searching messages, and fetching a single message. There is no overlap or ambiguity between them.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern: list_mailboxes, list_messages, search_messages, get_message. The naming is predictable and uniform.

Tool Count5/5

With 4 tools, the set is well-scoped for a focused read-only email access use case. Each tool serves a clear purpose and none are redundant.

Completeness4/5

The toolset covers the primary read workflow: enumerate mailboxes, list messages, search, and fetch full content. However, it lacks send, draft, or message mutation capabilities, which are common in email tools but may be intentionally omitted for a read-only bridge interface.

Maintenance

ActivityMaintained
ResponsivenessNo issues