stalwart-mail-mcp 2.2.0
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.
- package/LICENSE +21 -0
- package/README.cs.md +226 -0
- package/README.md +224 -0
- package/THIRD-PARTY-NOTICES.md +17 -0
- package/dist/index.cjs +100572 -0
- package/docs/mala-infrastruktura.md +149 -0
- package/docs/publishing.md +86 -0
- package/docs/small-infrastructure.md +150 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Petr Šrámek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.cs.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# Stalwart Mail MCP
|
|
2
|
+
|
|
3
|
+
*[English](README.md)*
|
|
4
|
+
|
|
5
|
+
MCP server, díky kterému Claude Desktop (a jakýkoli MCP klient přes stdio) pracuje se schránkou
|
|
6
|
+
na vlastním poštovním serveru [Stalwart](https://stalw.art): hledá a čte poštu včetně příloh
|
|
7
|
+
a skenů, odpovídá ve vlákně, odesílá, zakládá koncepty a hledá nebo přidává kontakty.
|
|
8
|
+
|
|
9
|
+
Se serverem mluví protokolem JMAP a přihlašuje se účtem schránky. Na server se nic neinstaluje.
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
Claude Desktop ──stdio──▶ dist/index.cjs (Node, tento MCP server)
|
|
13
|
+
│ HTTPS · JMAP (RFC 8620 / 8621 / 9610)
|
|
14
|
+
▼
|
|
15
|
+
https://mail.example.com/jmap (reverzní proxy → Stalwart)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Jak ho zapojit do malé vlastní infrastruktury — reverzní proxy, co pustit ven, sdílené
|
|
19
|
+
schránky, vlastní balíček pro rodinu nebo tým — popisuje
|
|
20
|
+
[docs/mala-infrastruktura.md](docs/mala-infrastruktura.md).
|
|
21
|
+
|
|
22
|
+
## Nástroje
|
|
23
|
+
|
|
24
|
+
Názvy mají předponu, výchozí je `mail_` (vlastní balíček si ji může změnit).
|
|
25
|
+
|
|
26
|
+
| Nástroj | Co dělá |
|
|
27
|
+
|---|---|
|
|
28
|
+
| `mail_list_mailboxes` | účty (vlastní + sdílené), složky s počty, povolení odesílatelé, adresáře |
|
|
29
|
+
| `mail_search_emails` | fulltext / od / komu / předmět / složka / datum / nepřečtené / s přílohou, nebo celé vlákno |
|
|
30
|
+
| `mail_get_email` | celá zpráva podle id (HTML → text) s číslovaným seznamem příloh |
|
|
31
|
+
| `mail_get_attachment` | obsah přílohy: text, PDF po stranách, OCR skenů a fotek dokumentů, obrázky; soubor uloží na disk |
|
|
32
|
+
| `mail_send_email` | odeslat nový mail nebo odpověď (`in_reply_to_id`, `reply_all`), přílohy z disku |
|
|
33
|
+
| `mail_create_draft` | totéž, ale jen uložit do Konceptů |
|
|
34
|
+
| `mail_send_draft` / `mail_delete_draft` | odeslat / smazat koncept podle id |
|
|
35
|
+
| `mail_search_contacts` | adresáře všech účtů a navíc odesílatelé a adresáti z historie pošty |
|
|
36
|
+
| `mail_add_contact` | nový kontakt (vlastní nebo sdílený adresář) |
|
|
37
|
+
|
|
38
|
+
Odeslání je okamžité a nejde vzít zpět, proto popisy nástrojů modelu říkají, že má posílat jen
|
|
39
|
+
na výslovný pokyn uživatele a jinak založit koncept.
|
|
40
|
+
|
|
41
|
+
## Instalace
|
|
42
|
+
|
|
43
|
+
### Claude Desktop (rozšíření)
|
|
44
|
+
|
|
45
|
+
Stáhni `stalwart-mail.mcpb` z
|
|
46
|
+
[posledního vydání](https://github.com/cybersmurf/stalwart-mail-mcp/releases/latest) a otevři
|
|
47
|
+
ho — Claude Desktop nabídne instalaci. Nebo si ho sestav:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm install
|
|
51
|
+
./pack.sh # → stalwart-mail.mcpb
|
|
52
|
+
open stalwart-mail.mcpb # Claude Desktop → Install
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Vyplň adresu serveru, e-mail a heslo schránky. Volitelně jazyk a klíč Mistral API pro OCR.
|
|
56
|
+
Heslo se ukládá do klíčenky systému.
|
|
57
|
+
|
|
58
|
+
### Jakýkoli MCP klient (stdio)
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install && npm run build
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"mcpServers": {
|
|
67
|
+
"stalwart-mail": {
|
|
68
|
+
"command": "node",
|
|
69
|
+
"args": ["/cesta/k/stalwart-mail-mcp/dist/index.cjs"],
|
|
70
|
+
"env": {
|
|
71
|
+
"STALWART_URL": "https://mail.example.com",
|
|
72
|
+
"STALWART_USER": "jana@example.com",
|
|
73
|
+
"STALWART_PASSWORD": "…"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Claude Code: `claude mcp add stalwart-mail --env STALWART_URL=https://mail.example.com --env STALWART_USER=jana@example.com --env STALWART_PASSWORD=… -- node /cesta/k/stalwart-mail-mcp/dist/index.cjs`
|
|
81
|
+
|
|
82
|
+
## Nastavení
|
|
83
|
+
|
|
84
|
+
| Proměnná | Význam |
|
|
85
|
+
|---|---|
|
|
86
|
+
| `STALWART_URL` | veřejná adresa serveru, např. `https://mail.example.com` (povinné) |
|
|
87
|
+
| `STALWART_USER` | schránka, kterou se přihlašuješ (povinné) |
|
|
88
|
+
| `STALWART_PASSWORD` | heslo schránky nebo heslo aplikace — posílá se jako Basic auth |
|
|
89
|
+
| `STALWART_TOKEN` | přístupový token OAuth místo hesla — posílá se jako Bearer |
|
|
90
|
+
| `MAIL_LANG` | `auto` (výchozí: jazyk počítače, angličtina, když ho neumíme) nebo kód jazyka |
|
|
91
|
+
| `MAIL_TOOL_PREFIX` | předpona názvů nástrojů, výchozí `mail` |
|
|
92
|
+
| `MAIL_BRAND` | zobrazovaný název serveru, výchozí `Stalwart Mail` |
|
|
93
|
+
| `MAIL_DOWNLOAD_DIR` | kam se ukládají přílohy, výchozí `~/Downloads/Mail-Attachments` |
|
|
94
|
+
| `MAIL_TIMEZONE` | časové pásmo (IANA) pro data ve výstupu, výchozí pásmo počítače |
|
|
95
|
+
| `MAIL_OCR_PROVIDER`, `MAIL_OCR_API_KEY`, `MAIL_OCR_MODEL`, `MAIL_OCR_BASE_URL` | kdo čte skeny — viz [Poskytovatelé OCR](#poskytovatelé-ocr) |
|
|
96
|
+
| `MISTRAL_API_KEY` | zkratka: když je nastavený jen tenhle, skeny jdou do Mistral OCR |
|
|
97
|
+
| `MAIL_ALLOW_SEND` | `false` odebere `send_email` a `send_draft` |
|
|
98
|
+
| `MAIL_ALLOW_DRAFTS` | `false` odebere `create_draft` a `delete_draft` |
|
|
99
|
+
| `MAIL_ALLOW_CONTACT_EDIT` | `false` odebere `add_contact` |
|
|
100
|
+
| `MAIL_ALLOW_ATTACHMENTS` | `false` odebere `get_attachment` |
|
|
101
|
+
| `MAIL_SAVE_ATTACHMENTS` | `false` = otevřené přílohy se jen přečtou, na disk se nic nezapíše |
|
|
102
|
+
|
|
103
|
+
## Co smí dělat
|
|
104
|
+
|
|
105
|
+
Každá schopnost je přepínač v nastavení rozšíření (nebo proměnná výše), ve výchozím stavu je
|
|
106
|
+
vše zapnuté. Vypnutá schopnost se **jako nástroj vůbec nenabídne**, takže platí bez ohledu na
|
|
107
|
+
to, co si pamatují schvalovací dotazy klienta:
|
|
108
|
+
|
|
109
|
+
- vypnuté odesílání → schránka, kterou Claude čte a píše do ní koncepty, ale nikdy z ní neodešle;
|
|
110
|
+
- vypnuté odesílání, koncepty i úpravy kontaktů → schránka jen pro čtení;
|
|
111
|
+
- vypnuté ukládání příloh → `get_attachment` čte soubor z dočasné kopie a je označený jako
|
|
112
|
+
nástroj jen pro čtení; se zapnutým ukládáním zapisuje do složky stahování a je označený jako
|
|
113
|
+
zapisující, s čímž klienti mohou při schvalování zacházet jinak.
|
|
114
|
+
|
|
115
|
+
Samotné schvalování („povolit jednou / povolit vždy“) patří klientovi, ne tomuto serveru.
|
|
116
|
+
V Claude Desktop se nastavuje po nástrojích v nastavení rozšíření; po aktualizaci, která změní
|
|
117
|
+
definici nástroje, se klient může zeptat znovu.
|
|
118
|
+
|
|
119
|
+
## Přílohy a OCR
|
|
120
|
+
|
|
121
|
+
`mail_get_attachment` stáhne soubor a vrátí to, co model přečte:
|
|
122
|
+
|
|
123
|
+
- textové soubory jako text, HTML převedené na text;
|
|
124
|
+
- PDF jako text po stranách (u dlouhých `page_from` / `page_to`);
|
|
125
|
+
- strany PDF bez textové vrstvy (skeny) a fotky jdou ke zvolenému **poskytovateli OCR** —
|
|
126
|
+
výsledkem je markdown včetně tabulek a takové strany jsou označené `(OCR)`. U smíšeného PDF
|
|
127
|
+
se posílají jen naskenované strany;
|
|
128
|
+
- obrázky se vrací jako obrázky; cokoli nad ~600 kB nebo v HEIC se na macOS zmenší (`sips`);
|
|
129
|
+
- ostatní typy (docx, xlsx, zip…) se jen uloží a vrátí se cesta.
|
|
130
|
+
|
|
131
|
+
Bez poskytovatele nebo s `ocr: false` se sken vrátí jako obrázek 1. strany (macOS)
|
|
132
|
+
s poznámkou. OCR je jediná věc, která z tohoto serveru posílá obsah jinam než na tvůj poštovní
|
|
133
|
+
server — ke zvolenému poskytovateli, nebo s lokálním modelem vůbec nikam.
|
|
134
|
+
|
|
135
|
+
### Poskytovatelé OCR
|
|
136
|
+
|
|
137
|
+
| `MAIL_OCR_PROVIDER` | Co to je | Potřebuje | Čte PDF |
|
|
138
|
+
|---|---|---|---|
|
|
139
|
+
| `auto` (výchozí) | Mistral, když je nastavený `MISTRAL_API_KEY`; vlastní server, když je zadaná adresa a model; jinak vypnuto | — | — |
|
|
140
|
+
| `mistral` | Mistral OCR (`mistral-ocr-latest`) | klíč | přímo |
|
|
141
|
+
| `anthropic` | Claude přes oficiální SDK (výchozí model `claude-opus-5-5`) | klíč | přímo |
|
|
142
|
+
| `openai`, `openrouter`, `gemini` | hostovaná API kompatibilní s OpenAI (chat s obrázky) | klíč + model | obrázky stran |
|
|
143
|
+
| `ollama`, `lmstudio` | lokální modely na `localhost` | model | obrázky stran |
|
|
144
|
+
| `custom` | jakýkoli jiný server kompatibilní s OpenAI | `MAIL_OCR_BASE_URL` + model | obrázky stran |
|
|
145
|
+
| `off` | bez OCR | — | — |
|
|
146
|
+
|
|
147
|
+
Volbu doplňují `MAIL_OCR_API_KEY`, `MAIL_OCR_MODEL` a `MAIL_OCR_BASE_URL`. Příklady:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
MAIL_OCR_PROVIDER=ollama MAIL_OCR_MODEL=llama3.2-vision # čistě lokálně
|
|
151
|
+
MAIL_OCR_PROVIDER=openrouter MAIL_OCR_API_KEY=… MAIL_OCR_MODEL=<model s viděním>
|
|
152
|
+
MAIL_OCR_PROVIDER=anthropic MAIL_OCR_API_KEY=…
|
|
153
|
+
MAIL_OCR_PROVIDER=custom MAIL_OCR_BASE_URL=http://nas.lan:8000/v1 MAIL_OCR_MODEL=…
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Poskytovatelé, kteří berou jen obrázky, dostanou každou naskenovanou stranu jako PNG vytažené
|
|
157
|
+
z PDF (samotný sken, zmenšený na 2000 px). Stranu, která není jeden velký obrázek, jim předat
|
|
158
|
+
nejde a nahlásí se jako nepřečtená; Mistral a Anthropic čtou jakékoli PDF. Strany se posílají
|
|
159
|
+
po třech.
|
|
160
|
+
|
|
161
|
+
S čím počítat: lokální model může na hustou stranu potřebovat minutu i víc, což může
|
|
162
|
+
přesáhnout časový limit nástroje v klientu — dlouhé skeny čti po rozsazích stran. Obecné
|
|
163
|
+
modely s viděním přepisují dobře, ale jako každé OCR umí v tabulkách s grafikou posunout
|
|
164
|
+
buňky; `preview: true` přidá obrázek strany, aby si to model mohl zkontrolovat. U `anthropic`
|
|
165
|
+
se odmítnutý požadavek na aktuálních modelech Claude zopakuje na serveru na záložním modelu
|
|
166
|
+
(`fallbacks: "default"`).
|
|
167
|
+
|
|
168
|
+
`node test/live-ocr.mjs` pustí poskytovatele nastaveného v prostředí proti naskenovanému
|
|
169
|
+
testovacímu souboru (nebo tvému vlastnímu) a vypíše výsledek.
|
|
170
|
+
|
|
171
|
+
## Jazyky
|
|
172
|
+
|
|
173
|
+
Názvy a popisy nástrojů, výstupy i chybové hlášky jsou lokalizované. Angličtina je zdroj,
|
|
174
|
+
čeština je psaná ručně a němčina, španělština, francouzština, italština, nizozemština,
|
|
175
|
+
polština, portugalština a slovenština jsou **strojové překlady**, které zatím žádný rodilý
|
|
176
|
+
mluvčí nekontroloval — opravy jsou vítané.
|
|
177
|
+
|
|
178
|
+
Jazyk se přidává nebo opravuje v `src/locales/<kód>.ts` (zkopíruj `en.ts`, zachovej
|
|
179
|
+
`{zástupné značky}` a zalomení řádků) a registruje se v `src/locales/index.ts`. Překlad může
|
|
180
|
+
být neúplný, chybějící texty se vezmou z angličtiny. `npm run test:offline` každý jazyk
|
|
181
|
+
porovná s anglickými klíči.
|
|
182
|
+
|
|
183
|
+
## Vlastní balíčky (předvolby)
|
|
184
|
+
|
|
185
|
+
Pro rodinu nebo tým jde vyrobit rozšíření, kde je adresa serveru předvyplněná a lidé zadají
|
|
186
|
+
jen e-mail a heslo. Předvolba je složka s vlastním `manifest.json` (a volitelně `icon.png`),
|
|
187
|
+
viz [presets/example](presets/example).
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
./pack.sh --preset /cesta/k/predvolbe # → /cesta/k/predvolbe/<name>.mcpb
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Manifest předvolby nastaví přes `env` `MAIL_TOOL_PREFIX`, `MAIL_BRAND`, `MAIL_LANG` nebo
|
|
194
|
+
`MAIL_DOWNLOAD_DIR` a položce `server_url` dá výchozí hodnotu. `name` předvolby neměň, aby
|
|
195
|
+
Claude Desktop bral nové sestavení jako aktualizaci.
|
|
196
|
+
|
|
197
|
+
## Testy
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
npm run test:offline # bez schránky: falešný JMAP + falešné OCR, skutečný server přes stdio
|
|
201
|
+
MISTRAL_API_KEY=… node test/offline.mjs --live-ocr # navíc pošle testovací soubory do skutečného OCR
|
|
202
|
+
STALWART_URL=… STALWART_USER=… STALWART_PASSWORD=… node test/smoke.mjs # skutečná schránka
|
|
203
|
+
STALWART_URL=… STALWART_USER=… STALWART_PASSWORD=… node test/smoke.mjs --send # navíc pošle mail sám sobě
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Offline test pokrývá přílohy, OCR, předponu nástrojů, výběr jazyka a úplnost překladů.
|
|
207
|
+
Kouřový test založí koncept a zase ho smaže; s `--send` po sobě nechá ve schránce jednu
|
|
208
|
+
testovací zprávu.
|
|
209
|
+
|
|
210
|
+
## Dobré vědět
|
|
211
|
+
|
|
212
|
+
- **Chybné heslo = ban IP** ve Stalwartu po několika pokusech. Server se přihlašuje až při
|
|
213
|
+
prvním volání nástroje, ne při startu, takže restarty klienta ban nevyrobí; opakované volání
|
|
214
|
+
se špatným heslem ano.
|
|
215
|
+
- Vzniklo pro Stalwart 0.16 a s ním se používá. Poštovní část je čisté RFC 8620/8621 a může
|
|
216
|
+
fungovat i s jinými JMAP servery, ale to není vyzkoušené; kontakty potřebují JMAP for
|
|
217
|
+
Contacts (RFC 9610).
|
|
218
|
+
- `Email/query` s `"inMailbox": null` Stalwart odmítne — filtr musí buď chybět, nebo mít id.
|
|
219
|
+
- Balíček je jeden soubor CommonJS (~3,8 MB, většinu dělá pdf.js z `unpdf`); přípona `.cjs`
|
|
220
|
+
je nutná, protože `package.json` má `"type": "module"`.
|
|
221
|
+
- Výsledek nástroje má v Claude Desktop strop kolem 1 MB, proto limit 600 kB pro vložené
|
|
222
|
+
obrázky.
|
|
223
|
+
|
|
224
|
+
## Licence
|
|
225
|
+
|
|
226
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Stalwart Mail MCP
|
|
2
|
+
|
|
3
|
+
*[Česky](README.cs.md)*
|
|
4
|
+
|
|
5
|
+
An MCP server that lets Claude Desktop (or any MCP client that speaks stdio) work with a mailbox
|
|
6
|
+
on your own [Stalwart](https://stalw.art) mail server: search and read mail including
|
|
7
|
+
attachments and scans, reply in a thread, send, keep drafts, and look up or add contacts.
|
|
8
|
+
|
|
9
|
+
It talks JMAP with the mailbox's own credentials. Nothing is installed on the server.
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
Claude Desktop ──stdio──▶ dist/index.cjs (Node, this MCP server)
|
|
13
|
+
│ HTTPS · JMAP (RFC 8620 / 8621 / 9610)
|
|
14
|
+
▼
|
|
15
|
+
https://mail.example.com/jmap (reverse proxy → Stalwart)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
How it fits into a small self-hosted setup — reverse proxy, what to expose, shared mailboxes,
|
|
19
|
+
branded builds for a family or a team — is described in
|
|
20
|
+
[docs/small-infrastructure.md](docs/small-infrastructure.md).
|
|
21
|
+
|
|
22
|
+
## Tools
|
|
23
|
+
|
|
24
|
+
Names carry a prefix, `mail_` by default (a branded build can change it).
|
|
25
|
+
|
|
26
|
+
| Tool | What it does |
|
|
27
|
+
|---|---|
|
|
28
|
+
| `mail_list_mailboxes` | accounts (own + shared), folders with counts, allowed senders, address books |
|
|
29
|
+
| `mail_search_emails` | full text / from / to / subject / folder / date / unread / has attachment, or a whole thread |
|
|
30
|
+
| `mail_get_email` | a whole message by id (HTML → text) with a numbered list of attachments |
|
|
31
|
+
| `mail_get_attachment` | an attachment's content: text, PDF page by page, OCR of scans and photographed documents, images; saves the file to disk |
|
|
32
|
+
| `mail_send_email` | send a new mail or a reply (`in_reply_to_id`, `reply_all`), attachments from disk |
|
|
33
|
+
| `mail_create_draft` | the same, but only saved to Drafts |
|
|
34
|
+
| `mail_send_draft` / `mail_delete_draft` | send / delete a draft by id |
|
|
35
|
+
| `mail_search_contacts` | address books of every account plus senders and recipients from the mail history |
|
|
36
|
+
| `mail_add_contact` | new contact (own or shared address book) |
|
|
37
|
+
|
|
38
|
+
Sending is immediate and cannot be undone, so the tool descriptions tell the model to send only
|
|
39
|
+
on the user's explicit instruction and to create a draft otherwise.
|
|
40
|
+
|
|
41
|
+
## Install
|
|
42
|
+
|
|
43
|
+
### Claude Desktop (extension)
|
|
44
|
+
|
|
45
|
+
Download `stalwart-mail.mcpb` from the
|
|
46
|
+
[latest release](https://github.com/cybersmurf/stalwart-mail-mcp/releases/latest) and open it —
|
|
47
|
+
Claude Desktop offers to install it. Or build it yourself:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm install
|
|
51
|
+
./pack.sh # → stalwart-mail.mcpb
|
|
52
|
+
open stalwart-mail.mcpb # Claude Desktop → Install
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Fill in the server address, the mailbox e-mail and password. Optional: the language and a
|
|
56
|
+
Mistral API key for OCR. The password is kept in the operating system's keychain.
|
|
57
|
+
|
|
58
|
+
### Any MCP client (stdio)
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install && npm run build
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"mcpServers": {
|
|
67
|
+
"stalwart-mail": {
|
|
68
|
+
"command": "node",
|
|
69
|
+
"args": ["/path/to/stalwart-mail-mcp/dist/index.cjs"],
|
|
70
|
+
"env": {
|
|
71
|
+
"STALWART_URL": "https://mail.example.com",
|
|
72
|
+
"STALWART_USER": "jane@example.com",
|
|
73
|
+
"STALWART_PASSWORD": "…"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Claude Code: `claude mcp add stalwart-mail --env STALWART_URL=https://mail.example.com --env STALWART_USER=jane@example.com --env STALWART_PASSWORD=… -- node /path/to/stalwart-mail-mcp/dist/index.cjs`
|
|
81
|
+
|
|
82
|
+
## Configuration
|
|
83
|
+
|
|
84
|
+
| Variable | Meaning |
|
|
85
|
+
|---|---|
|
|
86
|
+
| `STALWART_URL` | public address of the server, e.g. `https://mail.example.com` (required) |
|
|
87
|
+
| `STALWART_USER` | the mailbox you sign in as (required) |
|
|
88
|
+
| `STALWART_PASSWORD` | mailbox or app password — sent as Basic auth |
|
|
89
|
+
| `STALWART_TOKEN` | an OAuth access token instead of the password — sent as Bearer |
|
|
90
|
+
| `MAIL_LANG` | `auto` (default: the machine's language, English when unsupported) or a locale code |
|
|
91
|
+
| `MAIL_TOOL_PREFIX` | prefix of the tool names, default `mail` |
|
|
92
|
+
| `MAIL_BRAND` | display name of the server, default `Stalwart Mail` |
|
|
93
|
+
| `MAIL_DOWNLOAD_DIR` | where attachments are saved, default `~/Downloads/Mail-Attachments` |
|
|
94
|
+
| `MAIL_TIMEZONE` | IANA zone for dates in the output, default the machine's zone |
|
|
95
|
+
| `MAIL_OCR_PROVIDER`, `MAIL_OCR_API_KEY`, `MAIL_OCR_MODEL`, `MAIL_OCR_BASE_URL` | who reads scans — see [OCR providers](#ocr-providers) |
|
|
96
|
+
| `MISTRAL_API_KEY` | shortcut: with only this set, scans go to Mistral OCR |
|
|
97
|
+
| `MAIL_ALLOW_SEND` | `false` removes `send_email` and `send_draft` |
|
|
98
|
+
| `MAIL_ALLOW_DRAFTS` | `false` removes `create_draft` and `delete_draft` |
|
|
99
|
+
| `MAIL_ALLOW_CONTACT_EDIT` | `false` removes `add_contact` |
|
|
100
|
+
| `MAIL_ALLOW_ATTACHMENTS` | `false` removes `get_attachment` |
|
|
101
|
+
| `MAIL_SAVE_ATTACHMENTS` | `false` = opened attachments are only read, nothing is written to disk |
|
|
102
|
+
|
|
103
|
+
## What it is allowed to do
|
|
104
|
+
|
|
105
|
+
Every capability is a switch in the extension settings (or an env variable above), all on by
|
|
106
|
+
default. A capability that is off is **not offered as a tool at all**, so it holds regardless
|
|
107
|
+
of what the client's approval prompts remember:
|
|
108
|
+
|
|
109
|
+
- sending off → a mailbox Claude can read and draft in, but never send from;
|
|
110
|
+
- sending, drafts and contact edits off → a read-only mailbox;
|
|
111
|
+
- saving attachments off → `get_attachment` reads the file from a temporary copy and is
|
|
112
|
+
annotated read-only; with saving on it writes to the download folder and is annotated as a
|
|
113
|
+
writing tool, which clients may treat differently when asking for approval.
|
|
114
|
+
|
|
115
|
+
Approvals themselves ("allow once / always allow") belong to the client, not to this server.
|
|
116
|
+
In Claude Desktop they are set per tool in the extension's settings; a client may ask again
|
|
117
|
+
after an update that changes a tool's definition.
|
|
118
|
+
|
|
119
|
+
## Attachments and OCR
|
|
120
|
+
|
|
121
|
+
`mail_get_attachment` downloads the file and returns what the model can read:
|
|
122
|
+
|
|
123
|
+
- text files as text, HTML converted to text;
|
|
124
|
+
- PDFs as text page by page (`page_from` / `page_to` for long ones);
|
|
125
|
+
- PDF pages without a text layer (scans) and photos go to the **OCR provider** you choose —
|
|
126
|
+
the result is markdown including tables, and those pages are marked `(OCR)`. A mixed PDF
|
|
127
|
+
sends only its scanned pages;
|
|
128
|
+
- images are returned as images; anything above ~600 kB or in HEIC is downscaled on macOS
|
|
129
|
+
(`sips`);
|
|
130
|
+
- other types (docx, xlsx, zip…) are only saved, and the path is returned.
|
|
131
|
+
|
|
132
|
+
Without a provider, or with `ocr: false`, a scan comes back as an image of page 1 (macOS) with
|
|
133
|
+
a note. OCR is the only thing in this server that sends content anywhere besides your mail
|
|
134
|
+
server — to the provider you picked, or nowhere at all with a local model.
|
|
135
|
+
|
|
136
|
+
### OCR providers
|
|
137
|
+
|
|
138
|
+
| `MAIL_OCR_PROVIDER` | What it is | Needs | Reads PDFs |
|
|
139
|
+
|---|---|---|---|
|
|
140
|
+
| `auto` (default) | Mistral when `MISTRAL_API_KEY` is set, a custom server when address and model are set, otherwise off | — | — |
|
|
141
|
+
| `mistral` | Mistral OCR (`mistral-ocr-latest`) | key | directly |
|
|
142
|
+
| `anthropic` | Claude through the official SDK (default model `claude-opus-5-5`) | key | directly |
|
|
143
|
+
| `openai`, `openrouter`, `gemini` | hosted OpenAI-compatible vision chat APIs | key + model | page images |
|
|
144
|
+
| `ollama`, `lmstudio` | local models on `localhost` | model | page images |
|
|
145
|
+
| `custom` | any other OpenAI-compatible server | `MAIL_OCR_BASE_URL` + model | page images |
|
|
146
|
+
| `off` | no OCR | — | — |
|
|
147
|
+
|
|
148
|
+
`MAIL_OCR_API_KEY`, `MAIL_OCR_MODEL` and `MAIL_OCR_BASE_URL` complete the choice. Examples:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
MAIL_OCR_PROVIDER=ollama MAIL_OCR_MODEL=llama3.2-vision # fully local
|
|
152
|
+
MAIL_OCR_PROVIDER=openrouter MAIL_OCR_API_KEY=… MAIL_OCR_MODEL=<a vision model>
|
|
153
|
+
MAIL_OCR_PROVIDER=anthropic MAIL_OCR_API_KEY=…
|
|
154
|
+
MAIL_OCR_PROVIDER=custom MAIL_OCR_BASE_URL=http://nas.lan:8000/v1 MAIL_OCR_MODEL=…
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Providers that take images only get each scanned page as a PNG taken out of the PDF (the
|
|
158
|
+
scan itself, scaled to 2000 px). A page that is not one big picture cannot be handed to them
|
|
159
|
+
and is reported as unread; Mistral and Anthropic read any PDF. Pages are sent three at a time.
|
|
160
|
+
|
|
161
|
+
Things to expect: a local model can need a minute or more per dense page, which may exceed
|
|
162
|
+
your client's tool timeout — read long scans in page ranges. General vision models transcribe
|
|
163
|
+
well but, like every OCR, can misplace cells in tables with graphics; `preview: true` adds the
|
|
164
|
+
page image so the model can check. With `anthropic`, a declined request is retried
|
|
165
|
+
server-side on a fallback model (`fallbacks: "default"`) on the current Claude models.
|
|
166
|
+
|
|
167
|
+
`node test/live-ocr.mjs` runs the provider configured in the environment against a scanned
|
|
168
|
+
fixture (or your own file) and prints the result.
|
|
169
|
+
|
|
170
|
+
## Languages
|
|
171
|
+
|
|
172
|
+
Tool titles, descriptions, output and error messages are localized. English is the source,
|
|
173
|
+
Czech is written by hand, and German, Spanish, French, Italian, Dutch, Polish, Portuguese and
|
|
174
|
+
Slovak are **machine translations** that no native speaker has reviewed yet — corrections are
|
|
175
|
+
welcome.
|
|
176
|
+
|
|
177
|
+
To add or fix a language edit `src/locales/<code>.ts` (copy `en.ts`, keep the `{placeholders}`
|
|
178
|
+
and line breaks) and register it in `src/locales/index.ts`. A locale may be partial; missing
|
|
179
|
+
keys fall back to English. `npm run test:offline` checks every locale against the English keys.
|
|
180
|
+
|
|
181
|
+
## Branded builds (presets)
|
|
182
|
+
|
|
183
|
+
For a family or a team you can ship an extension where the server address is pre-filled and
|
|
184
|
+
people only type their e-mail and password. A preset is a folder with its own `manifest.json`
|
|
185
|
+
(and optionally `icon.png`); see [presets/example](presets/example).
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
./pack.sh --preset /path/to/preset # → /path/to/preset/<name>.mcpb
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
The preset's manifest sets `MAIL_TOOL_PREFIX`, `MAIL_BRAND`, `MAIL_LANG` or
|
|
192
|
+
`MAIL_DOWNLOAD_DIR` through `env`, and gives `server_url` a default. Keep the preset's `name`
|
|
193
|
+
stable so Claude Desktop treats new builds as updates.
|
|
194
|
+
|
|
195
|
+
## Tests
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
npm run test:offline # no mailbox needed: fake JMAP + fake OCR, the real server over stdio
|
|
199
|
+
MISTRAL_API_KEY=… node test/offline.mjs --live-ocr # also sends the fixtures to the real OCR
|
|
200
|
+
STALWART_URL=… STALWART_USER=… STALWART_PASSWORD=… node test/smoke.mjs # real mailbox
|
|
201
|
+
STALWART_URL=… STALWART_USER=… STALWART_PASSWORD=… node test/smoke.mjs --send # also sends a mail to yourself
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The offline test covers attachments, OCR, the tool prefix, language selection and locale
|
|
205
|
+
consistency. The smoke test creates a draft and deletes it; with `--send` it leaves one test
|
|
206
|
+
message in the mailbox.
|
|
207
|
+
|
|
208
|
+
## Good to know
|
|
209
|
+
|
|
210
|
+
- **A wrong password gets the IP banned** by Stalwart after a few attempts. The server signs in
|
|
211
|
+
on the first tool call, not at start, so restarting the client does not cause bans; calling
|
|
212
|
+
tools repeatedly with a wrong password does.
|
|
213
|
+
- Built for and used with Stalwart 0.16. The mail part is plain RFC 8620/8621 and may work with
|
|
214
|
+
other JMAP servers, but that is untested; contacts need JMAP for Contacts (RFC 9610).
|
|
215
|
+
- `Email/query` with `"inMailbox": null` is rejected by Stalwart — the filter must be absent or
|
|
216
|
+
carry an id.
|
|
217
|
+
- The extension bundle is one CommonJS file (~3.8 MB, most of it pdf.js from `unpdf`); the
|
|
218
|
+
`.cjs` extension matters because `package.json` says `"type": "module"`.
|
|
219
|
+
- A tool result in Claude Desktop is capped at about 1 MB, hence the 600 kB limit for inline
|
|
220
|
+
images.
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
MIT
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
The distributed bundle (`dist/index.cjs`, the `.mcpb` extension and the npm package) contains
|
|
4
|
+
the following open-source software. Each is used unmodified.
|
|
5
|
+
|
|
6
|
+
| Component | License | Source |
|
|
7
|
+
|---|---|---|
|
|
8
|
+
| @modelcontextprotocol/sdk | MIT | https://github.com/modelcontextprotocol/typescript-sdk |
|
|
9
|
+
| @anthropic-ai/sdk | MIT | https://github.com/anthropics/anthropic-sdk-typescript |
|
|
10
|
+
| zod | MIT | https://github.com/colinhacks/zod |
|
|
11
|
+
| unpdf | MIT | https://github.com/unjs/unpdf |
|
|
12
|
+
| PDF.js (bundled inside unpdf) | Apache-2.0 | https://github.com/mozilla/pdf.js |
|
|
13
|
+
|
|
14
|
+
PDF.js is Copyright Mozilla Foundation and licensed under the Apache License, Version 2.0;
|
|
15
|
+
a copy of that license is available at https://www.apache.org/licenses/LICENSE-2.0.
|
|
16
|
+
The MIT-licensed components are Copyright their respective authors; their license texts ship
|
|
17
|
+
in the corresponding packages on npm.
|