ProtonScope
by dazzle-blip
README.md
# ProtonScope
A lightweight **MCP server** that gives an AI agent a **scoped, read-and-draft-only** view
into your Proton Mail through **Proton Bridge**.
The scope is enforced in code, not by prompting: the agent physically cannot read or touch
mail outside the workspace you configure, and **it can never send** — replies are saved as
drafts for you to review and send yourself in Proton.
## What it does (and doesn't)
- ✅ Read mail within a configured scope (specific folders/labels, optionally only starred,
optionally only certain correspondents — including mail where you were **BCC'd**).
- ✅ Work **thread-centric**: list and read whole conversations.
- ✅ **Draft** replies and new messages (saved to your Drafts).
- ✅ Optional housekeeping: mark read/unread, star, move/label within scope, optional delete.
- ❌ **No sending. No SMTP.** The server never opens an SMTP connection and has no send tool.
- ❌ No calendar, no contacts. Mail only.
> Proton Bridge exposes mail over local IMAP/SMTP only; this server uses **IMAP exclusively**.
## How scope works
Each *workspace* is a single committed YAML file, `workspaces/<name>.yaml` (name/description/
account plus a `mail:` section for permission, scope, and write targets). Scope is
**deny-by-default** and combines (AND) up to three filters — a message is in scope only if
**all** apply:
1. it is in an allowed **source** mailbox (`scope.sources`);
2. if `require_starred: true`, it is **starred**;
3. if `scope.addresses` is set, one of those addresses appears in From/To/Cc **or** the
delivery headers (`Delivered-To` / `X-Original-To` / `Envelope-To` — this is how BCC'd
mail to your aliases is matched).
See [`workspaces/example-clients.yaml`](workspaces/example-clients.yaml) for a fully
commented example. One server instance serves exactly one workspace.
## Prerequisites
1. **Proton Bridge** installed, running, and signed in. Add your account and note the
per-account **IMAP username** and **Bridge password** (Bridge → account → *Mailbox
configuration*). This is the Bridge password, **not** your Proton login password.
2. **Python 3.11+** and [**uv**](https://docs.astral.sh/uv/).
## Install
```bash
git clone <this-repo> code-protonscope
cd code-protonscope
uv sync
```
Run the tests (no Proton Bridge needed — scope logic is pure):
```bash
uv run pytest
```
<details>
<summary>No <code>uv</code>? Use a plain venv + pip instead</summary>
```bash
python -m venv .venv
# Linux/macOS:
source .venv/bin/activate
# Windows PowerShell:
.\.venv\Scripts\Activate.ps1
pip install -e . pytest
pytest
protonscope --workspace workspaces/my-clients.yaml # after configuring (see below)
```
Requires a real Python 3.11+ on `PATH` (the Microsoft Store stub won't work).
</details>
## Configure a workspace
Copy the example and edit it:
```bash
# Linux/macOS
cp workspaces/example-clients.yaml workspaces/my-clients.yaml
```
```powershell
# Windows (PowerShell)
Copy-Item workspaces/example-clients.yaml workspaces/my-clients.yaml
```
Edit `workspaces/my-clients.yaml`: your `username`, and under `mail:` your scope,
permission tier, and the real names of your Drafts/Trash mailboxes as Bridge reports them.
## Try it locally with the MCP Inspector
```bash
PROTONSCOPE_BRIDGE_PASSWORD="<bridge-password>" \
uv run protonscope --workspace workspaces/my-clients.yaml
```
Or with the interactive inspector:
```bash
PROTONSCOPE_WORKSPACE=workspaces/my-clients.yaml \
PROTONSCOPE_BRIDGE_PASSWORD="<bridge-password>" \
uv run mcp dev src/protonscope/__main__.py
```
On **Windows PowerShell**, set the env vars first:
```powershell
$env:PROTONSCOPE_BRIDGE_PASSWORD = "<bridge-password>"
uv run protonscope --workspace workspaces/my-clients.yaml
```
## Register with an MCP client
Add **one entry per workspace** to your client config (e.g. Claude Desktop's
`claude_desktop_config.json`, or a project `.mcp.json`):
```json
{
"mcpServers": {
"protonscope-clients": {
"command": "uv",
"args": ["run", "protonscope", "--workspace", "workspaces/my-clients.yaml"],
"env": { "PROTONSCOPE_BRIDGE_PASSWORD": "<bridge-password>" }
}
}
}
```
> On Windows, use the absolute path to the workspace and ensure `uv` is on `PATH` (or give
> the full path to `uv.exe`). Bridge's default ports (IMAP 1143) are identical on both OSes.
### Picking a permission tier
| `permission` | Reads | Drafts & housekeeping | Sends |
|--------------|:-----:|:---------------------:|:-----:|
| `readonly` | ✅ | ❌ | ❌ (never) |
| `read-write` | ✅ | ✅ | ❌ (never) |
`delete_message` is only offered when `allow_delete: true` (and needs `write_targets.trash`).
## Security notes
- Workspace YAML is committed; **secrets are not**. The Bridge password is only ever read
from `PROTONSCOPE_BRIDGE_PASSWORD`. `workspaces/.gitignore` also ignores `*.secret` /
`*.local.yaml`.
- Thread reconstruction stays within your allowed sources, so a thread may come back
*partial* if some messages are outside scope — this is intentional (no peeking via All Mail).
- The scope core ([`src/protonscope/scope.py`](src/protonscope/scope.py)) is pure and fully
unit-tested ([`tests/test_scope.py`](tests/test_scope.py)).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing