hypermail-mcp 0.6.2 → 0.7.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/README.md +64 -145
- package/dist/cli.js +178 -643
- package/dist/cli.js.map +1 -1
- package/package.json +1 -3
package/README.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
A **Model Context Protocol** server that lets an agent operate any of the user's
|
|
4
4
|
inboxes through a single, unified tool surface.
|
|
5
5
|
|
|
6
|
+
> **v0.7.0** — Email watch mode: background poll loop detects new inbox
|
|
7
|
+
> messages and POSTs them to a configurable webhook URL (e.g. Mastra). Opt-in —
|
|
8
|
+
> disabled by default, enabled via `HYPERMAIL_WATCH_ENABLED=true` or config.
|
|
9
|
+
> Works in both stdio and HTTP transport modes.
|
|
10
|
+
>
|
|
11
|
+
> **v0.6.3** — Unify stdio and HTTP modes into a single feature set. Removed
|
|
12
|
+
> email watch (inbox polling, SSE push, notification buffer), agent
|
|
13
|
+
> multi-tenancy (`agents.yaml`, `x-api-key` auth, per-agent allowlists), and
|
|
14
|
+
> the `check_notifications` tool. Dropped `js-yaml` dependency. Dockerfile
|
|
15
|
+
> simplified to a single `install → build → prune` step.
|
|
16
|
+
>
|
|
6
17
|
> **v0.6.2** — Version source-of-truth fix: `version.ts` now imports directly
|
|
7
18
|
> from `package.json` instead of hardcoding, preventing version drift between
|
|
8
19
|
> the two files.
|
|
@@ -11,10 +22,6 @@ inboxes through a single, unified tool surface.
|
|
|
11
22
|
> email notification bug fixes (ID-based dedup, pagination cap, dynamic
|
|
12
23
|
> re-scan), Node 22 base image, dropped docker-compose.
|
|
13
24
|
>
|
|
14
|
-
> **v0.6.0** — Email watch notifications (polling-based), `signaturePath`
|
|
15
|
-
> support in `set_account_settings` for loading signatures from files,
|
|
16
|
-
> and a `check_notifications` tool for draining pending alerts.
|
|
17
|
-
>
|
|
18
25
|
> **v0.5.0** — Replaced optional `isHtml` boolean with required `format`
|
|
19
26
|
> parameter (`"html"` | `"markdown"`) on `send_email`, `draft_email`, and
|
|
20
27
|
> `edit_draft`. Markdown bodies are converted to HTML via `marked` so
|
|
@@ -99,135 +106,37 @@ docker run -d \
|
|
|
99
106
|
|
|
100
107
|
The image runs the server in HTTP mode on port 3000 with a 30-second
|
|
101
108
|
HEALTHCHECK against `/mcp`. Data is persisted via a Docker volume at `/data`.
|
|
102
|
-
Pass `HYPERMAIL_AGENTS_CONFIG` and mount a config file for agent multi-tenancy.
|
|
103
109
|
|
|
104
|
-
### Development
|
|
110
|
+
### Development
|
|
105
111
|
|
|
106
|
-
To test the
|
|
112
|
+
To test the HTTP server locally:
|
|
107
113
|
|
|
108
114
|
```bash
|
|
109
115
|
# Terminal 1: auto-rebuild TypeScript on save
|
|
110
116
|
pnpm dev
|
|
111
117
|
|
|
112
|
-
# Terminal 2: start HTTP server with dev config
|
|
118
|
+
# Terminal 2: start HTTP server with dev config
|
|
113
119
|
pnpm dev:http
|
|
114
120
|
```
|
|
115
121
|
|
|
116
122
|
The server listens on `http://127.0.0.1:3000/mcp`. Pi connects via the
|
|
117
123
|
`.pi/mcp.json` config (read by `pi-mcp-adapter`). Tools appear as
|
|
118
|
-
`hypermail_http_
|
|
119
|
-
|
|
120
|
-
The dev config (`hypermail-config.http.json`) uses a separate data dir
|
|
121
|
-
(`~/.hypermail-mcp-dev`) and a 10-second poll interval for fast feedback.
|
|
122
|
-
|
|
123
|
-
## Modes: stdio vs HTTP
|
|
124
|
-
|
|
125
|
-
The server runs in one of two modes — the choice affects session management,
|
|
126
|
-
security, and which features are available.
|
|
127
|
-
|
|
128
|
-
| | stdio (default) | HTTP (`--http`) |
|
|
129
|
-
| --- | --- | --- |
|
|
130
|
-
| **Transport** | stdin/stdout | HTTP (Streamable HTTP MCP) |
|
|
131
|
-
| **Lifecycle** | Per-invocation (lazy) — spawned on demand by the MCP host | Long-lived server process |
|
|
132
|
-
| **Session model** | One `McpServer` instance for all invocations | One `McpServer` per MCP session (multi-tenant) |
|
|
133
|
-
| **Key management** | Auto-generated, stored in OS keychain or `master.key` file | Requires `HYPERMAIL_MCP_KEY` env var (32-byte key for AES-256-GCM) |
|
|
134
|
-
| **Email watch** | ❌ Not available | ✅ Polls inbox every N seconds for new mail |
|
|
135
|
-
| **`check_notifications`** | ❌ Not registered | ✅ Drains pending new-mail alerts |
|
|
136
|
-
| **Agent multi-tenancy** | ❌ Unrestricted access | ✅ Per-agent API keys, account allowlists, provisioning control (via `agents.yaml`) |
|
|
137
|
-
| **Pi tool naming** | `hyper_*` | `hypermail_http_*` |
|
|
138
|
-
|
|
139
|
-
**When to use HTTP mode:**
|
|
140
|
-
- You need email watch / push notifications
|
|
141
|
-
- You want to expose the server to multiple agents with different permissions
|
|
142
|
-
- You're hosting the server as a service (Docker, cloud)
|
|
143
|
-
|
|
144
|
-
**When to use stdio mode:**
|
|
145
|
-
- Single-user local development with a desktop MCP client (Claude, Pi)
|
|
146
|
-
- You don't need email watch or multi-agent access control
|
|
147
|
-
|
|
148
|
-
## Agent multi-tenancy
|
|
149
|
-
|
|
150
|
-
In HTTP mode, the server can be shared across multiple agents with
|
|
151
|
-
different permissions. Agent identity and authorization are defined in an
|
|
152
|
-
`agents.yaml` file.
|
|
153
|
-
|
|
154
|
-
### agents.yaml
|
|
155
|
-
|
|
156
|
-
```yaml
|
|
157
|
-
agents:
|
|
158
|
-
- id: my-assistant
|
|
159
|
-
api_key: hm_sk_<64-hex-chars>
|
|
160
|
-
name: My Email Assistant
|
|
161
|
-
accounts: # which email addresses this agent can access
|
|
162
|
-
- alice@example.com
|
|
163
|
-
- bob@example.com
|
|
164
|
-
provisioning: false # can this agent add/remove accounts?
|
|
165
|
-
|
|
166
|
-
- id: admin-agent
|
|
167
|
-
api_key: hm_sk_<64-hex-chars>
|
|
168
|
-
name: Admin Agent
|
|
169
|
-
accounts: [] # empty = all accounts
|
|
170
|
-
provisioning: true
|
|
171
|
-
|
|
172
|
-
# Optional: pre-declare email accounts with provider hints
|
|
173
|
-
email_accounts:
|
|
174
|
-
alice@example.com:
|
|
175
|
-
provider: outlook
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
**Agent ID:** lowercase letters, digits, hyphens, underscores. No spaces.
|
|
179
|
-
|
|
180
|
-
**API key format:** `hm_sk_` prefix + 64 hex characters. Generate with:
|
|
181
|
-
|
|
182
|
-
```bash
|
|
183
|
-
hypermail-mcp generate-key
|
|
184
|
-
# => hm_sk_a1b2c3d4...
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
The API key is hashed (SHA-256) before storage — the plaintext is never
|
|
188
|
-
written to disk. Agents authenticate by passing the key in the
|
|
189
|
-
`Authorization: Bearer hm_sk_...` header.
|
|
190
|
-
|
|
191
|
-
**accounts:** An allowlist of email addresses the agent can operate on.
|
|
192
|
-
If empty or omitted, the agent can access all configured accounts.
|
|
193
|
-
|
|
194
|
-
**provisioning:** When `true`, the agent can call `add_account` and
|
|
195
|
-
`remove_account`. Defaults to `false`.
|
|
196
|
-
|
|
197
|
-
### Configuration
|
|
124
|
+
`hypermail_http_*`.
|
|
198
125
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
```bash
|
|
202
|
-
# Via CLI flag
|
|
203
|
-
hypermail-mcp --http --agents-config ./agents.yaml
|
|
204
|
-
|
|
205
|
-
# Via env var
|
|
206
|
-
export HYPERMAIL_AGENTS_CONFIG=/etc/hypermail/agents.yaml
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
The server watches `agents.yaml` for changes and reloads automatically
|
|
210
|
-
(live reload — no restart needed). Agents removed from the file lose
|
|
211
|
-
access on their next request.
|
|
212
|
-
|
|
213
|
-
In **stdio mode**, agent multi-tenancy is not available — the server runs
|
|
214
|
-
with unrestricted access (the local user _is_ the agent).
|
|
215
|
-
|
|
216
|
-
## Configuration
|
|
126
|
+
## Add-account flow (Outlook)
|
|
217
127
|
|
|
218
128
|
| Env var | Purpose | Default |
|
|
219
129
|
| --- | --- | --- |
|
|
220
130
|
| `HYPERMAIL_MCP_DATA_DIR` | Where to keep the encrypted accounts blob | `~/.hypermail-mcp` |
|
|
221
|
-
| `HYPERMAIL_MCP_KEY` | 32-byte AES-256-GCM key (hex, base64, or any passphrase — derived via SHA-256). Required for hosted deployments. | auto-generated, stored via OS keychain (`keytar`) or a local `master.key` file |
|
|
222
|
-
| `HYPERMAIL_AGENTS_CONFIG` | Path to `agents.yaml` for HTTP multi-tenant mode (see Agent multi-tenancy above). | — (multi-tenancy disabled) |
|
|
131
|
+
| `HYPERMAIL_MCP_KEY` | 32-byte AES-256-GCM key (hex, base64, or any passphrase — derived via SHA-256). Required for hosted deployments. Auto-generated for stdio. | auto-generated, stored via OS keychain (`keytar`) or a local `master.key` file |
|
|
223
132
|
| `MS_CLIENT_ID` | Azure Entra public client (application) id used for device-code login | placeholder — **set your own for production** |
|
|
224
133
|
| `MS_TENANT_ID` | Tenant for the authority URL | `common` |
|
|
225
134
|
|
|
226
|
-
CLI flags: `--http`, `--port`, `--host`, `--data-dir`, `--
|
|
135
|
+
CLI flags: `--http`, `--port`, `--host`, `--data-dir`, `--read-only`, `--help`.
|
|
227
136
|
|
|
228
|
-
Subcommands: `hypermail-mcp generate-key` — generate an `hm_sk_` API key
|
|
137
|
+
Subcommands: `hypermail-mcp generate-key` — generate an `hm_sk_` API key.
|
|
229
138
|
|
|
230
|
-
###
|
|
139
|
+
### Configuration
|
|
231
140
|
|
|
232
141
|
Instead of (or in addition to) CLI flags and env vars, you can configure the
|
|
233
142
|
server with a `hypermail-config.json` file next to the server binary. The server
|
|
@@ -245,6 +154,14 @@ looks for it in the same directory as `cli.js`.
|
|
|
245
154
|
},
|
|
246
155
|
"providers": {
|
|
247
156
|
"outlook": { "clientId": "...", "tenantId": "..." }
|
|
157
|
+
},
|
|
158
|
+
"watch": {
|
|
159
|
+
"enabled": true,
|
|
160
|
+
"pollIntervalSeconds": 10,
|
|
161
|
+
"webhook": {
|
|
162
|
+
"url": "http://your-agent:3000/api/email-webhook",
|
|
163
|
+
"retry": { "maxAttempts": 5, "baseDelayMs": 1000 }
|
|
164
|
+
}
|
|
248
165
|
}
|
|
249
166
|
}
|
|
250
167
|
```
|
|
@@ -285,45 +202,51 @@ account store.
|
|
|
285
202
|
| `rename_folder` | `account`, `folderId`, `newName` | Rename an existing mail folder. Disabled under `--read-only`. |
|
|
286
203
|
| `mark_read` | `account`, `id` | Mark a message as read. Disabled under `--read-only`. |
|
|
287
204
|
| `mark_unread` | `account`, `id` | Mark a message as unread. Disabled under `--read-only`. |
|
|
288
|
-
| `check_notifications` | — | Returns pending email-watch notifications (new-email alerts, auth failures). Drains the buffer on read. Only registered in HTTP mode. |
|
|
289
205
|
|
|
290
206
|
## Email Watch
|
|
291
207
|
|
|
292
|
-
When
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
- **Push** — `notifications/message` sent over the MCP stream. Compatible
|
|
297
|
-
clients (e.g. Mastra) receive these in real time.
|
|
298
|
-
- **Poll** — `check_notifications` tool drains an in-memory buffer. Works with
|
|
299
|
-
**any** MCP client, even those that don't maintain an SSE listener.
|
|
300
|
-
|
|
301
|
-
**Configuration** (in `hypermail-config.json`):
|
|
208
|
+
When enabled, hypermail-mcp runs a background poll loop that scans inboxes for
|
|
209
|
+
new messages and POSTs each one to a configurable webhook URL. Intended for
|
|
210
|
+
push-based email triage — downstream agents (e.g. Mastra) receive full email
|
|
211
|
+
content without polling.
|
|
302
212
|
|
|
303
213
|
```jsonc
|
|
304
214
|
{
|
|
305
215
|
"watch": {
|
|
306
|
-
"enabled": true,
|
|
307
|
-
"pollIntervalSeconds":
|
|
216
|
+
"enabled": true,
|
|
217
|
+
"pollIntervalSeconds": 10,
|
|
218
|
+
"webhook": {
|
|
219
|
+
"url": "http://localhost:3000/api/email-webhook",
|
|
220
|
+
"retry": { "maxAttempts": 5, "baseDelayMs": 1000 }
|
|
221
|
+
}
|
|
308
222
|
}
|
|
309
223
|
}
|
|
310
224
|
```
|
|
311
225
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
- Each poll paginates through the inbox (25 items per page) to catch email
|
|
320
|
-
bursts without missing messages.
|
|
321
|
-
- Auth failures (e.g. expired OAuth tokens) generate immediate notifications.
|
|
322
|
-
|
|
323
|
-
**Not supported in stdio mode.** The watcher requires a long-lived server
|
|
324
|
-
process. In stdio mode the `check_notifications` tool is not registered.
|
|
226
|
+
| Setting | Default | Notes |
|
|
227
|
+
| --- | --- | --- |
|
|
228
|
+
| `watch.enabled` | `false` | Toggle via config or `HYPERMAIL_WATCH_ENABLED=true` env var |
|
|
229
|
+
| `watch.pollIntervalSeconds` | `10` | Min 10s, max 3600s |
|
|
230
|
+
| `watch.webhook.url` | — | Endpoint that receives `POST` with `EmailFull` JSON |
|
|
231
|
+
| `watch.webhook.retry.maxAttempts` | `5` | Max delivery attempts (1–10) |
|
|
232
|
+
| `watch.webhook.retry.baseDelayMs` | `1000` | Base backoff delay (× 2^attempt) |
|
|
325
233
|
|
|
326
|
-
|
|
234
|
+
**Behavior:**
|
|
235
|
+
- Polls **all accounts** in the store, **inbox only**.
|
|
236
|
+
- Detects new emails via `lastSeenIds` (capped at 200) stored in the encrypted
|
|
237
|
+
account file — no duplicate emits across restarts.
|
|
238
|
+
- One `POST` per email (full body: subject, sender, text, HTML, attachments
|
|
239
|
+
metadata, thread ID via `EmailFull`).
|
|
240
|
+
- Delivery uses exponential backoff (`baseDelay × 2^attempt`). Retries on
|
|
241
|
+
non-2xx responses and connection errors. Logs and moves on after
|
|
242
|
+
`maxAttempts` exhausted — never blocks the poll loop.
|
|
243
|
+
- Works in both **stdio** and **HTTP** transport modes — the poll interval
|
|
244
|
+
fires normally alongside MCP message handling.
|
|
245
|
+
|
|
246
|
+
**Rate limits:** Polling every 10s on a single inbox = 6 req/min = 0.6% of
|
|
247
|
+
Microsoft Graph's 10,000 req/10min per-user limit. Safe for personal inboxes.
|
|
248
|
+
|
|
249
|
+
## Add-account flow (Outlook)
|
|
327
250
|
|
|
328
251
|
1. Agent calls `add_account({ provider: "outlook" })`.
|
|
329
252
|
2. Server returns:
|
|
@@ -357,11 +280,8 @@ src/
|
|
|
357
280
|
server.ts # MCP server, stdio + HTTP transports, session management
|
|
358
281
|
version.ts # version constant
|
|
359
282
|
config.ts # hypermail-config.json schema + resolution
|
|
360
|
-
config/
|
|
361
|
-
agents-config.ts # agents.yaml schema, validation, live-reload watcher
|
|
362
283
|
store/
|
|
363
284
|
account-store.ts # encrypted multi-account store (AES-256-GCM)
|
|
364
|
-
agent-store.ts # agent identity + credentials store (HTTP multi-tenant)
|
|
365
285
|
crypto.ts # AES-256-GCM encrypt/decrypt, key resolution, atomic writes
|
|
366
286
|
providers/
|
|
367
287
|
types.ts # EmailProvider interface + shared DTOs
|
|
@@ -377,16 +297,15 @@ src/
|
|
|
377
297
|
index.ts # GmailProvider implementation
|
|
378
298
|
shared/ # shared utilities across providers
|
|
379
299
|
watcher/
|
|
380
|
-
manager.ts # inbox
|
|
381
|
-
|
|
300
|
+
manager.ts # WatcherManager — inbox poll loop + dedup
|
|
301
|
+
webhook.ts # HTTP POST with exponential backoff retry
|
|
302
|
+
index.ts # barrel export
|
|
382
303
|
tools/
|
|
383
304
|
index.ts # MCP tool registrations
|
|
384
|
-
agent-context.ts # agent authorization guards (checkAccountAccess, checkProvisioning)
|
|
385
305
|
accounts.ts # list/add/remove/complete-add account tools
|
|
386
306
|
browse.ts # list/search/read email tools
|
|
387
307
|
compose.ts # send/draft/edit/send-draft/add-attachment tools
|
|
388
308
|
folders.ts # list/create/delete/rename folder tools
|
|
389
|
-
notifications.ts # check_notifications tool (HTTP only)
|
|
390
309
|
organize.ts # archive/trash/move/mark-read/mark-unread tools
|
|
391
310
|
shared.ts # shared tool helpers
|
|
392
311
|
```
|