@rndmjoker/proton-mcp 0.4.7 → 0.4.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +69 -21
  2. package/dist/bridge/certificate.d.ts +33 -1
  3. package/dist/bridge/certificate.js +82 -9
  4. package/dist/bridge/certificate.js.map +1 -1
  5. package/dist/bridge/connection.js +31 -6
  6. package/dist/bridge/connection.js.map +1 -1
  7. package/dist/bridge/errors.d.ts +8 -0
  8. package/dist/bridge/errors.js +28 -3
  9. package/dist/bridge/errors.js.map +1 -1
  10. package/dist/config.d.ts +6 -0
  11. package/dist/config.js +1 -0
  12. package/dist/config.js.map +1 -1
  13. package/dist/credentials/availability.d.ts +5 -0
  14. package/dist/credentials/availability.js +7 -0
  15. package/dist/credentials/availability.js.map +1 -1
  16. package/dist/credentials/encrypted-file.js +7 -2
  17. package/dist/credentials/encrypted-file.js.map +1 -1
  18. package/dist/credentials/keyring.d.ts +12 -2
  19. package/dist/credentials/keyring.js +44 -6
  20. package/dist/credentials/keyring.js.map +1 -1
  21. package/dist/credentials/plain-file.js +8 -2
  22. package/dist/credentials/plain-file.js.map +1 -1
  23. package/dist/credentials/session-bus.d.ts +38 -0
  24. package/dist/credentials/session-bus.js +68 -0
  25. package/dist/credentials/session-bus.js.map +1 -0
  26. package/dist/credentials/store.d.ts +5 -1
  27. package/dist/credentials/store.js.map +1 -1
  28. package/dist/in-flight.d.ts +6 -3
  29. package/dist/in-flight.js +6 -3
  30. package/dist/in-flight.js.map +1 -1
  31. package/dist/mail/actions.d.ts +0 -2
  32. package/dist/mail/actions.js +8 -7
  33. package/dist/mail/actions.js.map +1 -1
  34. package/dist/mail/attachments.d.ts +12 -2
  35. package/dist/mail/attachments.js +19 -11
  36. package/dist/mail/attachments.js.map +1 -1
  37. package/dist/mail/compose.d.ts +70 -15
  38. package/dist/mail/compose.js +147 -11
  39. package/dist/mail/compose.js.map +1 -1
  40. package/dist/mail/drafts.d.ts +28 -2
  41. package/dist/mail/drafts.js +91 -21
  42. package/dist/mail/drafts.js.map +1 -1
  43. package/dist/mail/ids.d.ts +10 -0
  44. package/dist/mail/ids.js +16 -4
  45. package/dist/mail/ids.js.map +1 -1
  46. package/dist/mail/labels.js +9 -4
  47. package/dist/mail/labels.js.map +1 -1
  48. package/dist/mail/messages.d.ts +50 -10
  49. package/dist/mail/messages.js +94 -6
  50. package/dist/mail/messages.js.map +1 -1
  51. package/dist/mail/saved-attachments.d.ts +128 -0
  52. package/dist/mail/saved-attachments.js +448 -0
  53. package/dist/mail/saved-attachments.js.map +1 -0
  54. package/dist/mail/search.d.ts +73 -5
  55. package/dist/mail/search.js +150 -27
  56. package/dist/mail/search.js.map +1 -1
  57. package/dist/mail/send.js +24 -9
  58. package/dist/mail/send.js.map +1 -1
  59. package/dist/mail/uid-search.d.ts +17 -0
  60. package/dist/mail/uid-search.js +25 -0
  61. package/dist/mail/uid-search.js.map +1 -0
  62. package/dist/mime/filenames.d.ts +24 -0
  63. package/dist/mime/filenames.js +58 -0
  64. package/dist/mime/filenames.js.map +1 -0
  65. package/dist/mime/parts.d.ts +34 -0
  66. package/dist/mime/parts.js +92 -0
  67. package/dist/mime/parts.js.map +1 -0
  68. package/dist/server.js +39 -8
  69. package/dist/server.js.map +1 -1
  70. package/dist/session.d.ts +15 -3
  71. package/dist/session.js +35 -8
  72. package/dist/session.js.map +1 -1
  73. package/dist/tools/actions.js +2 -1
  74. package/dist/tools/actions.js.map +1 -1
  75. package/dist/tools/confirm.js +47 -11
  76. package/dist/tools/confirm.js.map +1 -1
  77. package/dist/tools/drafts.d.ts +3 -0
  78. package/dist/tools/drafts.js +31 -10
  79. package/dist/tools/drafts.js.map +1 -1
  80. package/dist/tools/format.d.ts +8 -0
  81. package/dist/tools/format.js +44 -6
  82. package/dist/tools/format.js.map +1 -1
  83. package/dist/tools/guidance.js +27 -3
  84. package/dist/tools/guidance.js.map +1 -1
  85. package/dist/tools/messages.js +41 -13
  86. package/dist/tools/messages.js.map +1 -1
  87. package/dist/tools/pending-view.d.ts +7 -0
  88. package/dist/tools/pending-view.js +4 -1
  89. package/dist/tools/pending-view.js.map +1 -1
  90. package/dist/tools/saved.d.ts +15 -0
  91. package/dist/tools/saved.js +107 -0
  92. package/dist/tools/saved.js.map +1 -0
  93. package/dist/tools/send.js +12 -4
  94. package/dist/tools/send.js.map +1 -1
  95. package/dist/web/layout.js +2 -0
  96. package/dist/web/layout.js.map +1 -1
  97. package/dist/web/pages.js +1 -0
  98. package/dist/web/pages.js.map +1 -1
  99. package/dist/web/pending.d.ts +4 -0
  100. package/dist/web/pending.js +32 -4
  101. package/dist/web/pending.js.map +1 -1
  102. package/dist/web/server.d.ts +16 -5
  103. package/dist/web/server.js +12 -8
  104. package/dist/web/server.js.map +1 -1
  105. package/package.json +21 -18
package/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  An MCP server for Proton Mail. It talks to a locally running Proton Mail Bridge and makes your mailbox available to AI assistants such as Claude.
4
4
 
5
+ > **Unofficial.** proton-mcp is not made by, affiliated with or endorsed by Proton AG. "Proton" and "Proton Mail" are their trademarks.
6
+ >
7
+ > **Largely AI-generated.** Most of the code, tests and documentation in this repository were written by Anthropic's Claude Opus models. I decide what gets built and how, and I note this on every one of my projects that is largely AI-generated.
8
+
5
9
  **Status: under construction.** Reading works and can be used, and so does signing in through the browser. Labels, moving between folders, read state, trash, drafts and sending all work. Every send asks you first, and that question is enforced by the server rather than requested in a prompt. See [Status](#status) for the details.
6
10
 
7
11
  ## Why everything runs locally
@@ -17,24 +21,26 @@ This server therefore runs on your machine as well, started by the AI client as
17
21
  | Tool | What it does |
18
22
  | :--- | :--- |
19
23
  | `list_folders` | Lists folders and labels, grouped by kind |
20
- | `list_messages` | Headers of a mailbox, newest first, with paging |
21
- | `search_messages` | Full text, subject, sender, recipient, date range, read state, star, size |
24
+ | `list_messages` | Headers of a mailbox, newest first, with paging. In "All Mail" the discarded ones are marked as such |
25
+ | `search_messages` | Full text, subject, sender, recipient, date range, read state, star, size. Dates are the sender's, matching what the results show. Subject, sender and recipient match umlauts and spaces as written. Full text cannot reach attachments or parts sent as base64, and the answer says so |
22
26
  | `get_message` | One message as readable text, HTML converted, budgeted |
23
27
  | `get_attachment` | One attachment by index, textual types only |
28
+ | `save_attachment` | Saves one attachment as a file into the directory you set in `PROTON_MCP_ATTACHMENT_DIR`, so the assistant can open it. Deleted again after an hour and when the server stops, see [Saved attachments](#saved-attachments) |
29
+ | `delete_saved_attachments` | Deletes files `save_attachment` wrote, all of them or the ones named, and nothing else |
24
30
  | `add_label` | Applies an existing label. The message stays in its folder |
25
31
  | `remove_label` | Removes a label. Folder, other labels and the message itself are untouched |
26
32
  | `move_messages` | Moves messages into a folder. Labels survive the move |
27
33
  | `set_flags` | Marks read or unread and sets or clears the star |
28
34
  | `trash_messages` | Moves messages to the trash, which is what deletion means here |
29
35
  | `create_draft` | Writes a draft. Nothing is sent |
30
- | `update_draft` | Replaces a draft, keeping its id |
36
+ | `update_draft` | Replaces a draft, keeping its id and the files stored with it |
31
37
  | `reply_draft` | Prepares a reply as a draft, with the original quoted |
32
38
  | `forward_draft` | Prepares a forward as a draft, attachments and all |
33
39
  | `list_drafts` | The drafts, newest first |
34
40
  | `send_message` | Composes and sends. Asks you first, always |
35
41
  | `send_reply` | Replies and sends, keeping the conversation intact |
36
42
  | `send_forward` | Forwards and sends, attachments and all |
37
- | `send_draft` | Sends a draft that is already written |
43
+ | `send_draft` | Sends a draft that is already written, exactly as it was stored |
38
44
  | `open_configuration` | Hands back the address of the local web interface, with the token that opens it |
39
45
  | `check_for_updates` | Asks npm whether a newer version exists. The only thing here that contacts anything but your own machine, and only when called |
40
46
 
@@ -75,7 +81,7 @@ This table says what the server cannot do today. The issue behind each entry say
75
81
  | Choosing in the interface how much markup a message may carry. The levels exist and a caller picks one per message; what is missing is a ceiling the caller cannot raise | [#24](https://github.com/RndmJoker/proton-mcp/issues/24) |
76
82
  | A fixed extra recipient the assistant cannot remove | [#18](https://github.com/RndmJoker/proton-mcp/issues/18) |
77
83
 
78
- **Binary attachments** are missing from that table on purpose. They are not an unfinished feature waiting for its turn: `get_attachment` refuses anything that is not text and says why. Handing one over would mean either base64 in the context window, which is unusable, or writing decrypted content to your disk, which this server does not do. Changing that needs a decision first, not an implementation, so there is nothing to track yet.
84
+ **Binary attachments** are not returned as text: base64 in the context window would be unusable. `save_attachment` writes one to a directory you name instead, and it is off until you name one, see [Saved attachments](#saved-attachments).
79
85
 
80
86
  ### What will never exist
81
87
 
@@ -90,7 +96,7 @@ These limits come from the Bridge itself and cannot be worked around:
90
96
  ## Requirements
91
97
 
92
98
  - **A paid Proton plan.** The Bridge is not included in the free tier.
93
- - **Proton Mail Bridge**, installed, running and unlocked. The official application expects a desktop. On a machine without one, [proton-mail-bridge-docker](https://github.com/RndmJoker/proton-mail-bridge-docker) runs it in a container instead. That is a way to get a bridge, not a way to put one somewhere else: it decrypts your mail wherever it runs, so a bridge on another machine means your mail is decrypted on that machine. The section above still applies, and the container's own readme says the same.
99
+ - **Proton Mail Bridge**, installed, running and unlocked. Tried against versions 3.25.0 and 3.27.1. The official application expects a desktop. On a machine without one, [proton-mail-bridge-docker](https://github.com/RndmJoker/proton-mail-bridge-docker) runs it in a container instead. That is a way to get a bridge, not a way to put one somewhere else: it decrypts your mail wherever it runs, so a bridge on another machine means your mail is decrypted on that machine. The section above still applies, and the container's own readme says the same.
94
100
  - **Node.js 24 or newer.**
95
101
  - **The Bridge password**, which is not your Proton account password. The Bridge generates one per account. You find it in the Bridge application under the account, or in a terminal via `protonmail-bridge --cli` and then `info`.
96
102
 
@@ -198,8 +204,12 @@ Then it asks where the password should be kept. All four options are supported a
198
204
 
199
205
  The interface probes the keyring at runtime rather than guessing from the operating system, because the same Linux with and without a graphical session is a different machine as far as a keyring is concerned. An option that cannot work is shown greyed out with the actual reason.
200
206
 
207
+ On Linux the system keyring is the desktop's, GNOME Keyring or KWallet, reached over D-Bus. MCP clients usually start a server without the address of that bus, so the server looks for it in the usual place itself. Where there is no desktop session, on a server or in a container, the keyring library uses the kernel's keyring instead. That one keeps the password in memory only: it is gone after a restart, and after three days without use by default. The sign-in page says so when that is the case.
208
+
201
209
  If you pick the encrypted file, every later start shows an unlock page asking for that master password alone. Forget it and nothing anywhere can recover the file; the page offers to throw it away so you can sign in afresh.
202
210
 
211
+ **Signing in again replaces what was stored.** The password then lives only where you chose last, and every other place is emptied. **Signing out empties all four.** If one of them cannot be emptied, a file the server may not delete for instance, the page says which and how to remove it by hand, because until then the next start signs in with it again.
212
+
203
213
  #### Without a browser
204
214
 
205
215
  Environment variables still work and take precedence over anything stored:
@@ -241,13 +251,17 @@ Use an absolute path; `~` is not expanded by every client. The setup script prin
241
251
  Without any client, by speaking the protocol directly:
242
252
 
243
253
  ```bash
244
- printf '%s\n' \
245
- '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"check","version":"1"}}}' \
246
- '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
247
- '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_folders","arguments":{"kind":"system"}}}' \
248
- | node dist/server.js
254
+ {
255
+ printf '%s\n' \
256
+ '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"check","version":"1"}}}' \
257
+ '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
258
+ '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_folders","arguments":{"kind":"system"}}}'
259
+ sleep 5
260
+ } | node dist/server.js
249
261
  ```
250
262
 
263
+ The `sleep` keeps the input open while the answer is on its way. A client signals that it is leaving by closing the server's input, and from that moment no further answer is written, so a plain `printf ... |` only ever gets the reply to `initialize`.
264
+
251
265
  You should see your system mailboxes. If instead you get a message saying the Bridge is probably not running, start and unlock the Bridge and try again. The server explains what to do in its error messages rather than printing error codes.
252
266
 
253
267
  ## Security
@@ -259,7 +273,7 @@ The content of someone else's email is text written by strangers, and it is hand
259
273
  - **Sending always requires your confirmation**, enforced in the server rather than in a system prompt. There is no switch to turn it off, and a client that cannot ask the question cannot send.
260
274
  - **There will be no permanent deletion**, and no tools for filters, forwarding, account or key settings. A hijacked session must not be able to leave behind lasting access.
261
275
  - **HTML is never passed through raw** and external content is never fetched. Tracking pixels stay ineffective.
262
- - **No message ever touches your disk.** No cache, no index, no copies. Anything this server wrote down would be your mail in plain text, outside the encryption you pay Proton for.
276
+ - **Your mail is not kept on your disk.** No cache, no index, no copies. Anything this server wrote down would be your mail in plain text, outside the encryption you pay Proton for. The one exception is an attachment you have the assistant save, into a directory you chose, for an hour at most, see [Saved attachments](#saved-attachments).
263
277
 
264
278
  ### Writing to your mailbox
265
279
 
@@ -284,9 +298,11 @@ Formatting changes what a confirmation has to show, and that is the interesting
284
298
  - **Text a recipient can read that the body does not show.** Measured: an image's alt text never appears in the converted body, and mail clients block remote images by default, so the alt text is frequently what the recipient actually reads. That was a way past the confirmation, and it is closed.
285
299
  - **Every property beyond ordinary formatting**, when `extended` was used, with the ones that really put something out of sight marked as such.
286
300
 
287
- What no level permits is `style` blocks, `script`, event handlers, `data:` addresses and comments. Comments look inert and are not: Outlook runs conditional ones, so a `<style>` block inside a comment reaches those recipients as markup while the confirmation and the preview see a comment. Addresses are checked wherever they appear, a CSS `background: url(...)` included, and every one of them is listed on the preview page. The line runs between describing a document and running inside it or reaching out of it: a `<style>` in the quote of a reply restyles the answer written above it, and 66 percent of real formatted mail carries one. Attachments from files on this machine are deliberately not supported either: a path named by a model, read by the server and carried out by the next confirmation is not a feature, it is a way out for anything on your disk. Forwarding loses nothing all the same, because the original message travels along whole, embedded images included.
301
+ What no level permits is `style` blocks, `script`, event handlers, `data:` addresses and comments. Comments look inert and are not: Outlook runs conditional ones, so a `<style>` block inside a comment reaches those recipients as markup while the confirmation and the preview see a comment. Addresses are checked wherever they appear, a CSS `background: url(...)` included, and every one of them is listed on the preview page. The line runs between describing a document and running inside it or reaching out of it: a `<style>` in the quote of a reply restyles the answer written above it, and 66 percent of real formatted mail carries one. Attachments from files on this machine are not supported today: a path named by a model, read by the server and carried out by the next confirmation would be a way out for anything on your disk. [#17](https://github.com/RndmJoker/proton-mcp/issues/17) tracks a version that reads only from a directory you have set yourself, and stays off until you do. Forwarding loses nothing all the same, because the original message travels along whole, embedded images included.
302
+
303
+ A stored draft is sent exactly as it was stored, its files and a forwarded original included. Its markup is checked when the draft is written, not again when it is sent: once stored, the part somebody wrote and the quote below it can no longer be told apart, and checked again a formatted reply would fail on the `<style>` of its quote. Nothing is waved through unseen for that. The preview page lists every address, every hidden text and everything a newly written message could not contain, and the confirmation carries the same warning as `extended` whenever the draft holds more than `standard` would have let through. `update_draft` keeps a draft's files whatever happens to its body.
288
304
 
289
- One thing worth knowing about drafts: Proton rewrites the thread headers of anything it stores. A reply is built with `In-Reply-To` and `References`, and what comes back has neither, only Proton's own internal thread id. Threading a stored draft is therefore Proton's business rather than this server's.
305
+ One more thing worth knowing about drafts: Proton rewrites the thread headers of anything it stores. A reply is built with `In-Reply-To` and `References`, and what comes back has neither, only Proton's own internal thread id. Threading a stored draft is therefore Proton's business rather than this server's.
290
306
 
291
307
  Writes need a moment to settle. A move takes roughly fifteen seconds to reconcile with Proton, and until then the Bridge lists the message in both places, so the tools say so rather than reading back an intermediate state and calling it the result. Flags are the exception: those hold immediately.
292
308
 
@@ -297,12 +313,13 @@ Mail is text written by strangers, handed to a model that can call tools. A mess
297
313
  - **Nothing is sent without a person saying yes.** The first call never sends. It returns a question through your client naming the sender, every recipient separated into To, Cc and Bcc, and the subject. Only the second call, carrying your answer, sends.
298
314
  - **The question is short, and the message is somewhere with room.** It carries no part of the message itself; it links to a page in the local interface where you can read it as the recipient will see it, with every address in full. That split exists because the question used to grow with the message: 74 lines for a newsletter-shaped one, at which point the confirm button sat below the bottom of the dialog and nothing could be sent at all.
299
315
  - **Recipients are never summarised**, however many there are. Seeing three of eight would mean agreeing to a send to five strangers.
316
+ - **The address you confirm is the address the message goes to.** Every recipient is read back through the code that builds the envelope, and refused if it would come out as another address or as none. An address with a character outside ASCII is refused as well: letters from another script can spell a familiar domain, and the message would go to a different one that anyone can register. A domain that really is written with such letters can be given in its `xn--` form, which is then exactly what you confirm.
300
317
  - **The answer goes through your client, never through the browser.** That page has no confirm button and will not get one: the address of the interface reaches your assistant, so a control there could be operated by the thing it is supervising.
301
318
  - **There is no setting that turns the question off.** Not an environment variable, not an argument, not a mode.
302
319
  - **A client that cannot ask cannot send.** If your client does not support form elicitation, sending is refused and you are pointed at drafts instead. That is deliberately different from the sign-in prompt, which falls back to text: the worst outcome there is an inconvenience, and here it is a message that cannot be recalled. What counts as "can ask" is the capability your client declares, read from the request when the protocol revision carries it there and from the handshake otherwise.
303
320
  - **Your yes covers one specific message.** A fingerprint of the sender, every recipient, the subject and the body is sealed with an HMAC whose key exists only in the running process, and it travels with the question. On the way back the fingerprint is recomputed from what is being asked for now. If a single address was added in between, nothing is sent. A confirmation is also bound to the tool that asked, so one cannot be reused for another.
304
321
  - **Blind copies stay blind.** They travel in the envelope and never appear in the headers the recipients see. Verified against a real delivery.
305
- - **The Bridge password is protected on the way out too.** SMTP is verified against the same pinned certificate as IMAP, and STARTTLS is required rather than merely attempted.
322
+ - **The Bridge password is protected on the way out too.** IMAP and SMTP are both verified against the same pinned certificate, and on both STARTTLS is required rather than merely attempted. Something listening on the port that offers no encryption gets no password.
306
323
 
307
324
  Replying and forwarding exist as sending tools of their own, not just as drafts. The reason is measured: Proton rewrites the thread headers of anything it stores, so a reply written to a draft and sent later loses the chain, while a reply handed straight to SMTP keeps its `In-Reply-To` and stays in the conversation.
308
325
 
@@ -315,14 +332,45 @@ Only these, all under `~/.config/proton-mcp/` (on Windows `%USERPROFILE%\.config
315
332
  | File | When | What is in it |
316
333
  | :--- | :--- | :--- |
317
334
  | `known-certificate.json` | On the first connection | The Bridge's certificate and its fingerprint |
318
- | `settings.json` | When you change the ports in the interface | Two port numbers |
335
+ | `settings.json` | When you change the ports or dismiss the notice in the interface | The two Bridge ports, and whether the notice that this is not an official Proton tool was dismissed |
319
336
  | `credentials.enc` | Only if you chose the encrypted file | Your Bridge password, encrypted with your master password |
320
- | `env` | Only if you put it there yourself | Your Bridge password in plain text |
337
+ | `env` | Only if you chose the plain file, or put it there yourself | Your Bridge password in plain text |
338
+ | `saved-attachments/` | While attachments are saved | Which files this server saved, so it can delete exactly those again. No content |
321
339
 
322
340
  Choosing the system keyring puts the password where the operating system keeps your other passwords, and nothing of it in a file. Choosing "this session only" writes nothing at all.
323
341
 
324
342
  **No mail, no subjects, no sender addresses, no folder names, no search terms.** The activity list in the interface records tool names and timings, in memory only, and is gone when the server stops.
325
343
 
344
+ ### Saved attachments
345
+
346
+ `save_attachment` writes an attachment to your disk so that the assistant can open it, a PDF or a spreadsheet for instance. That is your mail decrypted, so it is bounded on every side:
347
+
348
+ - **Off until you name a directory** in `PROTON_MCP_ATTACHMENT_DIR`, and only there or in a folder inside it. The tool is still listed, and without the directory its answer says what to set. The variable is read from the environment only; the web interface cannot set it, because an assistant can reach that page.
349
+ - **Nothing outside it.** A folder is checked after it is resolved; `..` and a symbolic link on the way are refused.
350
+ - **The sender's file name is reduced to a plain one**, without path separators, control or formatting characters, a leading dot or a device name Windows reserves.
351
+ - **An existing file is never replaced**, a link in its place is never followed, and every file is readable by your account alone.
352
+ - **Gone within the hour.** A saved file is deleted one hour after saving and when the server stops. A server that was killed leaves its files to the next one that starts. The assistant is told so, and copies a file it needs for longer.
353
+ - **Only what it saved.** The server records which files it wrote and deletes a file only while it is still that file, so whatever else is in the directory is never touched. A folder it created for a file goes again once it is empty; a folder that was there before stays. The one gap: a folder deleted and made again under the same name can be taken for the one it created, when the file system hands out the same inode again, and then goes too if it is empty.
354
+ - **At most 25 MB**, which is what Proton accepts per message anyway.
355
+
356
+ To switch it on, add the variable to the server's entry in your client's configuration:
357
+
358
+ ```json
359
+ {
360
+ "mcpServers": {
361
+ "proton": {
362
+ "command": "node",
363
+ "args": ["/absolute/path/to/proton-mcp/dist/server.js"],
364
+ "env": { "PROTON_MCP_ATTACHMENT_DIR": "/absolute/path/to/a/directory" }
365
+ }
366
+ }
367
+ }
368
+ ```
369
+
370
+ The directory has to exist; it is not created for you, so that a mistyped path does not become a new place for mail to land.
371
+
372
+ **Do not choose a folder that is synced to a cloud service.** A file saved there leaves your machine decrypted, and the server cannot tell such a folder from any other.
373
+
326
374
  ### The web interface
327
375
 
328
376
  It binds to `127.0.0.1` and there is no option to change that. It is not remote access and cannot be made into it. Four defences, each against a specific attack:
@@ -344,7 +392,7 @@ The names alone say something. A folder `Banking/Revolut` reveals your bank, `Ta
344
392
 
345
393
  The Bridge generates its own certificate and keeps it inside its encrypted vault rather than on disk, so it cannot be trusted in advance. Switching verification off would mean anything that manages to listen on the port gets your Bridge password.
346
394
 
347
- Instead the certificate is **pinned on first use**. The first connection records its fingerprint in `~/.config/proton-mcp/known-certificate.json` and reports it on stderr. The web interface shows it too, along with the date it was recorded. Every connection after that is verified against that one certificate, which is stricter than the public trust store: a certificate signed by a recognised authority would not do.
395
+ Instead the certificate is **pinned on first use**. The first connection records its fingerprint in `~/.config/proton-mcp/known-certificate.json` and reports it on stderr. The web interface shows it too, along with the date it was recorded. Every connection after that is verified against that one certificate, which is stricter than the public trust store: a certificate signed by a recognised authority would not do. The check happens in the connection's own handshake, before the password is sent. The certificate is read on a connection of its own only on first use and after a connection failed, to tell whether the certificate is what changed.
348
396
 
349
397
  If the certificate ever changes, the server refuses to connect and says so:
350
398
 
@@ -371,7 +419,7 @@ The one moment this cannot protect you is the very first connection, which is wh
371
419
  | Schemas | `zod` |
372
420
  | Tests | Vitest, `node` environment |
373
421
 
374
- Every dependency that ships is permissive: mostly MIT, with MIT-0 (`nodemailer`), BSD-2-Clause (the `htmlparser2` family), BSD-3-Clause (`deepmerge-ts`), ISC (`split2`) and one dual `MIT OR EUPL-1.1+` (`@zone-eu/mailsplit`). Development dependencies add Apache-2.0 and MPL-2.0.
422
+ Every dependency that ships is permissive: mostly MIT, with Apache-2.0 (`@modelcontextprotocol/server` and `@modelcontextprotocol/core`, which are moving from MIT and keep it for older contributions), MIT-0 (`nodemailer`), BSD-2-Clause (the `htmlparser2` family), BSD-3-Clause (`deepmerge-ts`), ISC (`split2`) and one dual `MIT OR EUPL-1.1+` (`@zone-eu/mailsplit`). Development dependencies add MPL-2.0.
375
423
 
376
424
  ```bash
377
425
  npm run build # compile into dist/
@@ -390,7 +438,7 @@ src/
390
438
  ├── bridge/ connection handling, certificate pinning, error translation
391
439
  ├── credentials/ the four places a password can be kept, and the runtime probe
392
440
  ├── mail/ listing, reading, searching, identifiers, attachments
393
- ├── mime/ parsing, HTML to text, budgeting
441
+ ├── mime/ parsing, HTML to text, budgeting, the parts of a stored draft
394
442
  ├── tools/ the MCP tools and their output formatting
395
443
  ├── web/ the local interface and its security layer
396
444
  ├── activity.ts what is running and what ran, in memory only
@@ -409,7 +457,7 @@ The CI in `.github/workflows/ci.yml` runs the tests, the type check, the build,
409
457
 
410
458
  ```bash
411
459
  npm test
412
- npx tsc --noEmit
460
+ npm run typecheck
413
461
  npm run build
414
462
  npm audit --omit=dev
415
463
  ```
@@ -15,7 +15,15 @@
15
15
  * the certificate out. Verified against Bridge 03.25.00: checkServerIdentity is
16
16
  * never invoked while verification is off, and the certificate is not attached
17
17
  * to the verification error either.
18
+ *
19
+ * That probe runs only when it tells something: on first use, to record the
20
+ * certificate, and after a connection failed, to say whether the certificate
21
+ * is what changed. Every other connection is verified by its own handshake
22
+ * against the pin alone, which fails before any credentials are sent. Up to
23
+ * 0.4.11 every connection and every send began with a probe, and the Bridge
24
+ * logged each one as "Cannot upgrade connection: EOF". See pinFor.
18
25
  */
26
+ import { BridgeError } from './errors.js';
19
27
  /** What is known about a pinned certificate. */
20
28
  export interface PinnedCertificate {
21
29
  host: string;
@@ -39,7 +47,9 @@ export declare function toPem(der: Buffer): string;
39
47
  *
40
48
  * Deliberately minimal: it reads the greeting, sends STARTTLS, waits for the OK
41
49
  * and upgrades. It does not log in, so no credentials are involved at this
42
- * point.
50
+ * point. It leaves with LOGOUT and closes rather than destroys the socket: up to
51
+ * 0.4.11 it destroyed it right after the handshake, and the Bridge logged every
52
+ * probe as a failed connection.
43
53
  */
44
54
  export declare function fetchCertificate(host: string, port: number, timeoutMs?: number): Promise<{
45
55
  fingerprint256: string;
@@ -73,3 +83,25 @@ export interface EnsureOptions {
73
83
  * open to a machine-in-the-middle. Every later connection is pinned.
74
84
  */
75
85
  export declare function ensurePinned(host: string, port: number, options?: EnsureOptions): Promise<PinnedCertificate>;
86
+ /**
87
+ * The certificate a connection is to be verified against, probing only on
88
+ * first use.
89
+ *
90
+ * Once a certificate is pinned, a probe before every connection adds nothing:
91
+ * the connection is verified against the pin alone, `rejectUnauthorized` with
92
+ * the pin as the only authority, and a different certificate fails its
93
+ * handshake before any credentials are sent. imapflow sends LOGIN only after
94
+ * STARTTLS, and nodemailer with requireTLS sends AUTH only after it.
95
+ */
96
+ export declare function pinFor(host: string, port: number, options?: EnsureOptions): Promise<PinnedCertificate>;
97
+ /**
98
+ * After a connection failed: whether the certificate is what changed.
99
+ *
100
+ * A failed handshake looks like any other failure from the outside, so the
101
+ * certificate is fetched and compared now, the one moment a probe is worth it.
102
+ * Returns the explanation with both fingerprints when it changed, and nothing
103
+ * otherwise, so the caller reports the failure it had. A probe that fails as
104
+ * well says nothing: a Bridge that is not running is the likelier story, and
105
+ * the original failure tells it.
106
+ */
107
+ export declare function certificateChanged(host: string, port: number, pinned: PinnedCertificate, options?: Pick<EnsureOptions, 'path' | 'fetch'>): Promise<BridgeError | undefined>;
@@ -15,6 +15,13 @@
15
15
  * the certificate out. Verified against Bridge 03.25.00: checkServerIdentity is
16
16
  * never invoked while verification is off, and the certificate is not attached
17
17
  * to the verification error either.
18
+ *
19
+ * That probe runs only when it tells something: on first use, to record the
20
+ * certificate, and after a connection failed, to say whether the certificate
21
+ * is what changed. Every other connection is verified by its own handshake
22
+ * against the pin alone, which fails before any credentials are sent. Up to
23
+ * 0.4.11 every connection and every send began with a probe, and the Bridge
24
+ * logged each one as "Cannot upgrade connection: EOF". See pinFor.
18
25
  */
19
26
  import { connect as netConnect } from 'node:net';
20
27
  import { connect as tlsConnect } from 'node:tls';
@@ -34,25 +41,59 @@ export function toPem(der) {
34
41
  const lines = base64.match(/.{1,64}/g) ?? [];
35
42
  return `-----BEGIN CERTIFICATE-----\n${lines.join('\n')}\n-----END CERTIFICATE-----\n`;
36
43
  }
44
+ /**
45
+ * Ends the session the way an IMAP session ends, and calls `done` once the
46
+ * Bridge has answered, has closed, or has taken too long.
47
+ */
48
+ function logout(secure, done, timeoutMs = 2_000) {
49
+ let reply = '';
50
+ const timer = setTimeout(done, timeoutMs);
51
+ const end = () => {
52
+ clearTimeout(timer);
53
+ done();
54
+ };
55
+ secure.setEncoding('utf8');
56
+ secure.on('data', (chunk) => {
57
+ reply += chunk;
58
+ if (/^A2 /m.test(reply))
59
+ end();
60
+ });
61
+ secure.once('end', end);
62
+ secure.once('close', end);
63
+ secure.write('A2 LOGOUT\r\n');
64
+ }
37
65
  /**
38
66
  * Fetches the certificate by doing the STARTTLS dance manually.
39
67
  *
40
68
  * Deliberately minimal: it reads the greeting, sends STARTTLS, waits for the OK
41
69
  * and upgrades. It does not log in, so no credentials are involved at this
42
- * point.
70
+ * point. It leaves with LOGOUT and closes rather than destroys the socket: up to
71
+ * 0.4.11 it destroyed it right after the handshake, and the Bridge logged every
72
+ * probe as a failed connection.
43
73
  */
44
74
  export function fetchCertificate(host, port, timeoutMs = 10_000) {
45
75
  return new Promise((resolve, reject) => {
46
76
  const socket = netConnect({ host, port });
77
+ let secure;
47
78
  let settled = false;
48
79
  let stage = 'greeting';
49
80
  let buffer = '';
50
- const finish = (error, value) => {
81
+ const finish = (error, value, graceful = false) => {
51
82
  if (settled)
52
83
  return;
53
84
  settled = true;
54
85
  clearTimeout(timer);
55
- socket.destroy();
86
+ if (graceful && secure) {
87
+ // close_notify and a FIN instead of a reset. The Bridge closes its side
88
+ // after BYE; should it not, the socket goes after a second regardless.
89
+ const open = secure;
90
+ open.end();
91
+ setTimeout(() => open.destroy(), 1_000).unref();
92
+ }
93
+ else {
94
+ secure?.destroy();
95
+ socket.destroy();
96
+ }
56
97
  if (error)
57
98
  reject(error);
58
99
  else if (value)
@@ -89,13 +130,13 @@ export function fetchCertificate(host, port, timeoutMs = 10_000) {
89
130
  // Encoding was set for the plaintext part, and it has to go before the
90
131
  // socket is handed to the TLS layer.
91
132
  socket.setEncoding(null);
92
- const secure = tlsConnect({
133
+ const upgraded = tlsConnect({
93
134
  socket,
94
135
  // The point of this connection is to look at the certificate, so it
95
- // cannot be validated beforehand. Nothing is sent over it.
136
+ // cannot be validated beforehand. Nothing but LOGOUT is sent over it.
96
137
  rejectUnauthorized: false,
97
138
  }, () => {
98
- const cert = secure.getPeerCertificate();
139
+ const cert = upgraded.getPeerCertificate();
99
140
  if (!cert || !cert.raw) {
100
141
  finish(new BridgeError(`${host}:${port} presented no certificate.`));
101
142
  return;
@@ -109,10 +150,10 @@ export function fetchCertificate(host, port, timeoutMs = 10_000) {
109
150
  subject: Array.isArray(cn) ? cn.join(', ') : (cn ?? JSON.stringify(cert.subject ?? {})),
110
151
  validTo: cert.valid_to ?? '',
111
152
  };
112
- secure.destroy();
113
- finish(undefined, value);
153
+ logout(upgraded, () => finish(undefined, value, true));
114
154
  });
115
- secure.on('error', (error) => finish(error));
155
+ secure = upgraded;
156
+ upgraded.on('error', (error) => finish(error));
116
157
  });
117
158
  });
118
159
  }
@@ -173,4 +214,36 @@ export async function ensurePinned(host, port, options = {}) {
173
214
  }
174
215
  return pinned;
175
216
  }
217
+ /**
218
+ * The certificate a connection is to be verified against, probing only on
219
+ * first use.
220
+ *
221
+ * Once a certificate is pinned, a probe before every connection adds nothing:
222
+ * the connection is verified against the pin alone, `rejectUnauthorized` with
223
+ * the pin as the only authority, and a different certificate fails its
224
+ * handshake before any credentials are sent. imapflow sends LOGIN only after
225
+ * STARTTLS, and nodemailer with requireTLS sends AUTH only after it.
226
+ */
227
+ export async function pinFor(host, port, options = {}) {
228
+ const pinned = loadPinned(options.path ?? pinPath());
229
+ if (pinned && pinned.host === host && pinned.port === port)
230
+ return pinned;
231
+ return ensurePinned(host, port, options);
232
+ }
233
+ /**
234
+ * After a connection failed: whether the certificate is what changed.
235
+ *
236
+ * A failed handshake looks like any other failure from the outside, so the
237
+ * certificate is fetched and compared now, the one moment a probe is worth it.
238
+ * Returns the explanation with both fingerprints when it changed, and nothing
239
+ * otherwise, so the caller reports the failure it had. A probe that fails as
240
+ * well says nothing: a Bridge that is not running is the likelier story, and
241
+ * the original failure tells it.
242
+ */
243
+ export async function certificateChanged(host, port, pinned, options = {}) {
244
+ const actual = await (options.fetch ?? fetchCertificate)(host, port).catch(() => undefined);
245
+ if (!actual || actual.fingerprint256 === pinned.fingerprint256)
246
+ return undefined;
247
+ return new BridgeError(mismatchMessage(pinned, actual, options.path ?? pinPath()));
248
+ }
176
249
  //# sourceMappingURL=certificate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"certificate.js","sourceRoot":"","sources":["../../src/bridge/certificate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"certificate.js","sourceRoot":"","sources":["../../src/bridge/certificate.ts"],"names":[],"mappings":"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"}
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import { ImapFlow } from 'imapflow';
10
10
  import { explainError, BridgeError } from './errors.js';
11
- import { ensurePinned } from './certificate.js';
11
+ import { certificateChanged, pinFor } from './certificate.js';
12
12
  /** Thrown when a tool is used before anyone has signed in. */
13
13
  export class NotSignedInError extends BridgeError {
14
14
  name = 'NotSignedInError';
@@ -91,12 +91,21 @@ export class Connection {
91
91
  'Proton Mail Bridge only listens on 127.0.0.1, so this only makes sense if you ' +
92
92
  'deliberately put a tunnel in front of it. Otherwise correct BRIDGE_HOST.');
93
93
  }
94
- // Pin the certificate before handing over any credentials. On first use this
95
- // records what it finds, afterwards it verifies. A changed certificate stops
96
- // us here rather than after the password has gone out.
97
- const pinned = await ensurePinned(this.config.host, this.config.imapPort, {
94
+ // The certificate to verify against. On first use this reads and records
95
+ // it, and that read is the first thing to reach the Bridge, so a Bridge
96
+ // that is not running shows up here as a bare socket error. Measured before
97
+ // it was translated: "Unexpected error while listing mailboxes: Error:
98
+ // connect ECONNREFUSED", where the explanation below was meant to be.
99
+ //
100
+ // Once one is pinned, nothing is read here: the handshake below verifies
101
+ // against the pin and fails before the password goes out, see pinFor.
102
+ const pinned = await pinFor(this.config.host, this.config.imapPort, {
98
103
  onFirstUse: (entry) => this.notify(`recorded the Bridge certificate on first use, fingerprint ${entry.fingerprint256}. ` +
99
104
  'Further connections are verified against it.'),
105
+ }).catch((error) => {
106
+ throw error instanceof BridgeError
107
+ ? error
108
+ : explainError(error, this.config.host, this.config.imapPort);
100
109
  });
101
110
  const client = new ImapFlow({
102
111
  host: this.config.host,
@@ -104,6 +113,13 @@ export class Connection {
104
113
  // The Bridge expects a plaintext connection upgraded via STARTTLS,
105
114
  // not a direct TLS handshake.
106
115
  secure: false,
116
+ // Required, not "if offered". Left to its default, imapflow logs in over
117
+ // the unencrypted connection when the greeting does not offer STARTTLS,
118
+ // and with logging off nobody would see the warning. Up to 0.4.11 the
119
+ // certificate probe in front of every connection happened to prevent
120
+ // that; since the probe runs only on first use, this is what does. The
121
+ // same as requireTLS on the SMTP side.
122
+ doSTARTTLS: true,
107
123
  auth: { user: credentials.user, pass: credentials.pass },
108
124
  tls: {
109
125
  // Verified against exactly one certificate: the pinned one. This is
@@ -131,7 +147,10 @@ export class Connection {
131
147
  await client.connect();
132
148
  }
133
149
  catch (error) {
134
- throw explainError(error, this.config.host, this.config.imapPort);
150
+ // A certificate other than the pinned one fails the handshake, and from
151
+ // here that looks like any other failure. Only now is a probe worth it.
152
+ const changed = await certificateChanged(this.config.host, this.config.imapPort, pinned);
153
+ throw changed ?? explainError(error, this.config.host, this.config.imapPort);
135
154
  }
136
155
  this.#client = client;
137
156
  return client;
@@ -190,6 +209,12 @@ export class Connection {
190
209
  */
191
210
  async status(path) {
192
211
  const st = await this.#withRetry((client) => client.status(path, { messages: true, unseen: true, uidValidity: true, uidNext: true }));
212
+ // imapflow answers a STATUS it could not complete with false rather than
213
+ // an error. Read as zero messages, the mailbox would look empty.
214
+ if (!st) {
215
+ throw new BridgeError(`The Bridge did not report the state of "${path}", so it cannot be said how many messages ` +
216
+ 'it holds. Try again, and if it fails again, check that the Bridge is running and unlocked.');
217
+ }
193
218
  return {
194
219
  path,
195
220
  messages: st.messages ?? 0,
@@ -1 +1 @@
1
- {"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/bridge/connection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/bridge/connection.ts"],"names":[],"mappings":"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"}
@@ -26,6 +26,14 @@ export declare class BridgeError extends Error {
26
26
  readonly remedy: BridgeRemedy;
27
27
  constructor(message: string, remedy?: BridgeRemedy, options?: ErrorOptions);
28
28
  }
29
+ /**
30
+ * Whether the connection itself failed, rather than something said over it.
31
+ *
32
+ * Sending learns this only from nodemailer, which relabels the system error,
33
+ * and since the certificate is no longer fetched before every send, a send is
34
+ * where a Bridge that is not running shows up first.
35
+ */
36
+ export declare function isConnectionFailure(error: unknown): boolean;
29
37
  /**
30
38
  * Builds an understandable message from an arbitrary failure.
31
39
  *