@agenticmail/mcp 0.3.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/REFERENCE.md ADDED
@@ -0,0 +1,857 @@
1
+ # @agenticmail/mcp — Technical Reference
2
+
3
+ Complete technical reference for the AgenticMail MCP server. Lists every tool, resource, input schema, and behavioral detail.
4
+
5
+ ---
6
+
7
+ ## Server Configuration
8
+
9
+ | Property | Value |
10
+ |----------|-------|
11
+ | Name | `AgenticMail` |
12
+ | Version | `0.2.26` |
13
+ | Description | `Email infrastructure for AI agents — by Ope Olatunji` |
14
+ | Transport | `StdioServerTransport` (stdin/stdout) |
15
+ | Capabilities | Tools, Resources |
16
+ | SDK | `@modelcontextprotocol/sdk ^1.12.0` |
17
+
18
+ ## Environment Variables
19
+
20
+ | Variable | Default | Description |
21
+ |----------|---------|-------------|
22
+ | `AGENTICMAIL_API_URL` | `http://127.0.0.1:3100` | API server URL |
23
+ | `AGENTICMAIL_API_KEY` | `''` | Agent API key |
24
+ | `AGENTICMAIL_MASTER_KEY` | `''` | Master key (for admin tools) |
25
+
26
+ ## API Request Function
27
+
28
+ ```typescript
29
+ async function apiRequest(
30
+ method: string,
31
+ path: string,
32
+ body?: unknown,
33
+ useMasterKey = false,
34
+ timeoutMs = 30_000
35
+ ): Promise<any>
36
+ ```
37
+
38
+ - Base URL: `${API_URL}/api/agenticmail${path}`
39
+ - Auth: `Authorization: Bearer ${useMasterKey && MASTER_KEY ? MASTER_KEY : API_KEY}`
40
+ - Content-Type: `application/json` (only when body provided)
41
+ - Timeout: `AbortSignal.timeout(timeoutMs)`
42
+ - Error: Reads response text, throws `Error: API error {status}: {text}`
43
+ - Response: Parses JSON if Content-Type includes `application/json`, returns `null` otherwise
44
+
45
+ ## Master Key Tools
46
+
47
+ These tools automatically use the master key instead of the agent key:
48
+
49
+ ```
50
+ create_account, setup_email_relay, setup_email_domain, setup_guide,
51
+ setup_gmail_alias, setup_payment, purchase_domain, check_gateway_status,
52
+ send_test_email, delete_agent, deletion_reports, cleanup_agents
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Tool Definitions
58
+
59
+ ### send_email
60
+
61
+ Send email from agent's mailbox. External emails scanned for sensitive content.
62
+
63
+ **Input Schema:**
64
+ | Field | Type | Required | Description |
65
+ |-------|------|----------|-------------|
66
+ | `to` | string | Yes | Recipient email |
67
+ | `subject` | string | Yes | Email subject |
68
+ | `text` | string | No | Plain text body |
69
+ | `html` | string | No | HTML body |
70
+ | `cc` | string | No | CC recipients |
71
+ | `inReplyTo` | string | No | Message-ID for threading |
72
+ | `references` | string | No | Reference chain |
73
+ | `attachments` | array | No | File attachments |
74
+
75
+ **Attachment schema:** `{ filename: string, content: string (required), contentType: string, encoding: string }`
76
+
77
+ **Behavior:**
78
+ - Posts to `POST /mail/send`
79
+ - If blocked: Returns pending ID, schedules follow-up reminders
80
+ - If sent with warnings: Returns message ID + warnings
81
+ - If clean: Returns message ID
82
+
83
+ ---
84
+
85
+ ### list_inbox
86
+
87
+ **Input Schema:**
88
+ | Field | Type | Required | Default | Range |
89
+ |-------|------|----------|---------|-------|
90
+ | `limit` | number | No | 20 | 1–100 |
91
+ | `offset` | number | No | 0 | 0+ |
92
+
93
+ **Behavior:** `GET /mail/inbox?limit=N&offset=N`
94
+
95
+ **Response format:** `"UID: {uid} | From: {address} | Subject: {subject} | Date: {date}"` per message.
96
+
97
+ ---
98
+
99
+ ### read_email
100
+
101
+ **Input Schema:**
102
+ | Field | Type | Required |
103
+ |-------|------|----------|
104
+ | `uid` | number | Yes (positive integer) |
105
+
106
+ **Behavior:** `GET /mail/messages/{uid}`
107
+
108
+ **Response format:** Multi-line with From, To, Subject, Date, Message-ID, In-Reply-To, body text, attachments list, security section (spam score, sanitization, attachment warnings, phishing alerts).
109
+
110
+ **Security section includes:**
111
+ - `[SPAM]` or `[WARNING]` with score and category
112
+ - `[SANITIZED]` with detection types
113
+ - Attachment risk levels: `[CRITICAL]` (double extensions), `[HIGH]` (executables, HTML), `[MEDIUM]` (archives)
114
+ - Phishing rule matches: `ph_mismatched_display_url`, `ph_data_uri`, `ph_homograph`, `ph_spoofed_sender`, `de_webhook_exfil`, `pi_invisible_unicode`
115
+
116
+ ---
117
+
118
+ ### reply_email
119
+
120
+ **Input Schema:**
121
+ | Field | Type | Required | Default |
122
+ |-------|------|----------|---------|
123
+ | `uid` | number | Yes | — |
124
+ | `text` | string | Yes | — |
125
+ | `html` | string | No | — |
126
+ | `replyAll` | boolean | No | false |
127
+
128
+ **Behavior:**
129
+ 1. `GET /mail/messages/{uid}` — fetch original
130
+ 2. Build reply: `Re: {subject}`, `In-Reply-To: {messageId}`, `References: {chain}`
131
+ 3. If `replyAll`: includes all original recipients
132
+ 4. Appends quoted body: `\n\n--- Original message ---\n{original text}`
133
+ 5. `POST /mail/send` with threading headers
134
+
135
+ ---
136
+
137
+ ### forward_email
138
+
139
+ **Input Schema:**
140
+ | Field | Type | Required |
141
+ |-------|------|----------|
142
+ | `uid` | number | Yes |
143
+ | `to` | string | Yes |
144
+ | `text` | string | No |
145
+
146
+ **Behavior:**
147
+ 1. Fetch original message
148
+ 2. Build forward: `Fwd: {subject}`
149
+ 3. Body: `{optional text}\n\n--- Forwarded message ---\n{original text}`
150
+ 4. Preserves original attachments as base64
151
+ 5. `POST /mail/send`
152
+
153
+ ---
154
+
155
+ ### search_emails
156
+
157
+ **Input Schema:**
158
+ | Field | Type | Required | Description |
159
+ |-------|------|----------|-------------|
160
+ | `from` | string | No | Sender filter |
161
+ | `to` | string | No | Recipient filter |
162
+ | `subject` | string | No | Subject filter |
163
+ | `text` | string | No | Body text search |
164
+ | `since` | string | No | ISO 8601 date (after) |
165
+ | `before` | string | No | ISO 8601 date (before) |
166
+ | `seen` | boolean | No | Read status filter |
167
+ | `searchRelay` | boolean | No | Also search relay account (default: false) |
168
+
169
+ **Behavior:** `POST /mail/search`
170
+
171
+ **Response:** Local UIDs + relay results (if enabled) with `uid, source, account, messageId, subject, from, to, date, flags`.
172
+
173
+ ---
174
+
175
+ ### import_relay_email
176
+
177
+ **Input Schema:**
178
+ | Field | Type | Required |
179
+ |-------|------|----------|
180
+ | `uid` | number | Yes |
181
+
182
+ **Behavior:** `POST /mail/import-relay` — imports email from connected relay into local inbox.
183
+
184
+ ---
185
+
186
+ ### delete_email
187
+
188
+ **Input Schema:** `{ uid: number (required, positive integer) }`
189
+
190
+ **Behavior:** `DELETE /mail/messages/{uid}`
191
+
192
+ ---
193
+
194
+ ### move_email
195
+
196
+ **Input Schema:**
197
+ | Field | Type | Required | Default |
198
+ |-------|------|----------|---------|
199
+ | `uid` | number | Yes | — |
200
+ | `to` | string | Yes | — |
201
+ | `from` | string | No | "INBOX" |
202
+
203
+ **Behavior:** `POST /mail/messages/{uid}/move`
204
+
205
+ ---
206
+
207
+ ### mark_read
208
+
209
+ **Input Schema:** `{ uid: number (required) }`
210
+
211
+ **Behavior:** `POST /mail/messages/{uid}/seen`
212
+
213
+ ---
214
+
215
+ ### mark_unread
216
+
217
+ **Input Schema:** `{ uid: number (required) }`
218
+
219
+ **Behavior:** `POST /mail/messages/{uid}/unseen`
220
+
221
+ ---
222
+
223
+ ### inbox_digest
224
+
225
+ **Input Schema:**
226
+ | Field | Type | Default | Range |
227
+ |-------|------|---------|-------|
228
+ | `limit` | number | 20 | 1–50 |
229
+ | `offset` | number | 0 | 0+ |
230
+ | `folder` | string | "INBOX" | — |
231
+ | `previewLength` | number | 200 | 50–500 |
232
+
233
+ **Behavior:** `GET /mail/digest?limit=N&offset=N&folder=F&previewLength=N`
234
+
235
+ **Response format:** Compact digest with `[*]` for unread, `[r]` for read, sender, subject, date, and text preview.
236
+
237
+ ---
238
+
239
+ ### wait_for_email
240
+
241
+ **Input Schema:**
242
+ | Field | Type | Default | Range |
243
+ |-------|------|---------|-------|
244
+ | `timeout` | number | 120 | 1–300 seconds |
245
+
246
+ **Behavior:**
247
+ 1. Opens SSE connection to `GET /events`
248
+ 2. Listens for `new` (email) or `task` events
249
+ 3. Falls back to polling if SSE unavailable
250
+ 4. Uses `AbortController` for timeout
251
+
252
+ **Response:**
253
+ ```json
254
+ {
255
+ "arrived": true,
256
+ "mode": "push",
257
+ "eventType": "email",
258
+ "timedOut": false,
259
+ "uid": 123,
260
+ "subject": "...",
261
+ "from": "..."
262
+ }
263
+ ```
264
+
265
+ ---
266
+
267
+ ### list_folders
268
+
269
+ **Behavior:** `GET /mail/folders`
270
+
271
+ **Response:** Folder paths, one per line.
272
+
273
+ ---
274
+
275
+ ### list_folder
276
+
277
+ **Input Schema:**
278
+ | Field | Type | Required | Default | Range |
279
+ |-------|------|----------|---------|-------|
280
+ | `folder` | string | Yes | — | — |
281
+ | `limit` | number | No | 20 | 1–100 |
282
+ | `offset` | number | No | 0 | 0+ |
283
+
284
+ **Behavior:** `GET /mail/folders/{folder}?limit=N&offset=N`
285
+
286
+ ---
287
+
288
+ ### Batch Operations
289
+
290
+ All batch tools validate: `Array.isArray(uids) && uids.length > 0`
291
+
292
+ **batch_delete:** `{ uids: number[], folder?: string }` → `POST /mail/batch/delete`
293
+
294
+ **batch_mark_read:** `{ uids: number[], folder?: string }` → `POST /mail/batch/seen`
295
+
296
+ **batch_mark_unread:** `{ uids: number[], folder?: string }` → `POST /mail/batch/unseen`
297
+
298
+ **batch_move:** `{ uids: number[], to: string, from?: string }` → `POST /mail/batch/move`
299
+
300
+ **batch_read:** `{ uids: number[], folder?: string }` → `POST /mail/batch/read`
301
+ Returns 500-char preview per message.
302
+
303
+ ---
304
+
305
+ ### manage_contacts
306
+
307
+ **Input Schema:**
308
+ | Field | Type | Required |
309
+ |-------|------|----------|
310
+ | `action` | "list" \| "add" \| "delete" | Yes |
311
+ | `email` | string | For "add" |
312
+ | `name` | string | No (for "add") |
313
+ | `id` | string | For "delete" |
314
+
315
+ **API calls:** `GET /contacts`, `POST /contacts`, `DELETE /contacts/{id}`
316
+
317
+ ---
318
+
319
+ ### manage_drafts
320
+
321
+ **Input Schema:**
322
+ | Field | Type | Required |
323
+ |-------|------|----------|
324
+ | `action` | "list" \| "create" \| "update" \| "send" \| "delete" | Yes |
325
+ | `to` | string | For "create" |
326
+ | `subject` | string | For "create" |
327
+ | `text` | string | For "create"/"update" |
328
+ | `html` | string | No |
329
+ | `id` | string | For "update"/"send"/"delete" |
330
+
331
+ **API calls:** `GET /drafts`, `POST /drafts`, `PUT /drafts/{id}`, `POST /drafts/{id}/send`, `DELETE /drafts/{id}`
332
+
333
+ ---
334
+
335
+ ### manage_signatures
336
+
337
+ **Input Schema:**
338
+ | Field | Type | Required |
339
+ |-------|------|----------|
340
+ | `action` | "list" \| "create" \| "delete" | Yes |
341
+ | `name` | string | For "create" |
342
+ | `text` | string | For "create" |
343
+ | `isDefault` | boolean | No |
344
+ | `id` | string | For "delete" |
345
+
346
+ **API calls:** `GET /signatures`, `POST /signatures`, `DELETE /signatures/{id}`
347
+
348
+ ---
349
+
350
+ ### manage_templates
351
+
352
+ **Input Schema:**
353
+ | Field | Type | Required |
354
+ |-------|------|----------|
355
+ | `action` | "list" \| "create" \| "delete" | Yes |
356
+ | `name` | string | For "create" |
357
+ | `subject` | string | For "create" |
358
+ | `text` | string | For "create" |
359
+ | `id` | string | For "delete" |
360
+
361
+ **API calls:** `GET /templates`, `POST /templates`, `DELETE /templates/{id}`
362
+
363
+ ---
364
+
365
+ ### template_send
366
+
367
+ **Input Schema:**
368
+ | Field | Type | Required |
369
+ |-------|------|----------|
370
+ | `id` | string | Yes |
371
+ | `to` | string | Yes |
372
+ | `variables` | object | No |
373
+ | `cc` | string | No |
374
+ | `bcc` | string | No |
375
+
376
+ **Behavior:** `POST /templates/{id}/send`
377
+
378
+ Replaces `{{ variableName }}` patterns in subject and body.
379
+
380
+ ---
381
+
382
+ ### manage_scheduled
383
+
384
+ **Input Schema:**
385
+ | Field | Type | Required |
386
+ |-------|------|----------|
387
+ | `action` | "create" \| "list" \| "cancel" | Yes |
388
+ | `to` | string | For "create" |
389
+ | `subject` | string | For "create" |
390
+ | `text` | string | For "create" |
391
+ | `sendAt` | string | For "create" |
392
+ | `html` | string | No |
393
+ | `cc` | string | No |
394
+ | `bcc` | string | No |
395
+ | `id` | string | For "cancel" |
396
+
397
+ **Supported `sendAt` formats:** ISO 8601, relative (`in 30 minutes`), named (`tomorrow 8am`), day-based (`next monday 9am`), human (`02-14-2026 3:30 PM EST`), casual (`tonight`).
398
+
399
+ ---
400
+
401
+ ### manage_tags
402
+
403
+ **Input Schema:**
404
+ | Field | Type | Required |
405
+ |-------|------|----------|
406
+ | `action` | "list" \| "create" \| "delete" \| "tag_message" \| "untag_message" \| "get_messages" \| "get_message_tags" | Yes |
407
+ | `name` | string | For "create" |
408
+ | `color` | string | No (hex, for "create") |
409
+ | `id` | string | For "delete"/"tag_message"/"untag_message"/"get_messages" |
410
+ | `uid` | number | For "tag_message"/"untag_message"/"get_message_tags" |
411
+ | `folder` | string | No (for message operations) |
412
+
413
+ **API calls:** `GET /tags`, `POST /tags`, `DELETE /tags/{id}`, `POST /tags/{id}/messages`, `DELETE /tags/{id}/messages/{uid}`, `GET /tags/{id}/messages`, `GET /messages/{uid}/tags`
414
+
415
+ ---
416
+
417
+ ### manage_rules
418
+
419
+ **Input Schema:**
420
+ | Field | Type | Required |
421
+ |-------|------|----------|
422
+ | `action` | "list" \| "create" \| "delete" | Yes |
423
+ | `name` | string | For "create" |
424
+ | `priority` | number | No (for "create") |
425
+ | `conditions` | object | For "create" |
426
+ | `actions` | object | For "create" |
427
+ | `id` | string | For "delete" |
428
+
429
+ **Conditions:** `from_contains`, `subject_contains`, `subject_regex`, `to_contains`, `has_attachment`
430
+
431
+ **Actions:** `move_to`, `mark_read`, `delete`, `add_tags`
432
+
433
+ ---
434
+
435
+ ### manage_spam
436
+
437
+ **Input Schema:**
438
+ | Field | Type | Required |
439
+ |-------|------|----------|
440
+ | `action` | "list" \| "report" \| "not_spam" \| "score" | Yes |
441
+ | `uid` | number | For "report"/"not_spam"/"score" |
442
+ | `folder` | string | No (for "report"/"score") |
443
+ | `limit` | number | No (for "list") |
444
+ | `offset` | number | No (for "list") |
445
+
446
+ **API calls:** `GET /mail/spam`, `POST /mail/messages/{uid}/spam`, `POST /mail/messages/{uid}/not-spam`, `GET /mail/messages/{uid}/spam-score`
447
+
448
+ ---
449
+
450
+ ### manage_pending_emails
451
+
452
+ **Input Schema:**
453
+ | Field | Type | Required |
454
+ |-------|------|----------|
455
+ | `action` | "list" \| "view" \| "approve" \| "reject" | Yes |
456
+ | `id` | string | For "view"/"approve"/"reject" |
457
+
458
+ **Critical:** `approve` and `reject` actions are **explicitly blocked** — returns error message directing agent to notify the owner.
459
+
460
+ **API calls:** `GET /mail/pending`, `GET /mail/pending/{id}`
461
+
462
+ ---
463
+
464
+ ### create_folder
465
+
466
+ **Input Schema:** `{ name: string (required) }`
467
+
468
+ **Behavior:** `POST /mail/folders`
469
+
470
+ ---
471
+
472
+ ### check_health
473
+
474
+ **Behavior:** `GET /health`
475
+
476
+ **Response:** Status message with API and Stalwart status.
477
+
478
+ ---
479
+
480
+ ### create_account
481
+
482
+ **Master key required.**
483
+
484
+ **Input Schema:**
485
+ | Field | Type | Required | Description |
486
+ |-------|------|----------|-------------|
487
+ | `name` | string | Yes | Agent name |
488
+ | `domain` | string | No | Default: localhost |
489
+ | `role` | enum | No | secretary, assistant, researcher, writer, custom |
490
+
491
+ **Behavior:** `POST /accounts`
492
+
493
+ ---
494
+
495
+ ### delete_agent
496
+
497
+ **Master key required.**
498
+
499
+ **Input Schema:**
500
+ | Field | Type | Required |
501
+ |-------|------|----------|
502
+ | `name` | string | Yes |
503
+ | `reason` | string | No |
504
+
505
+ **Behavior:** Looks up agent by name, calls `DELETE /accounts/{id}?archive=true&reason={}&deletedBy=agent`
506
+
507
+ ---
508
+
509
+ ### deletion_reports
510
+
511
+ **Master key required.**
512
+
513
+ **Input Schema:**
514
+ | Field | Type | Required |
515
+ |-------|------|----------|
516
+ | `id` | string | No (specific report) |
517
+
518
+ **Behavior:** `GET /accounts/deletions` or `GET /accounts/deletions/{id}`
519
+
520
+ ---
521
+
522
+ ### cleanup_agents
523
+
524
+ **Master key required.**
525
+
526
+ **Input Schema:**
527
+ | Field | Type | Required |
528
+ |-------|------|----------|
529
+ | `action` | "list_inactive" \| "cleanup" \| "set_persistent" | Yes |
530
+ | `hours` | number | No (for list/cleanup) |
531
+ | `dryRun` | boolean | No (for cleanup) |
532
+ | `agentId` | string | For "set_persistent" |
533
+ | `persistent` | boolean | For "set_persistent" |
534
+
535
+ ---
536
+
537
+ ### whoami
538
+
539
+ **Behavior:** `GET /accounts/me`
540
+
541
+ **Response:** Name, email, role, ID, created date, metadata.
542
+
543
+ ---
544
+
545
+ ### update_metadata
546
+
547
+ **Input Schema:** `{ metadata: object (required) }`
548
+
549
+ **Behavior:** `PATCH /accounts/me`
550
+
551
+ ---
552
+
553
+ ### list_agents
554
+
555
+ **Behavior:** `GET /accounts/directory`
556
+
557
+ ---
558
+
559
+ ### message_agent
560
+
561
+ **Input Schema:**
562
+ | Field | Type | Required | Description |
563
+ |-------|------|----------|-------------|
564
+ | `agent` | string | Yes | Target agent name |
565
+ | `subject` | string | Yes | Email subject |
566
+ | `text` | string | Yes | Message body |
567
+ | `priority` | enum | No | normal, high, urgent |
568
+
569
+ **Behavior:**
570
+ 1. `GET /accounts/directory/{agent}` — validate target exists
571
+ 2. If priority=high: prefix `[HIGH] `
572
+ 3. If priority=urgent: prefix `[URGENT] `
573
+ 4. `POST /mail/send` to `{agent}@localhost`
574
+
575
+ ---
576
+
577
+ ### check_messages
578
+
579
+ **Behavior:** `GET /mail/inbox?limit=10`
580
+
581
+ **Response:** Summary of unread messages, tagged as `[agent]` or `[external]`.
582
+
583
+ ---
584
+
585
+ ### assign_task
586
+
587
+ **Input Schema:**
588
+ | Field | Type | Required | Default |
589
+ |-------|------|----------|---------|
590
+ | `assignee` | string | Yes | — |
591
+ | `taskType` | string | No | "generic" |
592
+ | `payload` | object | No | — |
593
+ | `expiresInSeconds` | number | No | — |
594
+
595
+ **Behavior:** `POST /tasks/assign`
596
+
597
+ ---
598
+
599
+ ### check_tasks
600
+
601
+ **Input Schema:**
602
+ | Field | Type | Required |
603
+ |-------|------|----------|
604
+ | `direction` | "incoming" \| "outgoing" | Yes |
605
+ | `assignee` | string | No (for incoming only) |
606
+
607
+ **Behavior:** `GET /tasks/pending?assignee={name}` or `GET /tasks/assigned`
608
+
609
+ ---
610
+
611
+ ### claim_task
612
+
613
+ **Input Schema:** `{ id: string (required) }`
614
+
615
+ **Behavior:** `POST /tasks/{id}/claim`
616
+
617
+ ---
618
+
619
+ ### submit_result
620
+
621
+ **Input Schema:**
622
+ | Field | Type | Required |
623
+ |-------|------|----------|
624
+ | `id` | string | Yes |
625
+ | `result` | object | No |
626
+
627
+ **Behavior:** `POST /tasks/{id}/result`
628
+
629
+ ---
630
+
631
+ ### call_agent
632
+
633
+ **Input Schema:**
634
+ | Field | Type | Required | Default | Range |
635
+ |-------|------|----------|---------|-------|
636
+ | `target` | string | Yes | — | — |
637
+ | `task` | string | Yes | — | — |
638
+ | `payload` | object | No | — | — |
639
+ | `timeout` | number | No | 180 | 5–300 seconds |
640
+
641
+ **Behavior:** `POST /tasks/rpc` — holds connection open, returns result or timeout.
642
+
643
+ ---
644
+
645
+ ### Gateway Tools
646
+
647
+ **setup_email_relay** (master):
648
+ ```
649
+ { provider: "gmail"|"outlook"|"custom", email: string, password: string,
650
+ smtpHost?: string, smtpPort?: number, imapHost?: string, imapPort?: number,
651
+ agentName?: string, agentRole?: string, skipDefaultAgent?: boolean }
652
+ ```
653
+
654
+ **setup_email_domain** (master):
655
+ ```
656
+ { cloudflareToken: string, cloudflareAccountId: string,
657
+ domain?: string, purchase?: { keywords: string[], tld?: string },
658
+ gmailRelay?: { email: string, appPassword: string } }
659
+ ```
660
+
661
+ **setup_gmail_alias** (master):
662
+ ```
663
+ { agentEmail: string, agentDisplayName?: string }
664
+ ```
665
+
666
+ **setup_guide** (master): No input.
667
+
668
+ **setup_payment** (master): No input.
669
+
670
+ **purchase_domain** (master):
671
+ ```
672
+ { keywords: string[], tld?: string }
673
+ ```
674
+
675
+ **check_gateway_status** (master): No input.
676
+
677
+ **send_test_email** (master):
678
+ ```
679
+ { to: string }
680
+ ```
681
+
682
+ ---
683
+
684
+ ## Outbound Guard Rules
685
+
686
+ ### PII Detection (18 rules)
687
+
688
+ | Rule ID | Severity | Pattern |
689
+ |---------|----------|---------|
690
+ | `ob_ssn` | HIGH | `\b\d{3}-\d{2}-\d{4}\b` |
691
+ | `ob_ssn_obfuscated` | HIGH | Obfuscated SSN variants |
692
+ | `ob_credit_card` | HIGH | `\b(?:\d{4}[-\s]?){3}\d{4}\b` |
693
+ | `ob_phone` | MEDIUM | Phone number patterns |
694
+ | `ob_bank_routing` | HIGH | Routing/account numbers |
695
+ | `ob_drivers_license` | HIGH | Driver's license patterns |
696
+ | `ob_dob` | MEDIUM | Date of birth with keywords |
697
+ | `ob_passport` | HIGH | Passport numbers |
698
+ | `ob_tax_id` | HIGH | EIN/TIN patterns |
699
+ | `ob_itin` | HIGH | ITIN patterns |
700
+ | `ob_medicare` | HIGH | Medicare/Medicaid IDs |
701
+ | `ob_immigration` | HIGH | Immigration A-numbers |
702
+ | `ob_pin` | MEDIUM | PIN codes |
703
+ | `ob_security_qa` | MEDIUM | Security Q&A patterns |
704
+ | `ob_iban` | HIGH | IBAN patterns |
705
+ | `ob_swift` | MEDIUM | SWIFT/BIC codes |
706
+ | `ob_crypto_wallet` | HIGH | BTC/ETH/XMR wallet addresses |
707
+ | `ob_wire_transfer` | HIGH | Wire transfer instructions |
708
+
709
+ ### Credential Detection (19 rules)
710
+
711
+ | Rule ID | Severity | Pattern |
712
+ |---------|----------|---------|
713
+ | `ob_api_key` | HIGH | API key patterns |
714
+ | `ob_aws_key` | HIGH | `AKIA[A-Z0-9]{16}` |
715
+ | `ob_password_value` | HIGH | Password field patterns |
716
+ | `ob_private_key` | HIGH | PEM private key headers |
717
+ | `ob_bearer_token` | HIGH | Bearer token patterns |
718
+ | `ob_connection_string` | HIGH | DB connection strings |
719
+ | `ob_github_token` | HIGH | GitHub token patterns |
720
+ | `ob_stripe_key` | HIGH | Stripe key patterns |
721
+ | `ob_jwt` | HIGH | JWT token patterns |
722
+ | `ob_webhook_url` | HIGH | Slack/Discord webhook URLs |
723
+ | `ob_env_block` | HIGH | Consecutive ENV variable lines |
724
+ | `ob_seed_phrase` | HIGH | Crypto seed/recovery phrases |
725
+ | `ob_2fa_codes` | HIGH | 2FA backup codes |
726
+ | `ob_credential_pair` | HIGH | Username+password pairs |
727
+ | `ob_oauth_token` | HIGH | OAuth tokens |
728
+ | `ob_vpn_creds` | HIGH | VPN credentials |
729
+
730
+ ### System Internals (3 rules)
731
+
732
+ | Rule ID | Severity | Pattern |
733
+ |---------|----------|---------|
734
+ | `ob_private_ip` | MEDIUM | Private IP ranges (10.x, 172.16-31.x, 192.168.x) |
735
+ | `ob_file_path` | MEDIUM | File paths (/home, /Users, /etc, C:\\) |
736
+ | `ob_env_variable` | MEDIUM | Environment variable assignments |
737
+
738
+ ### Owner Privacy (2 rules)
739
+
740
+ | Rule ID | Severity | Pattern |
741
+ |---------|----------|---------|
742
+ | `ob_owner_info` | HIGH | Mentions of owner's personal info |
743
+ | `ob_personal_reveal` | HIGH | Reveals about agent's creator/operator |
744
+
745
+ ### Attachment Risk
746
+
747
+ | Risk Level | Extensions |
748
+ |------------|------------|
749
+ | HIGH (keys) | `.pem`, `.key`, `.p12`, `.pfx`, `.env`, `.credentials`, `.keystore`, `.jks`, `.p8` |
750
+ | MEDIUM (data) | `.db`, `.sqlite`, `.sqlite3`, `.sql`, `.csv`, `.tsv`, `.json`, `.yml`, `.yaml`, `.conf`, `.config`, `.ini` |
751
+ | HIGH (exec) | `.exe`, `.bat`, `.cmd`, `.ps1`, `.sh`, `.msi`, `.scr`, `.com`, `.vbs`, `.js`, `.wsf`, `.hta`, `.cpl`, `.jar`, `.app`, `.dmg`, `.run` |
752
+ | MEDIUM (archive) | `.zip`, `.rar`, `.7z`, `.tar`, `.gz`, `.bz2`, `.xz`, `.cab`, `.iso` |
753
+ | CRITICAL | Double extensions (e.g., `.pdf.exe`) |
754
+
755
+ ---
756
+
757
+ ## Pending Email Follow-Up System
758
+
759
+ ### Schedule
760
+
761
+ | Step | Delay | Description |
762
+ |------|-------|-------------|
763
+ | 0 | 12 hours | First reminder |
764
+ | 1 | 6 hours | Second reminder |
765
+ | 2 | 3 hours | Third reminder |
766
+ | 3 | 1 hour | Final reminder before cooldown |
767
+ | — | 3 days | Cooldown period |
768
+ | 4+ | Repeat cycle | Re-starts from 12 hours |
769
+
770
+ ### Heartbeat
771
+
772
+ Every 5 minutes, checks all tracked pending emails. If externally resolved, cancels reminders.
773
+
774
+ ### API
775
+
776
+ | Function | Description |
777
+ |----------|-------------|
778
+ | `scheduleFollowUp(pendingId, recipient, subject, checkFn)` | Start follow-ups |
779
+ | `drainFollowUps()` | Get and clear queued notifications |
780
+ | `cancelFollowUp(pendingId)` | Cancel specific email follow-ups |
781
+ | `cancelAllFollowUps()` | Cancel all follow-ups |
782
+ | `activeFollowUpCount()` | Count tracked emails |
783
+
784
+ ### Message Templates
785
+
786
+ **Interim (steps 0–2):**
787
+ ```
788
+ [FOLLOW-UP REMINDER {step+1}/{4}]
789
+ Your blocked email to {recipient} (subject: "{subject}") is still pending owner approval.
790
+ Please follow up with your owner — ask if they've reviewed the notification email.
791
+ Next reminder in {nextDelayH} hour(s).
792
+ Pending ID: {pendingId}
793
+ ```
794
+
795
+ **Final (step 3):**
796
+ ```
797
+ [FINAL FOLLOW-UP]
798
+ Your blocked email to {recipient} (subject: "{subject}") is STILL pending approval.
799
+ This is the last reminder before a 3-day cooldown. Please urgently remind your owner.
800
+ Pending ID: {pendingId}
801
+ ```
802
+
803
+ **Cycle restart (after cooldown):**
804
+ ```
805
+ [FOLLOW-UP REMINDER — cycle {cycle+2}]
806
+ Your blocked email to {recipient} has been pending for over {totalDays} days.
807
+ Starting a new follow-up cycle. Please remind your owner.
808
+ Pending ID: {pendingId}
809
+ ```
810
+
811
+ ---
812
+
813
+ ## Resources
814
+
815
+ | URI | Name | MIME Type | Description |
816
+ |-----|------|-----------|-------------|
817
+ | `agenticmail://inbox` | Agent Inbox | `text/plain` | 20 most recent inbox messages |
818
+
819
+ **Format:** `{index}. UID: {uid} | From: {address} | Subject: {subject} | Date: {date}`
820
+
821
+ ---
822
+
823
+ ## Constants Summary
824
+
825
+ | Constant | Value |
826
+ |----------|-------|
827
+ | Default API URL | `http://127.0.0.1:3100` |
828
+ | API request timeout | 30,000ms |
829
+ | list_inbox max limit | 100 |
830
+ | list_folder max limit | 100 |
831
+ | inbox_digest max limit | 50 |
832
+ | inbox_digest max preview | 500 chars |
833
+ | wait_for_email max timeout | 300 seconds |
834
+ | wait_for_email default timeout | 120 seconds |
835
+ | call_agent max timeout | 300 seconds |
836
+ | call_agent default timeout | 180 seconds |
837
+ | batch_read preview length | 500 chars |
838
+ | Follow-up step delays | [12h, 6h, 3h, 1h] |
839
+ | Follow-up cooldown | 3 days (259,200,000ms) |
840
+ | Follow-up heartbeat | 5 minutes |
841
+
842
+ ---
843
+
844
+ ## Signal Handlers
845
+
846
+ | Signal | Action |
847
+ |--------|--------|
848
+ | `SIGTERM` | Close server, exit 0 |
849
+ | `SIGINT` | Close server, exit 0 |
850
+
851
+ Shutdown errors are silently ignored.
852
+
853
+ ---
854
+
855
+ ## License
856
+
857
+ [MIT](./LICENSE) - Ope Olatunji ([@ope-olatunji](https://github.com/ope-olatunji))