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.
@@ -0,0 +1,149 @@
1
+ # Zapojení do malé vlastní infrastruktury
2
+
3
+ *[English](small-infrastructure.md)*
4
+
5
+ Popisuje sestavu, pro kterou server vznikl: jeden domácí nebo kancelářský stroj, na kterém běží
6
+ Stalwart pro rodinu nebo pár lidí, před ním reverzní proxy a na notebooku každého Claude
7
+ Desktop. Názvy hostitelů jsou příklady.
8
+
9
+ ## Jak to vypadá
10
+
11
+ ```text
12
+ notebook tvůj server
13
+ ┌───────────────────────────┐ ┌──────────────────────────────────────────────┐
14
+ │ Claude Desktop │ │ reverzní proxy (Traefik / Caddy / nginx), TLS│
15
+ │ └─ Stalwart Mail MCP ────┼── HTTPS ──▶│ /.well-known/jmap, /jmap/* ──▶ Stalwart │
16
+ │ (místní proces) │ JMAP │ (správcovské API zůstává uvnitř) │
17
+ │ └─ další tvoje MCP │ │ Stalwart: SMTP · IMAP · JMAP · CardDAV │
18
+ └───────────┬───────────────┘ │ webmail (volitelně) na stejném názvu │
19
+ │ volitelně, jen skeny └──────────────────────────────────────────────┘
20
+ ▼
21
+ OCR: lokální model (Ollama, LM Studio) nebo API (Mistral, Anthropic, kompatibilní s OpenAI)
22
+ ```
23
+
24
+ MCP server je místní proces na notebooku. Drží heslo schránky (z klíčenky), mluví s tvým
25
+ serverem přes JMAP a dává Claudovi deset nástrojů. Na straně serveru není potřeba žádný
26
+ doplněk, účet navíc ani API klíč — jen JMAP dostupný přes HTTPS.
27
+
28
+ ## Co musí server nabízet
29
+
30
+ 1. **JMAP přes HTTPS** na veřejném názvu (nebo dostupném přes VPN) s platným certifikátem.
31
+ 2. **Dvě cesty přes reverzní proxy**: `/.well-known/jmap` a všechno pod `/jmap` (session,
32
+ API, nahrávání i stahování žijí tam). Nic dalšího potřeba není — správcovské API a správu
33
+ Stalwartu na veřejný router nedávej.
34
+ 3. **Adresy v session musí ukazovat na veřejný název.** Klient si z objektu session přečte
35
+ `apiUrl`, `uploadUrl` a `downloadUrl` a volá je tak, jak jsou. Ověření:
36
+
37
+ ```bash
38
+ curl -s -u jana@example.com https://mail.example.com/.well-known/jmap -L | head -c 600
39
+ ```
40
+
41
+ Když adresy ukazují na vnitřní název nebo `http://`, oprav nejdřív veřejnou adresu
42
+ Stalwartu / hlavičky proxy — jinak by hledání fungovalo, ale přílohy a odesílání ne.
43
+ 4. **Ke Stalwartu musí dojít skutečná IP klienta.** Stalwart banuje adresy, které hádají
44
+ hesla. Když vidí jen adresu proxy, jedno špatně opsané heslo v nastavení něčího rozšíření
45
+ zabanuje proxy, tedy všechny. Předej IP klienta dál (PROXY protocol nebo důvěryhodné
46
+ hlavičky) a bany zůstanou na jednom člověku.
47
+
48
+ Router Traefiku pro JMAP vypadá takto (file provider):
49
+
50
+ ```yaml
51
+ http:
52
+ routers:
53
+ stalwart-jmap:
54
+ rule: "Host(`mail.example.com`) && (PathPrefix(`/jmap`) || Path(`/.well-known/jmap`))"
55
+ entryPoints: [websecure]
56
+ service: stalwart-web
57
+ tls: {}
58
+ services:
59
+ stalwart-web:
60
+ loadBalancer:
61
+ servers:
62
+ - url: "http://stalwart:8080"
63
+ ```
64
+
65
+ Pokud ti proti Stalwartu už běží webmail přes JMAP, cesty jsou hotové a není co měnit.
66
+
67
+ ## Účty a přihlášení
68
+
69
+ - Každý se přihlašuje **svou schránkou** — stejnou adresou a heslem jako v telefonu. Pokud
70
+ tvůj Stalwart nabízí hesla aplikací, použij pro rozšíření jedno z nich, ať jde zrušit
71
+ samostatně.
72
+ - `STALWART_TOKEN` přijme místo hesla přístupový token OAuth (posílá se jako Bearer), pokud
73
+ si tokeny vydáváš sám; rozšíření žádné interaktivní přihlášení OAuth nemá.
74
+ - **Sdílené schránky a skupiny** se na klientu nenastavují: každý účet, ke kterému má
75
+ přihlášený uživatel přístup, je v JMAP session a nástroje ho berou parametrem `account`
76
+ (`account: "rodina"`). Vypíše je `mail_list_mailboxes`. Sdílený účet má vlastní složky,
77
+ odesílací identitu i adresář.
78
+ - **Kontakty** jsou adresáře serveru (JMAP for Contacts). Tytéž adresáře se do telefonů
79
+ synchronizují přes CardDAV, takže kontakt, který Claude přidá do sdíleného adresáře, se
80
+ objeví všem v telefonu.
81
+
82
+ ## Co Claude může a co ne
83
+
84
+ - Čte, hledá, zakládá koncepty a odesílá **jako ten člověk** — nic víc, než dovolí heslo
85
+ schránky, a nic v cizích soukromých schránkách.
86
+ - Odeslání je okamžité. Popisy nástrojů modelu ukládají posílat jen na výslovný pokyn
87
+ a jinak uložit koncept; koncepty jsou vidět ve webmailu i v telefonu ke kontrole. Kdo chce
88
+ tvrdou pojistku místo pokynu, vypne v nastavení rozšíření **Povolit odesílání** — nástroje
89
+ pro odeslání pak pro model neexistují — nebo si je v klientu nechá schvalovat ručně.
90
+ - Přijatou ani odeslanou poštu smazat neumí; `mail_delete_draft` odmítne cokoli, co není
91
+ koncept.
92
+ - Přílohy se ukládají na notebook (výchozí `~/Downloads/Mail-Attachments`).
93
+
94
+ ## Co odchází z počítače
95
+
96
+ | Data | Kam jdou |
97
+ |---|---|
98
+ | heslo schránky, veškerý poštovní provoz | jen na tvůj Stalwart |
99
+ | obsah zpráv a příloh, které model čte | k AI klientu, který používáš (jako výstup každého nástroje) |
100
+ | naskenované strany PDF a fotky, když je zapnuté OCR | ke zvolenému poskytovateli OCR — nebo s lokálním modelem nikam |
101
+
102
+ OCR je vypnuté, dokud není nastavený poskytovatel, a `ocr: false` ho přeskočí u jedné přílohy.
103
+ Když dokumenty nesmí opustit dům, pusť model s viděním v Ollamě na notebooku nebo na serveru
104
+ a rozšíření na něj nasměruj (`ollama`, nebo `custom` s adresou serveru).
105
+
106
+ ## Jedno rozšíření pro celou domácnost
107
+
108
+ Psát adresu serveru je pro většinu lidí o jedno pole víc, než je zdrávo. Vyrob **předvolbu**:
109
+ kopii manifestu s předvyplněným serverem, vlastním názvem a ikonou a — pokud chceš, aby se
110
+ nástroje v rozhovoru četly přirozeně — s vlastní předponou a výchozím jazykem.
111
+
112
+ ```text
113
+ moje-predvolba/
114
+ manifest.json name, display_name, výchozí server_url, env: MAIL_TOOL_PREFIX, MAIL_BRAND, MAIL_LANG
115
+ icon.png
116
+ ```
117
+
118
+ ```bash
119
+ ./pack.sh --preset ~/infra/moje-predvolba # → ~/infra/moje-predvolba/<name>.mcpb
120
+ ```
121
+
122
+ Soubor `.mcpb` rozdej lidem (není tajný, žádné přihlašovací údaje v něm nejsou); otevřou ho,
123
+ zadají e-mail a heslo a je hotovo. Předvolbu drž vedle ostatní konfigurace infrastruktury
124
+ a přestav ji, kdykoli se tento repozitář posune. Její `name` neměň, aby klient nabídl
125
+ aktualizaci, a ne druhé rozšíření.
126
+
127
+ ## Kombinace s dalšími nástroji
128
+
129
+ Smysl pošty za MCP je v tom, že se v jednom rozhovoru potká s ostatními daty:
130
+
131
+ - oborový nástroj (CRM, databáze nemovitostí, fakturace jako vlastní MCP server) a pošta:
132
+ „podívej se, jestli už makléř odpověděl, přečti přiložený průkaz energetické náročnosti
133
+ a doplň zjištění k záznamu“;
134
+ - ranní naplánovaná úloha: nepřečtená pošta od včerejška podle odesílatelů, s přílohami
135
+ shrnutými;
136
+ - odpovědi z poznámek — Claude napíše koncept, ty ho odešleš z telefonu.
137
+
138
+ Každou oblast drž ve vlastním MCP serveru; tenhle zná jen poštu a kontakty.
139
+
140
+ ## Provozní poznámky
141
+
142
+ - **Bany**: po změně hesla uprav nastavení rozšíření dřív, než zavoláš další nástroj. Ban se
143
+ projeví jako odmítnuté spojení nebo 401 po nějakou dobu; zmizí sám, nebo ho zrušíš ve
144
+ správě Stalwartu.
145
+ - **Aktualizace**: `git pull && ./pack.sh` (nebo `--preset …`) a otevřít nový `.mcpb`.
146
+ - **Záloh** se netýká — server nedrží žádný stav, všechno je ve Stalwartu.
147
+ - **Monitoring**: sonda na `https://mail.example.com/.well-known/jmap` řekne, že cesta, na
148
+ které rozšíření stojí, žije — bez přihlášení Stalwart odpoví 307 na `/jmap/session`, která
149
+ vrátí anonymní session (200, schopnosti serveru, ale žádné účty).
@@ -0,0 +1,86 @@
1
+ # Publishing checklist
2
+
3
+ The repository starts private. Nothing below happens automatically — each step is a decision.
4
+
5
+ ## 0. Before anything goes public
6
+
7
+ - Read `git log` and the tree once more for anything private (hostnames, names, credentials).
8
+ The test fixtures are synthetic; presets with real server names belong in your own
9
+ infrastructure repository, not here.
10
+ - `npm run test:offline` and, against a real mailbox, `node test/smoke.mjs`.
11
+ - Bump `version` in `package.json` (and `server.json`); `pack.sh` copies it into the manifest.
12
+
13
+ ## 1. GitHub: make the repository public and cut a release
14
+
15
+ ```bash
16
+ gh repo edit cybersmurf/stalwart-mail-mcp --visibility public --accept-visibility-change-consequences
17
+ ./pack.sh
18
+ git tag v2.0.0 && git push origin v2.0.0
19
+ gh release create v2.0.0 stalwart-mail.mcpb --title "Stalwart Mail MCP 2.0.0" --notes "First public release."
20
+ ```
21
+
22
+ The `.mcpb` attached to the release is what Claude Desktop users download and open. This step
23
+ alone is enough for people to use it.
24
+
25
+ ## 2. npm: `npx stalwart-mail-mcp` for every other MCP client
26
+
27
+ ```bash
28
+ npm adduser # once
29
+ npm publish --access public # prepublishOnly builds and runs the offline test
30
+ ```
31
+
32
+ After that any client can run it without cloning:
33
+
34
+ ```json
35
+ { "command": "npx", "args": ["-y", "stalwart-mail-mcp"], "env": { "STALWART_URL": "…", "STALWART_USER": "…", "STALWART_PASSWORD": "…" } }
36
+ ```
37
+
38
+ ## 3. Official MCP Registry (feeds the catalogs of MCP clients)
39
+
40
+ The registry stores metadata only and verifies it against the npm package, so step 2 comes
41
+ first. `package.json` already carries `mcpName` and `server.json` is in the repository root;
42
+ both must name `io.github.cybersmurf/stalwart-mail-mcp` and the same version as on npm.
43
+
44
+ ```bash
45
+ brew install mcp-publisher
46
+ mcp-publisher login github # device code in the browser
47
+ mcp-publisher publish
48
+ ```
49
+
50
+ Guide: <https://modelcontextprotocol.io/registry/quickstart>
51
+
52
+ ## 4. Claude directory (optional, reviewed by Anthropic)
53
+
54
+ The directory no longer lists local servers packaged as desktop extensions (`.mcpb`). A local
55
+ MCP server gets there inside a **plugin bundle**, and that has a consequence worth knowing
56
+ before spending time on it: per Anthropic's platform table, a local server in a plugin runs in
57
+ **Claude Code** and in **Cowork sessions on your own computer**, and is **ignored in chat**
58
+ (claude.ai, desktop and mobile). Cowork also does not ask for settings, so a server that needs
59
+ a password only really works in Claude Code. People who want mail in Claude Desktop chat keep
60
+ using the `.mcpb` from the GitHub release.
61
+
62
+ The bundle is in [`plugin/`](../plugin): `.claude-plugin/plugin.json` (settings as
63
+ `userConfig`, secrets marked `sensitive`), `.mcp.json` (starts `npx -y stalwart-mail-mcp@<exact
64
+ version>`), a README that says what it runs and where data goes, and the license.
65
+
66
+ 1. npm publish first (step 2) — the bundle starts the package from npm.
67
+ 2. Keep the version in `plugin/.mcp.json` and `plugin/.claude-plugin/plugin.json` equal to
68
+ the published one (`claude plugin validate ./plugin` checks the files are well-formed).
69
+ 3. From a paid Claude account open <https://claude.ai/directory/manage> → **Submit new** →
70
+ **Plugin bundle** → repository `cybersmurf/stalwart-mail-mcp`, folder `plugin` → **Validate**.
71
+ 4. Expect holds for a reviewer rather than an instant listing: a pinned `npx` package is
72
+ always reviewed by a person, and the name contains "Stalwart", a brand that is not ours —
73
+ say in the submission that this is an independent client for Stalwart servers.
74
+
75
+ Checklist: <https://claude.com/docs/plugins/pre-submission-checklist>
76
+
77
+ ## 5. Tell people who run Stalwart
78
+
79
+ A short post in Stalwart's GitHub Discussions (or their community chat) with the link to the
80
+ release and to `docs/small-infrastructure.md` reaches exactly the audience this is for.
81
+
82
+ ## Releasing an update
83
+
84
+ Bump the version in `package.json`, `server.json`, `plugin/.claude-plugin/plugin.json` and `plugin/.mcp.json` → `npm run test:offline` → commit and tag →
85
+ `./pack.sh` and `gh release create` → `npm publish` → `mcp-publisher publish`. Branded presets
86
+ are rebuilt with `./pack.sh --preset <dir>` from their own repositories.
@@ -0,0 +1,150 @@
1
+ # Plugging it into a small self-hosted setup
2
+
3
+ *[Česky](mala-infrastruktura.md)*
4
+
5
+ This describes the kind of setup the server was built for: one home or small-office machine
6
+ that runs Stalwart for a family or a handful of people, behind a reverse proxy, with Claude
7
+ Desktop on everyone's laptop. Hostnames below are examples.
8
+
9
+ ## The picture
10
+
11
+ ```text
12
+ laptop your server
13
+ ┌───────────────────────────┐ ┌──────────────────────────────────────────────┐
14
+ │ Claude Desktop │ │ reverse proxy (Traefik / Caddy / nginx), TLS │
15
+ │ └─ Stalwart Mail MCP ────┼── HTTPS ──▶│ /.well-known/jmap, /jmap/* ──▶ Stalwart │
16
+ │ (local process) │ JMAP │ (admin API stays internal) │
17
+ │ └─ your other MCP servers│ │ Stalwart: SMTP · IMAP · JMAP · CardDAV │
18
+ └───────────┬───────────────┘ │ webmail (optional) on the same host name │
19
+ │ optional, scans only └──────────────────────────────────────────────┘
20
+ ▼
21
+ OCR: a local model (Ollama, LM Studio) or an API (Mistral, Anthropic, OpenAI-compatible)
22
+ ```
23
+
24
+ The MCP server is a local process on the laptop. It holds the mailbox password (from the
25
+ keychain), speaks JMAP to your server, and gives Claude ten tools. The server side needs no
26
+ plugin, no extra account and no API key — only JMAP reachable over HTTPS.
27
+
28
+ ## What the server has to provide
29
+
30
+ 1. **JMAP over HTTPS** on a public (or VPN-reachable) host name with a valid certificate.
31
+ 2. **Two paths through the reverse proxy**: `/.well-known/jmap` and everything under `/jmap`
32
+ (session, API, upload and download all live there). Nothing else is required — keep
33
+ Stalwart's management API and admin UI off the public router.
34
+ 3. **Session URLs that point at the public name.** The client reads `apiUrl`, `uploadUrl` and
35
+ `downloadUrl` from the session object and calls them as they are. Check it:
36
+
37
+ ```bash
38
+ curl -s -u jane@example.com https://mail.example.com/.well-known/jmap -L | head -c 600
39
+ ```
40
+
41
+ If the URLs show an internal host or `http://`, fix Stalwart's public URL / proxy headers
42
+ first — attachments and sending would otherwise fail while searching still works.
43
+ 4. **The real client IP reaching Stalwart.** Stalwart bans addresses that guess passwords. If
44
+ it only ever sees the proxy's address, one mistyped password in someone's extension settings
45
+ bans the proxy, i.e. everybody. Pass the client IP through (PROXY protocol or trusted
46
+ forwarded headers) and bans stay per person.
47
+
48
+ A Traefik router for the JMAP part looks like this (file provider):
49
+
50
+ ```yaml
51
+ http:
52
+ routers:
53
+ stalwart-jmap:
54
+ rule: "Host(`mail.example.com`) && (PathPrefix(`/jmap`) || Path(`/.well-known/jmap`))"
55
+ entryPoints: [websecure]
56
+ service: stalwart-web
57
+ tls: {}
58
+ services:
59
+ stalwart-web:
60
+ loadBalancer:
61
+ servers:
62
+ - url: "http://stalwart:8080"
63
+ ```
64
+
65
+ If a webmail client already works against your Stalwart over JMAP, the routes are already
66
+ there and there is nothing to change.
67
+
68
+ ## Accounts and sign-in
69
+
70
+ - Each person signs in with **their own mailbox** — the same address and password as on the
71
+ phone. If your Stalwart offers app passwords, use one for the extension so it can be revoked
72
+ on its own.
73
+ - `STALWART_TOKEN` takes an OAuth access token instead (sent as Bearer) if you issue tokens
74
+ yourself; the extension has no interactive OAuth flow.
75
+ - **Shared mailboxes and groups** need no setup on the client: every account the signed-in
76
+ user can access appears in the JMAP session, and tools take it through the `account`
77
+ parameter (`account: "family"`). `mail_list_mailboxes` lists them. A shared account has its
78
+ own folders, sending identity and address book.
79
+ - **Contacts** are the server's address books (JMAP for Contacts). The same books sync to
80
+ phones over CardDAV, so a contact Claude adds to the shared book appears on everyone's phone.
81
+
82
+ ## What Claude can and cannot do
83
+
84
+ - It reads, searches, drafts and sends **as that person** — nothing more than the mailbox
85
+ password allows, and nothing on other people's private mailboxes.
86
+ - Sending is immediate. The tool descriptions instruct the model to send only when the user
87
+ explicitly asks and to save a draft otherwise; drafts show up in webmail and on the phone
88
+ for review. If you want a hard guarantee rather than an instruction, switch **Allow sending** off
89
+ in the extension settings — the send tools then do not exist for the model — or keep them
90
+ on manual approval in the client.
91
+ - It cannot delete received or sent mail; `mail_delete_draft` refuses anything that is not a
92
+ draft.
93
+ - Attachments are written to the laptop (`~/Downloads/Mail-Attachments` by default).
94
+
95
+ ## What leaves the machine
96
+
97
+ | Data | Goes to |
98
+ |---|---|
99
+ | mailbox password, all mail traffic | your Stalwart server only |
100
+ | message and attachment content the model reads | the AI client you use (as with any tool output) |
101
+ | scanned PDF pages and photos, when OCR is on | the OCR provider you chose — or nowhere, with a local model |
102
+
103
+ OCR is off until a provider is set up, and `ocr: false` skips it for a single attachment. If
104
+ the documents must not leave the house, run a vision model in Ollama on the laptop or on the
105
+ server and point the extension at it (`ollama`, or `custom` with the server's address).
106
+
107
+ ## One extension for the whole household
108
+
109
+ Typing a server address is one field too many for most people. Build a **preset**: a copy of
110
+ the manifest with your server pre-filled, your own name and icon, and — if you want the tools
111
+ to read naturally in conversations — your own prefix and default language.
112
+
113
+ ```text
114
+ my-preset/
115
+ manifest.json name, display_name, default server_url, env: MAIL_TOOL_PREFIX, MAIL_BRAND, MAIL_LANG
116
+ icon.png
117
+ ```
118
+
119
+ ```bash
120
+ ./pack.sh --preset ~/infra/my-preset # → ~/infra/my-preset/<name>.mcpb
121
+ ```
122
+
123
+ Hand the `.mcpb` to people (it is not secret — it contains no credentials); they open it,
124
+ type e-mail and password, done. Keep the preset next to the rest of your infrastructure
125
+ config and rebuild it whenever this repository moves forward. Keep its `name` unchanged so
126
+ the client offers an update instead of a second extension.
127
+
128
+ ## Combining it with other tools
129
+
130
+ The point of putting mail behind MCP is that it meets your other data in one conversation:
131
+
132
+ - a domain tool (a CRM, a property database, an invoicing system as its own MCP server) plus
133
+ mail: "check whether the agent already answered, read the attached energy certificate and
134
+ add the findings to the record";
135
+ - a scheduled morning task: unread mail since yesterday, grouped by sender, with attachments
136
+ summarized;
137
+ - drafting replies from notes — Claude writes the draft, you send it from the phone.
138
+
139
+ Keep each concern in its own MCP server; this one only knows mail and contacts.
140
+
141
+ ## Operating notes
142
+
143
+ - **Bans**: after a password change, update the extension settings before the next tool call.
144
+ A ban shows up as a refused connection or 401 for a while; it lifts by itself or from the
145
+ Stalwart admin UI.
146
+ - **Updates**: `git pull && ./pack.sh` (or `--preset …`) and open the new `.mcpb`.
147
+ - **Backups** are unaffected — the server keeps no state; everything lives in Stalwart.
148
+ - **Monitoring**: a blackbox probe on `https://mail.example.com/.well-known/jmap` tells you
149
+ the route the extension depends on is alive — without credentials Stalwart answers 307 to
150
+ `/jmap/session`, which returns an anonymous session (200, capabilities but no accounts).
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "stalwart-mail-mcp",
3
+ "version": "2.2.0",
4
+ "description": "MCP server for Stalwart Mail over JMAP: search, read (attachments, OCR of scans), reply, send, drafts, contacts",
5
+ "mcpName": "io.github.cybersmurf/stalwart-mail-mcp",
6
+ "license": "MIT",
7
+ "author": "Petr Šrámek",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/cybersmurf/stalwart-mail-mcp.git"
11
+ },
12
+ "homepage": "https://github.com/cybersmurf/stalwart-mail-mcp#readme",
13
+ "keywords": [
14
+ "mcp",
15
+ "model-context-protocol",
16
+ "stalwart",
17
+ "jmap",
18
+ "email",
19
+ "contacts",
20
+ "ocr",
21
+ "claude"
22
+ ],
23
+ "bin": {
24
+ "stalwart-mail-mcp": "dist/index.cjs"
25
+ },
26
+ "files": [
27
+ "dist/index.cjs",
28
+ "README.md",
29
+ "README.cs.md",
30
+ "docs",
31
+ "LICENSE",
32
+ "THIRD-PARTY-NOTICES.md"
33
+ ],
34
+ "type": "module",
35
+ "main": "dist/index.cjs",
36
+ "scripts": {
37
+ "build": "esbuild src/index.ts --bundle --platform=node --target=node20 --format=cjs --outfile=dist/index.cjs --log-level=warning",
38
+ "typecheck": "tsc --noEmit",
39
+ "test": "npm run build && node test/offline.mjs && node test/smoke.mjs",
40
+ "test:offline": "npm run build && node test/offline.mjs",
41
+ "pack": "bash pack.sh",
42
+ "prepublishOnly": "npm run build && node test/offline.mjs"
43
+ },
44
+ "engines": {
45
+ "node": ">=20"
46
+ },
47
+ "dependencies": {
48
+ "@anthropic-ai/sdk": "^0.131.0",
49
+ "@modelcontextprotocol/sdk": "^1.31.0",
50
+ "unpdf": "^1.8.1",
51
+ "zod": "^4.6.5"
52
+ },
53
+ "devDependencies": {
54
+ "@types/node": "^26.6.3",
55
+ "esbuild": "^0.27.0",
56
+ "typescript": "^5.9.3"
57
+ }
58
+ }