icloud-mcp 1.1.0 ā 1.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/README.md +30 -16
- package/index.js +221 -82
- package/package.json +1 -1
- package/test.js +98 -9
package/README.md
CHANGED
|
@@ -5,13 +5,14 @@ A Model Context Protocol (MCP) server that connects Claude Desktop to your iClou
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- š¬ Read and paginate through your inbox
|
|
8
|
-
- š Search emails by keyword, sender,
|
|
8
|
+
- š Search emails by keyword, sender, date range, and more
|
|
9
9
|
- šļø Bulk delete emails by any combination of filters
|
|
10
10
|
- š Bulk move emails between folders with flexible filtering
|
|
11
11
|
- š Analyze top senders to identify inbox clutter
|
|
12
12
|
- š¢ Count emails matching any filter before taking action
|
|
13
|
-
- ā
Mark emails as read/unread, flag/unflag
|
|
14
|
-
- šļø List and
|
|
13
|
+
- ā
Mark emails as read/unread, flag/unflag in bulk or individually
|
|
14
|
+
- šļø List, create, rename, and delete mailboxes
|
|
15
|
+
- š Dry run mode for bulk operations ā preview before committing
|
|
15
16
|
|
|
16
17
|
## Prerequisites
|
|
17
18
|
|
|
@@ -77,33 +78,38 @@ Fully quit Claude Desktop (Cmd+Q) and reopen it. You should now be able to manag
|
|
|
77
78
|
|
|
78
79
|
| Tool | Description |
|
|
79
80
|
|------|-------------|
|
|
80
|
-
| `get_inbox_summary` | Total, unread, and recent email counts |
|
|
81
|
-
| `
|
|
81
|
+
| `get_inbox_summary` | Total, unread, and recent email counts for INBOX |
|
|
82
|
+
| `get_mailbox_summary` | Total, unread, and recent email counts for any folder |
|
|
83
|
+
| `get_top_senders` | Top senders by volume from a sample of recent emails (supports `sampleSize` and `maxResults`) |
|
|
82
84
|
| `get_unread_senders` | Top senders of unread emails (supports `sampleSize` and `maxResults`) |
|
|
83
85
|
| `read_inbox` | Paginated inbox with sender, subject, date |
|
|
84
86
|
| `get_email` | Full content of a specific email by UID |
|
|
85
87
|
| `get_emails_by_sender` | All emails from a specific address |
|
|
86
88
|
| `get_emails_by_date_range` | Emails between two dates |
|
|
87
|
-
| `search_emails` | Search by keyword
|
|
89
|
+
| `search_emails` | Search by keyword with optional filters (date, unread, domain, etc.) |
|
|
88
90
|
| `count_emails` | Count emails matching any combination of filters without modifying them |
|
|
89
|
-
| `bulk_move` | Move emails matching any combination of filters between folders |
|
|
90
|
-
| `bulk_delete` | Delete emails matching any combination of filters |
|
|
91
|
-
| `
|
|
92
|
-
| `
|
|
93
|
-
| `
|
|
91
|
+
| `bulk_move` | Move emails matching any combination of filters between folders (supports `dryRun`) |
|
|
92
|
+
| `bulk_delete` | Delete emails matching any combination of filters (supports `dryRun`) |
|
|
93
|
+
| `bulk_flag` | Flag or unflag emails matching any combination of filters |
|
|
94
|
+
| `bulk_mark_read` | Mark all emails (or all from a sender) as read |
|
|
95
|
+
| `bulk_mark_unread` | Mark all emails (or all from a sender) as unread |
|
|
94
96
|
| `bulk_delete_by_sender` | Delete all emails from a sender |
|
|
95
97
|
| `bulk_delete_by_subject` | Delete all emails matching a subject keyword |
|
|
96
98
|
| `bulk_move_by_sender` | Move all emails from a sender to a folder |
|
|
97
|
-
| `
|
|
98
|
-
| `
|
|
99
|
+
| `flag_email` | Flag or unflag a single email |
|
|
100
|
+
| `mark_as_read` | Mark a single email as read or unread |
|
|
101
|
+
| `delete_email` | Move an email to Deleted Messages |
|
|
99
102
|
| `move_email` | Move a single email to a folder |
|
|
103
|
+
| `delete_older_than` | Delete all emails older than N days |
|
|
100
104
|
| `list_mailboxes` | List all folders in your iCloud Mail |
|
|
101
105
|
| `create_mailbox` | Create a new folder |
|
|
106
|
+
| `rename_mailbox` | Rename an existing folder |
|
|
107
|
+
| `delete_mailbox` | Delete a folder (must be empty first) |
|
|
102
108
|
| `empty_trash` | Permanently delete all emails in Deleted Messages |
|
|
103
109
|
|
|
104
|
-
## Bulk Move &
|
|
110
|
+
## Bulk Move, Delete & Flag Filters
|
|
105
111
|
|
|
106
|
-
`bulk_move` and `
|
|
112
|
+
`bulk_move`, `bulk_delete`, `bulk_flag`, `search_emails`, and `count_emails` all accept any combination of these filters:
|
|
107
113
|
|
|
108
114
|
| Filter | Type | Description |
|
|
109
115
|
|--------|------|-------------|
|
|
@@ -118,17 +124,25 @@ Fully quit Claude Desktop (Cmd+Q) and reopen it. You should now be able to manag
|
|
|
118
124
|
| `smaller` | number | Only emails smaller than this size in KB |
|
|
119
125
|
| `hasAttachment` | boolean | Only emails with attachments |
|
|
120
126
|
|
|
127
|
+
### Dry Run Mode
|
|
128
|
+
|
|
129
|
+
Pass `dryRun: true` to `bulk_move` or `bulk_delete` to preview how many emails would be affected without making any changes:
|
|
130
|
+
|
|
131
|
+
> *"How many emails would be deleted if I removed everything from linkedin.com before 2022?"*
|
|
132
|
+
|
|
121
133
|
## Example Usage
|
|
122
134
|
|
|
123
135
|
Once configured, you can ask Claude things like:
|
|
124
136
|
|
|
125
137
|
- *"Show me the top senders in my iCloud inbox"*
|
|
126
138
|
- *"How many unread emails do I have from substack.com?"*
|
|
139
|
+
- *"How many emails would be moved if I archived everything from linkedin.com before 2022?"*
|
|
127
140
|
- *"Move all emails from substack.com older than 2023 to my Newsletters folder"*
|
|
128
141
|
- *"Delete all unread emails from linkedin.com before 2022"*
|
|
129
142
|
- *"Move everything in my old_folders/college folder to Archive"*
|
|
130
143
|
- *"How many emails do I have with attachments larger than 5MB?"*
|
|
131
|
-
- *"
|
|
144
|
+
- *"Flag all unread emails from my bank"*
|
|
145
|
+
- *"Rename my Newsletters folder to Old Newsletters"*
|
|
132
146
|
- *"Show me emails from the last week"*
|
|
133
147
|
|
|
134
148
|
## Security
|
package/index.js
CHANGED
|
@@ -84,7 +84,7 @@ async function getInboxSummary(mailbox = 'INBOX') {
|
|
|
84
84
|
return { mailbox, total: status.messages, unread: status.unseen, recent: status.recent };
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
async function getTopSenders(mailbox = 'INBOX', sampleSize = 500) {
|
|
87
|
+
async function getTopSenders(mailbox = 'INBOX', sampleSize = 500, maxResults = 20) {
|
|
88
88
|
const client = createClient();
|
|
89
89
|
await client.connect();
|
|
90
90
|
const mb = await client.mailboxOpen(mailbox);
|
|
@@ -108,8 +108,8 @@ async function getTopSenders(mailbox = 'INBOX', sampleSize = 500) {
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
await client.logout();
|
|
111
|
-
const topAddresses = Object.entries(senderCounts).sort((a, b) => b[1] - a[1]).slice(0,
|
|
112
|
-
const topDomains = Object.entries(senderDomains).sort((a, b) => b[1] - a[1]).slice(0,
|
|
111
|
+
const topAddresses = Object.entries(senderCounts).sort((a, b) => b[1] - a[1]).slice(0, maxResults).map(([address, count]) => ({ address, count }));
|
|
112
|
+
const topDomains = Object.entries(senderDomains).sort((a, b) => b[1] - a[1]).slice(0, maxResults).map(([domain, count]) => ({ domain, count }));
|
|
113
113
|
return { sampledEmails: count, topAddresses, topDomains };
|
|
114
114
|
}
|
|
115
115
|
|
|
@@ -126,7 +126,6 @@ async function getUnreadSenders(mailbox = 'INBOX', sampleSize = 500, maxResults
|
|
|
126
126
|
return [];
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
// Fetch all envelopes in a single batch instead of one by one
|
|
130
129
|
for await (const msg of client.fetch(recentUids, { envelope: true }, { uid: true })) {
|
|
131
130
|
const address = msg.envelope.from?.[0]?.address;
|
|
132
131
|
if (address) senderCounts[address] = (senderCounts[address] || 0) + 1;
|
|
@@ -244,6 +243,34 @@ async function bulkMarkRead(mailbox = 'INBOX', sender = null) {
|
|
|
244
243
|
return { marked: uids.length, sender: sender || 'all' };
|
|
245
244
|
}
|
|
246
245
|
|
|
246
|
+
async function bulkMarkUnread(mailbox = 'INBOX', sender = null) {
|
|
247
|
+
const client = createClient();
|
|
248
|
+
await client.connect();
|
|
249
|
+
await client.mailboxOpen(mailbox);
|
|
250
|
+
const query = sender ? { from: sender, seen: true } : { seen: true };
|
|
251
|
+
const uids = (await client.search(query, { uid: true })) ?? [];
|
|
252
|
+
if (uids.length === 0) { await client.logout(); return { marked: 0 }; }
|
|
253
|
+
await client.messageFlagsRemove(uids, ['\\Seen'], { uid: true });
|
|
254
|
+
await client.logout();
|
|
255
|
+
return { marked: uids.length, sender: sender || 'all' };
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async function bulkFlag(filters, flagged, mailbox = 'INBOX') {
|
|
259
|
+
const client = createClient();
|
|
260
|
+
await client.connect();
|
|
261
|
+
await client.mailboxOpen(mailbox);
|
|
262
|
+
const query = buildQuery(filters);
|
|
263
|
+
const uids = (await client.search(query, { uid: true })) ?? [];
|
|
264
|
+
if (uids.length === 0) { await client.logout(); return { flagged: 0 }; }
|
|
265
|
+
if (flagged) {
|
|
266
|
+
await client.messageFlagsAdd(uids, ['\\Flagged'], { uid: true });
|
|
267
|
+
} else {
|
|
268
|
+
await client.messageFlagsRemove(uids, ['\\Flagged'], { uid: true });
|
|
269
|
+
}
|
|
270
|
+
await client.logout();
|
|
271
|
+
return { [flagged ? 'flagged' : 'unflagged']: uids.length, filters };
|
|
272
|
+
}
|
|
273
|
+
|
|
247
274
|
async function emptyTrash() {
|
|
248
275
|
const client = createClient();
|
|
249
276
|
await client.connect();
|
|
@@ -263,6 +290,30 @@ async function createMailbox(name) {
|
|
|
263
290
|
return { created: name };
|
|
264
291
|
}
|
|
265
292
|
|
|
293
|
+
async function renameMailbox(oldName, newName) {
|
|
294
|
+
const client = createClient();
|
|
295
|
+
await client.connect();
|
|
296
|
+
await client.mailboxRename(oldName, newName);
|
|
297
|
+
await client.logout();
|
|
298
|
+
return { renamed: { from: oldName, to: newName } };
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
async function deleteMailbox(name) {
|
|
302
|
+
const client = createClient();
|
|
303
|
+
await client.connect();
|
|
304
|
+
await client.mailboxDelete(name);
|
|
305
|
+
await client.logout();
|
|
306
|
+
return { deleted: name };
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
async function getMailboxSummary(mailbox) {
|
|
310
|
+
const client = createClient();
|
|
311
|
+
await client.connect();
|
|
312
|
+
const status = await client.status(mailbox, { messages: true, unseen: true, recent: true });
|
|
313
|
+
await client.logout();
|
|
314
|
+
return { mailbox, total: status.messages, unread: status.unseen, recent: status.recent };
|
|
315
|
+
}
|
|
316
|
+
|
|
266
317
|
async function getEmailContent(uid, mailbox = 'INBOX') {
|
|
267
318
|
const client = createClient();
|
|
268
319
|
await client.connect();
|
|
@@ -344,14 +395,21 @@ async function listMailboxes() {
|
|
|
344
395
|
return mailboxes;
|
|
345
396
|
}
|
|
346
397
|
|
|
347
|
-
async function searchEmails(query, mailbox = 'INBOX', limit = 10) {
|
|
398
|
+
async function searchEmails(query, mailbox = 'INBOX', limit = 10, filters = {}) {
|
|
348
399
|
const client = createClient();
|
|
349
400
|
await client.connect();
|
|
350
401
|
await client.mailboxOpen(mailbox);
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
402
|
+
|
|
403
|
+
// Build base text search
|
|
404
|
+
const textQuery = { or: [{ subject: query }, { from: query }, { body: query }] };
|
|
405
|
+
|
|
406
|
+
// Merge with additional filters if provided
|
|
407
|
+
const extraQuery = buildQuery(filters);
|
|
408
|
+
const finalQuery = Object.keys(extraQuery).length > 0 && !extraQuery.all
|
|
409
|
+
? { ...textQuery, ...extraQuery }
|
|
410
|
+
: textQuery;
|
|
411
|
+
|
|
412
|
+
const uids = (await client.search(finalQuery, { uid: true })) ?? [];
|
|
355
413
|
const emails = [];
|
|
356
414
|
const recentUids = uids.slice(-limit).reverse();
|
|
357
415
|
for (const uid of recentUids) {
|
|
@@ -368,7 +426,7 @@ async function searchEmails(query, mailbox = 'INBOX', limit = 10) {
|
|
|
368
426
|
}
|
|
369
427
|
}
|
|
370
428
|
await client.logout();
|
|
371
|
-
return emails;
|
|
429
|
+
return { total: uids.length, showing: emails.length, emails };
|
|
372
430
|
}
|
|
373
431
|
|
|
374
432
|
async function moveEmail(uid, targetMailbox, sourceMailbox = 'INBOX') {
|
|
@@ -395,29 +453,36 @@ function buildQuery(filters) {
|
|
|
395
453
|
if (filters.larger) query.larger = filters.larger * 1024;
|
|
396
454
|
if (filters.smaller) query.smaller = filters.smaller * 1024;
|
|
397
455
|
if (filters.hasAttachment) query.header = ['Content-Type', 'multipart/mixed'];
|
|
398
|
-
// If no filters set, match all
|
|
399
456
|
if (Object.keys(query).length === 0) query.all = true;
|
|
400
457
|
return query;
|
|
401
458
|
}
|
|
402
459
|
|
|
403
|
-
async function bulkMove(filters, targetMailbox, sourceMailbox = 'INBOX') {
|
|
460
|
+
async function bulkMove(filters, targetMailbox, sourceMailbox = 'INBOX', dryRun = false) {
|
|
404
461
|
const client = createClient();
|
|
405
462
|
await client.connect();
|
|
406
463
|
await client.mailboxOpen(sourceMailbox);
|
|
407
464
|
const query = buildQuery(filters);
|
|
408
465
|
const uids = (await client.search(query, { uid: true })) ?? [];
|
|
466
|
+
if (dryRun) {
|
|
467
|
+
await client.logout();
|
|
468
|
+
return { dryRun: true, wouldMove: uids.length, sourceMailbox, targetMailbox, filters };
|
|
469
|
+
}
|
|
409
470
|
if (uids.length === 0) { await client.logout(); return { moved: 0, sourceMailbox, targetMailbox }; }
|
|
410
471
|
await client.messageMove(uids, targetMailbox, { uid: true });
|
|
411
472
|
await client.logout();
|
|
412
473
|
return { moved: uids.length, sourceMailbox, targetMailbox, filters };
|
|
413
474
|
}
|
|
414
475
|
|
|
415
|
-
async function bulkDelete(filters, sourceMailbox = 'INBOX') {
|
|
476
|
+
async function bulkDelete(filters, sourceMailbox = 'INBOX', dryRun = false) {
|
|
416
477
|
const client = createClient();
|
|
417
478
|
await client.connect();
|
|
418
479
|
await client.mailboxOpen(sourceMailbox);
|
|
419
480
|
const query = buildQuery(filters);
|
|
420
481
|
const uids = (await client.search(query, { uid: true })) ?? [];
|
|
482
|
+
if (dryRun) {
|
|
483
|
+
await client.logout();
|
|
484
|
+
return { dryRun: true, wouldDelete: uids.length, sourceMailbox, filters };
|
|
485
|
+
}
|
|
421
486
|
if (uids.length === 0) { await client.logout(); return { deleted: 0, sourceMailbox }; }
|
|
422
487
|
await client.messageDelete(uids, { uid: true });
|
|
423
488
|
await client.logout();
|
|
@@ -436,7 +501,7 @@ async function countEmails(filters, mailbox = 'INBOX') {
|
|
|
436
501
|
|
|
437
502
|
async function main() {
|
|
438
503
|
const server = new Server(
|
|
439
|
-
{ name: 'icloud-mail', version: '1.
|
|
504
|
+
{ name: 'icloud-mail', version: '1.2.0' },
|
|
440
505
|
{ capabilities: { tools: {} } }
|
|
441
506
|
);
|
|
442
507
|
|
|
@@ -460,6 +525,17 @@ async function main() {
|
|
|
460
525
|
description: 'Get a summary of a mailbox including total, unread, and recent email counts',
|
|
461
526
|
inputSchema: { type: 'object', properties: { mailbox: { type: 'string', description: 'Mailbox name (default INBOX)' } } }
|
|
462
527
|
},
|
|
528
|
+
{
|
|
529
|
+
name: 'get_mailbox_summary',
|
|
530
|
+
description: 'Get total, unread, and recent email counts for any specific mailbox/folder',
|
|
531
|
+
inputSchema: {
|
|
532
|
+
type: 'object',
|
|
533
|
+
properties: {
|
|
534
|
+
mailbox: { type: 'string', description: 'Mailbox path to summarize (e.g. Newsletters, Archive)' }
|
|
535
|
+
},
|
|
536
|
+
required: ['mailbox']
|
|
537
|
+
}
|
|
538
|
+
},
|
|
463
539
|
{
|
|
464
540
|
name: 'get_top_senders',
|
|
465
541
|
description: 'Get the top senders by email count from a sample of the inbox',
|
|
@@ -467,7 +543,8 @@ async function main() {
|
|
|
467
543
|
type: 'object',
|
|
468
544
|
properties: {
|
|
469
545
|
mailbox: { type: 'string', description: 'Mailbox to analyze (default INBOX)' },
|
|
470
|
-
sampleSize: { type: 'number', description: 'Number of emails to sample (default 500)' }
|
|
546
|
+
sampleSize: { type: 'number', description: 'Number of emails to sample (default 500)' },
|
|
547
|
+
maxResults: { type: 'number', description: 'Max number of senders/domains to return (default 20)' }
|
|
471
548
|
}
|
|
472
549
|
}
|
|
473
550
|
},
|
|
@@ -523,17 +600,68 @@ async function main() {
|
|
|
523
600
|
},
|
|
524
601
|
{
|
|
525
602
|
name: 'search_emails',
|
|
526
|
-
description: 'Search emails by keyword',
|
|
603
|
+
description: 'Search emails by keyword, with optional filters for date, read status, domain, and more',
|
|
527
604
|
inputSchema: {
|
|
528
605
|
type: 'object',
|
|
529
606
|
properties: {
|
|
530
|
-
query: { type: 'string', description: 'Search
|
|
607
|
+
query: { type: 'string', description: 'Search keyword (matches subject, sender, body)' },
|
|
531
608
|
mailbox: { type: 'string', description: 'Mailbox to search (default INBOX)' },
|
|
532
|
-
limit: { type: 'number', description: 'Max results (default 10)' }
|
|
609
|
+
limit: { type: 'number', description: 'Max results (default 10)' },
|
|
610
|
+
...filtersSchema
|
|
533
611
|
},
|
|
534
612
|
required: ['query']
|
|
535
613
|
}
|
|
536
614
|
},
|
|
615
|
+
{
|
|
616
|
+
name: 'count_emails',
|
|
617
|
+
description: 'Count how many emails match a set of filters without moving or deleting them. Use this before bulk_move or bulk_delete to preview how many emails will be affected.',
|
|
618
|
+
inputSchema: {
|
|
619
|
+
type: 'object',
|
|
620
|
+
properties: {
|
|
621
|
+
mailbox: { type: 'string', description: 'Mailbox to count in (default INBOX)' },
|
|
622
|
+
...filtersSchema
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
name: 'bulk_move',
|
|
628
|
+
description: 'Move emails matching any combination of filters from one mailbox to another. Operates on ALL matching emails in a single IMAP operation. Use dryRun: true to preview without making changes.',
|
|
629
|
+
inputSchema: {
|
|
630
|
+
type: 'object',
|
|
631
|
+
properties: {
|
|
632
|
+
targetMailbox: { type: 'string', description: 'Destination mailbox path' },
|
|
633
|
+
sourceMailbox: { type: 'string', description: 'Source mailbox (default INBOX)' },
|
|
634
|
+
dryRun: { type: 'boolean', description: 'If true, preview what would be moved without actually moving' },
|
|
635
|
+
...filtersSchema
|
|
636
|
+
},
|
|
637
|
+
required: ['targetMailbox']
|
|
638
|
+
}
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
name: 'bulk_delete',
|
|
642
|
+
description: 'Delete emails matching any combination of filters. Operates on ALL matching emails in a single IMAP operation. Use dryRun: true to preview without making changes.',
|
|
643
|
+
inputSchema: {
|
|
644
|
+
type: 'object',
|
|
645
|
+
properties: {
|
|
646
|
+
sourceMailbox: { type: 'string', description: 'Mailbox to delete from (default INBOX)' },
|
|
647
|
+
dryRun: { type: 'boolean', description: 'If true, preview what would be deleted without actually deleting' },
|
|
648
|
+
...filtersSchema
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
name: 'bulk_flag',
|
|
654
|
+
description: 'Flag or unflag emails matching any combination of filters in bulk',
|
|
655
|
+
inputSchema: {
|
|
656
|
+
type: 'object',
|
|
657
|
+
properties: {
|
|
658
|
+
flagged: { type: 'boolean', description: 'True to flag, false to unflag' },
|
|
659
|
+
mailbox: { type: 'string', description: 'Mailbox (default INBOX)' },
|
|
660
|
+
...filtersSchema
|
|
661
|
+
},
|
|
662
|
+
required: ['flagged']
|
|
663
|
+
}
|
|
664
|
+
},
|
|
537
665
|
{
|
|
538
666
|
name: 'bulk_delete_by_sender',
|
|
539
667
|
description: 'Delete all emails from a specific sender',
|
|
@@ -572,61 +700,56 @@ async function main() {
|
|
|
572
700
|
}
|
|
573
701
|
},
|
|
574
702
|
{
|
|
575
|
-
name: '
|
|
576
|
-
description: '
|
|
703
|
+
name: 'bulk_mark_read',
|
|
704
|
+
description: 'Mark all emails as read, optionally filtered by sender',
|
|
577
705
|
inputSchema: {
|
|
578
706
|
type: 'object',
|
|
579
707
|
properties: {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
}
|
|
583
|
-
required: ['days']
|
|
708
|
+
mailbox: { type: 'string', description: 'Mailbox (default INBOX)' },
|
|
709
|
+
sender: { type: 'string', description: 'Optional: only mark emails from this sender as read' }
|
|
710
|
+
}
|
|
584
711
|
}
|
|
585
712
|
},
|
|
586
713
|
{
|
|
587
|
-
name: '
|
|
588
|
-
description: '
|
|
714
|
+
name: 'bulk_mark_unread',
|
|
715
|
+
description: 'Mark all emails as unread, optionally filtered by sender',
|
|
589
716
|
inputSchema: {
|
|
590
717
|
type: 'object',
|
|
591
718
|
properties: {
|
|
592
|
-
startDate: { type: 'string', description: 'Start date (YYYY-MM-DD)' },
|
|
593
|
-
endDate: { type: 'string', description: 'End date (YYYY-MM-DD)' },
|
|
594
719
|
mailbox: { type: 'string', description: 'Mailbox (default INBOX)' },
|
|
595
|
-
|
|
596
|
-
}
|
|
597
|
-
required: ['startDate', 'endDate']
|
|
720
|
+
sender: { type: 'string', description: 'Optional: only mark emails from this sender as unread' }
|
|
721
|
+
}
|
|
598
722
|
}
|
|
599
723
|
},
|
|
600
724
|
{
|
|
601
|
-
name: '
|
|
602
|
-
description: '
|
|
725
|
+
name: 'delete_older_than',
|
|
726
|
+
description: 'Delete all emails older than a certain number of days',
|
|
603
727
|
inputSchema: {
|
|
604
728
|
type: 'object',
|
|
605
729
|
properties: {
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
}
|
|
730
|
+
days: { type: 'number', description: 'Delete emails older than this many days' },
|
|
731
|
+
mailbox: { type: 'string', description: 'Mailbox (default INBOX)' }
|
|
732
|
+
},
|
|
733
|
+
required: ['days']
|
|
609
734
|
}
|
|
610
735
|
},
|
|
611
736
|
{
|
|
612
|
-
name: '
|
|
613
|
-
description: '
|
|
614
|
-
inputSchema: { type: 'object', properties: {} }
|
|
615
|
-
},
|
|
616
|
-
{
|
|
617
|
-
name: 'create_mailbox',
|
|
618
|
-
description: 'Create a new mailbox/folder',
|
|
737
|
+
name: 'get_emails_by_date_range',
|
|
738
|
+
description: 'Get emails between two dates',
|
|
619
739
|
inputSchema: {
|
|
620
740
|
type: 'object',
|
|
621
741
|
properties: {
|
|
622
|
-
|
|
742
|
+
startDate: { type: 'string', description: 'Start date (YYYY-MM-DD)' },
|
|
743
|
+
endDate: { type: 'string', description: 'End date (YYYY-MM-DD)' },
|
|
744
|
+
mailbox: { type: 'string', description: 'Mailbox (default INBOX)' },
|
|
745
|
+
limit: { type: 'number', description: 'Max results (default 10)' }
|
|
623
746
|
},
|
|
624
|
-
required: ['
|
|
747
|
+
required: ['startDate', 'endDate']
|
|
625
748
|
}
|
|
626
749
|
},
|
|
627
750
|
{
|
|
628
751
|
name: 'flag_email',
|
|
629
|
-
description: 'Flag or unflag
|
|
752
|
+
description: 'Flag or unflag a single email',
|
|
630
753
|
inputSchema: {
|
|
631
754
|
type: 'object',
|
|
632
755
|
properties: {
|
|
@@ -639,7 +762,7 @@ async function main() {
|
|
|
639
762
|
},
|
|
640
763
|
{
|
|
641
764
|
name: 'mark_as_read',
|
|
642
|
-
description: 'Mark
|
|
765
|
+
description: 'Mark a single email as read or unread',
|
|
643
766
|
inputSchema: {
|
|
644
767
|
type: 'object',
|
|
645
768
|
properties: {
|
|
@@ -652,7 +775,7 @@ async function main() {
|
|
|
652
775
|
},
|
|
653
776
|
{
|
|
654
777
|
name: 'delete_email',
|
|
655
|
-
description: 'Delete
|
|
778
|
+
description: 'Delete a single email',
|
|
656
779
|
inputSchema: {
|
|
657
780
|
type: 'object',
|
|
658
781
|
properties: {
|
|
@@ -664,7 +787,7 @@ async function main() {
|
|
|
664
787
|
},
|
|
665
788
|
{
|
|
666
789
|
name: 'move_email',
|
|
667
|
-
description: 'Move
|
|
790
|
+
description: 'Move a single email to a different mailbox/folder',
|
|
668
791
|
inputSchema: {
|
|
669
792
|
type: 'object',
|
|
670
793
|
properties: {
|
|
@@ -681,39 +804,43 @@ async function main() {
|
|
|
681
804
|
inputSchema: { type: 'object', properties: {} }
|
|
682
805
|
},
|
|
683
806
|
{
|
|
684
|
-
name: '
|
|
685
|
-
description: '
|
|
807
|
+
name: 'create_mailbox',
|
|
808
|
+
description: 'Create a new mailbox/folder',
|
|
686
809
|
inputSchema: {
|
|
687
810
|
type: 'object',
|
|
688
811
|
properties: {
|
|
689
|
-
|
|
690
|
-
sourceMailbox: { type: 'string', description: 'Source mailbox (default INBOX)' },
|
|
691
|
-
...filtersSchema
|
|
812
|
+
name: { type: 'string', description: 'Name of the new mailbox' }
|
|
692
813
|
},
|
|
693
|
-
required: ['
|
|
814
|
+
required: ['name']
|
|
694
815
|
}
|
|
695
816
|
},
|
|
696
817
|
{
|
|
697
|
-
name: '
|
|
698
|
-
description: '
|
|
818
|
+
name: 'rename_mailbox',
|
|
819
|
+
description: 'Rename an existing mailbox/folder',
|
|
699
820
|
inputSchema: {
|
|
700
821
|
type: 'object',
|
|
701
822
|
properties: {
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
}
|
|
823
|
+
oldName: { type: 'string', description: 'Current mailbox path' },
|
|
824
|
+
newName: { type: 'string', description: 'New mailbox path' }
|
|
825
|
+
},
|
|
826
|
+
required: ['oldName', 'newName']
|
|
705
827
|
}
|
|
706
828
|
},
|
|
707
829
|
{
|
|
708
|
-
name: '
|
|
709
|
-
description: '
|
|
830
|
+
name: 'delete_mailbox',
|
|
831
|
+
description: 'Delete a mailbox/folder. The folder must be empty first.',
|
|
710
832
|
inputSchema: {
|
|
711
833
|
type: 'object',
|
|
712
834
|
properties: {
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
835
|
+
name: { type: 'string', description: 'Mailbox path to delete' }
|
|
836
|
+
},
|
|
837
|
+
required: ['name']
|
|
716
838
|
}
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
name: 'empty_trash',
|
|
842
|
+
description: 'Permanently delete all emails in Deleted Messages',
|
|
843
|
+
inputSchema: { type: 'object', properties: {} }
|
|
717
844
|
}
|
|
718
845
|
]
|
|
719
846
|
}));
|
|
@@ -724,8 +851,10 @@ async function main() {
|
|
|
724
851
|
let result;
|
|
725
852
|
if (name === 'get_inbox_summary') {
|
|
726
853
|
result = await getInboxSummary(args.mailbox || 'INBOX');
|
|
854
|
+
} else if (name === 'get_mailbox_summary') {
|
|
855
|
+
result = await getMailboxSummary(args.mailbox);
|
|
727
856
|
} else if (name === 'get_top_senders') {
|
|
728
|
-
result = await getTopSenders(args.mailbox || 'INBOX', args.sampleSize || 500);
|
|
857
|
+
result = await getTopSenders(args.mailbox || 'INBOX', args.sampleSize || 500, args.maxResults || 20);
|
|
729
858
|
} else if (name === 'get_unread_senders') {
|
|
730
859
|
result = await getUnreadSenders(args.mailbox || 'INBOX', args.sampleSize || 500, args.maxResults || 20);
|
|
731
860
|
} else if (name === 'get_emails_by_sender') {
|
|
@@ -735,23 +864,34 @@ async function main() {
|
|
|
735
864
|
} else if (name === 'get_email') {
|
|
736
865
|
result = await getEmailContent(args.uid, args.mailbox || 'INBOX');
|
|
737
866
|
} else if (name === 'search_emails') {
|
|
738
|
-
|
|
867
|
+
const { query, mailbox, limit, ...filters } = args;
|
|
868
|
+
result = await searchEmails(query, mailbox || 'INBOX', limit || 10, filters);
|
|
869
|
+
} else if (name === 'count_emails') {
|
|
870
|
+
const { mailbox, ...filters } = args;
|
|
871
|
+
result = await countEmails(filters, mailbox || 'INBOX');
|
|
872
|
+
} else if (name === 'bulk_move') {
|
|
873
|
+
const { targetMailbox, sourceMailbox, dryRun, ...filters } = args;
|
|
874
|
+
result = await bulkMove(filters, targetMailbox, sourceMailbox || 'INBOX', dryRun || false);
|
|
875
|
+
} else if (name === 'bulk_delete') {
|
|
876
|
+
const { sourceMailbox, dryRun, ...filters } = args;
|
|
877
|
+
result = await bulkDelete(filters, sourceMailbox || 'INBOX', dryRun || false);
|
|
878
|
+
} else if (name === 'bulk_flag') {
|
|
879
|
+
const { flagged, mailbox, ...filters } = args;
|
|
880
|
+
result = await bulkFlag(filters, flagged, mailbox || 'INBOX');
|
|
739
881
|
} else if (name === 'bulk_delete_by_sender') {
|
|
740
882
|
result = await bulkDeleteBySender(args.sender, args.mailbox || 'INBOX');
|
|
741
883
|
} else if (name === 'bulk_move_by_sender') {
|
|
742
884
|
result = await bulkMoveBySender(args.sender, args.targetMailbox, args.sourceMailbox || 'INBOX');
|
|
743
885
|
} else if (name === 'bulk_delete_by_subject') {
|
|
744
886
|
result = await bulkDeleteBySubject(args.subject, args.mailbox || 'INBOX');
|
|
887
|
+
} else if (name === 'bulk_mark_read') {
|
|
888
|
+
result = await bulkMarkRead(args.mailbox || 'INBOX', args.sender || null);
|
|
889
|
+
} else if (name === 'bulk_mark_unread') {
|
|
890
|
+
result = await bulkMarkUnread(args.mailbox || 'INBOX', args.sender || null);
|
|
745
891
|
} else if (name === 'delete_older_than') {
|
|
746
892
|
result = await deleteOlderThan(args.days, args.mailbox || 'INBOX');
|
|
747
893
|
} else if (name === 'get_emails_by_date_range') {
|
|
748
894
|
result = await getEmailsByDateRange(args.startDate, args.endDate, args.mailbox || 'INBOX', args.limit || 10);
|
|
749
|
-
} else if (name === 'bulk_mark_read') {
|
|
750
|
-
result = await bulkMarkRead(args.mailbox || 'INBOX', args.sender || null);
|
|
751
|
-
} else if (name === 'empty_trash') {
|
|
752
|
-
result = await emptyTrash();
|
|
753
|
-
} else if (name === 'create_mailbox') {
|
|
754
|
-
result = await createMailbox(args.name);
|
|
755
895
|
} else if (name === 'flag_email') {
|
|
756
896
|
result = await flagEmail(args.uid, args.flagged, args.mailbox || 'INBOX');
|
|
757
897
|
} else if (name === 'mark_as_read') {
|
|
@@ -762,15 +902,14 @@ async function main() {
|
|
|
762
902
|
result = await moveEmail(args.uid, args.targetMailbox, args.sourceMailbox || 'INBOX');
|
|
763
903
|
} else if (name === 'list_mailboxes') {
|
|
764
904
|
result = await listMailboxes();
|
|
765
|
-
} else if (name === '
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
result = await
|
|
771
|
-
} else if (name === '
|
|
772
|
-
|
|
773
|
-
result = await countEmails(filters, mailbox || 'INBOX');
|
|
905
|
+
} else if (name === 'create_mailbox') {
|
|
906
|
+
result = await createMailbox(args.name);
|
|
907
|
+
} else if (name === 'rename_mailbox') {
|
|
908
|
+
result = await renameMailbox(args.oldName, args.newName);
|
|
909
|
+
} else if (name === 'delete_mailbox') {
|
|
910
|
+
result = await deleteMailbox(args.name);
|
|
911
|
+
} else if (name === 'empty_trash') {
|
|
912
|
+
result = await emptyTrash();
|
|
774
913
|
} else {
|
|
775
914
|
throw new Error(`Unknown tool: ${name}`);
|
|
776
915
|
}
|
package/package.json
CHANGED
package/test.js
CHANGED
|
@@ -32,7 +32,7 @@ function callTool(name, args = {}) {
|
|
|
32
32
|
{
|
|
33
33
|
cwd: projectDir,
|
|
34
34
|
encoding: 'utf8',
|
|
35
|
-
timeout:
|
|
35
|
+
timeout: 300000,
|
|
36
36
|
env: { ...process.env, IMAP_USER, IMAP_PASSWORD }
|
|
37
37
|
}
|
|
38
38
|
);
|
|
@@ -74,6 +74,7 @@ function assert(condition, message) {
|
|
|
74
74
|
|
|
75
75
|
console.log('\nš§Ŗ iCloud MCP Server Tests\n');
|
|
76
76
|
|
|
77
|
+
// āāā Mailbox & Summary āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
77
78
|
console.log('š¬ Mailbox & Summary');
|
|
78
79
|
|
|
79
80
|
test('get_inbox_summary', () => {
|
|
@@ -84,6 +85,14 @@ test('get_inbox_summary', () => {
|
|
|
84
85
|
console.log(`\n ā ${result.total} total, ${result.unread} unread`);
|
|
85
86
|
});
|
|
86
87
|
|
|
88
|
+
test('get_mailbox_summary', () => {
|
|
89
|
+
const result = callTool('get_mailbox_summary', { mailbox: 'INBOX' });
|
|
90
|
+
assert(typeof result.total === 'number', 'total should be a number');
|
|
91
|
+
assert(typeof result.unread === 'number', 'unread should be a number');
|
|
92
|
+
assert(result.mailbox === 'INBOX', 'mailbox should be INBOX');
|
|
93
|
+
console.log(`\n ā ${result.total} total, ${result.unread} unread`);
|
|
94
|
+
});
|
|
95
|
+
|
|
87
96
|
test('list_mailboxes', () => {
|
|
88
97
|
const result = callTool('list_mailboxes');
|
|
89
98
|
assert(Array.isArray(result), 'result should be an array');
|
|
@@ -92,14 +101,23 @@ test('list_mailboxes', () => {
|
|
|
92
101
|
console.log(`\n ā ${result.length} mailboxes found`);
|
|
93
102
|
});
|
|
94
103
|
|
|
95
|
-
test('get_top_senders (sample 50)', () => {
|
|
104
|
+
test('get_top_senders (sample 50, default maxResults)', () => {
|
|
96
105
|
const result = callTool('get_top_senders', { sampleSize: 50 });
|
|
97
106
|
assert(Array.isArray(result.topAddresses), 'topAddresses should be an array');
|
|
98
107
|
assert(Array.isArray(result.topDomains), 'topDomains should be an array');
|
|
99
108
|
assert(result.sampledEmails <= 50, 'should not exceed sample size');
|
|
109
|
+
assert(result.topAddresses.length <= 20, 'should not exceed default maxResults of 20');
|
|
100
110
|
console.log(`\n ā top sender: ${result.topAddresses[0]?.address} (${result.topAddresses[0]?.count})`);
|
|
101
111
|
});
|
|
102
112
|
|
|
113
|
+
test('get_top_senders (sample 50, maxResults 5)', () => {
|
|
114
|
+
const result = callTool('get_top_senders', { sampleSize: 50, maxResults: 5 });
|
|
115
|
+
assert(Array.isArray(result.topAddresses), 'topAddresses should be an array');
|
|
116
|
+
assert(result.topAddresses.length <= 5, 'should not exceed maxResults of 5');
|
|
117
|
+
assert(result.topDomains.length <= 5, 'domains should not exceed maxResults of 5');
|
|
118
|
+
console.log(`\n ā ${result.topAddresses.length} senders, ${result.topDomains.length} domains (capped at 5)`);
|
|
119
|
+
});
|
|
120
|
+
|
|
103
121
|
test('get_unread_senders (sample 50, default maxResults)', () => {
|
|
104
122
|
const result = callTool('get_unread_senders', { sampleSize: 50 });
|
|
105
123
|
assert(Array.isArray(result), 'result should be an array');
|
|
@@ -121,6 +139,7 @@ test('get_unread_senders (sample 50, maxResults 50)', () => {
|
|
|
121
139
|
console.log(`\n ā ${result.length} unread senders found (capped at 50)`);
|
|
122
140
|
});
|
|
123
141
|
|
|
142
|
+
// āāā Reading Emails āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
124
143
|
console.log('\nš§ Reading Emails');
|
|
125
144
|
|
|
126
145
|
test('read_inbox (page 1, limit 5)', () => {
|
|
@@ -149,10 +168,25 @@ test('read_inbox (unread only)', () => {
|
|
|
149
168
|
console.log(`\n ā ${result.emails.length} unread emails`);
|
|
150
169
|
});
|
|
151
170
|
|
|
152
|
-
test('search_emails', () => {
|
|
171
|
+
test('search_emails (keyword only)', () => {
|
|
153
172
|
const result = callTool('search_emails', { query: 'test', limit: 5 });
|
|
154
|
-
assert(
|
|
155
|
-
|
|
173
|
+
assert(typeof result.total === 'number', 'total should be a number');
|
|
174
|
+
assert(Array.isArray(result.emails), 'emails should be an array');
|
|
175
|
+
console.log(`\n ā ${result.total} results`);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test('search_emails (keyword + unread filter)', () => {
|
|
179
|
+
const result = callTool('search_emails', { query: 'test', limit: 5, unread: true });
|
|
180
|
+
assert(typeof result.total === 'number', 'total should be a number');
|
|
181
|
+
assert(Array.isArray(result.emails), 'emails should be an array');
|
|
182
|
+
console.log(`\n ā ${result.total} unread results`);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test('search_emails (keyword + date filter)', () => {
|
|
186
|
+
const result = callTool('search_emails', { query: 'test', limit: 5, since: '2024-01-01' });
|
|
187
|
+
assert(typeof result.total === 'number', 'total should be a number');
|
|
188
|
+
assert(Array.isArray(result.emails), 'emails should be an array');
|
|
189
|
+
console.log(`\n ā ${result.total} results since 2024`);
|
|
156
190
|
});
|
|
157
191
|
|
|
158
192
|
test('get_emails_by_sender', () => {
|
|
@@ -186,6 +220,7 @@ test('get_email (fetch first email content)', () => {
|
|
|
186
220
|
console.log(`\n ā fetched email: "${result.subject?.slice(0, 40)}..."`);
|
|
187
221
|
});
|
|
188
222
|
|
|
223
|
+
// āāā Count & Bulk Query āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
189
224
|
console.log('\nš Count & Bulk Query');
|
|
190
225
|
|
|
191
226
|
test('count_emails (all in INBOX)', () => {
|
|
@@ -201,12 +236,17 @@ test('count_emails (unread only)', () => {
|
|
|
201
236
|
console.log(`\n ā ${result.count} unread emails`);
|
|
202
237
|
});
|
|
203
238
|
|
|
239
|
+
test('count_emails (read only)', () => {
|
|
240
|
+
const result = callTool('count_emails', { unread: false });
|
|
241
|
+
assert(typeof result.count === 'number', 'count should be a number');
|
|
242
|
+
console.log(`\n ā ${result.count} read emails`);
|
|
243
|
+
});
|
|
244
|
+
|
|
204
245
|
test('count_emails (by domain)', () => {
|
|
205
246
|
const senders = callTool('get_top_senders', { sampleSize: 20 });
|
|
206
247
|
const topDomain = senders.topDomains[0]?.domain;
|
|
207
248
|
assert(topDomain, 'should have at least one domain');
|
|
208
249
|
const result = callTool('count_emails', { domain: topDomain });
|
|
209
|
-
console.log('\n ā raw result:', JSON.stringify(result));
|
|
210
250
|
assert(typeof result.count === 'number', 'count should be a number');
|
|
211
251
|
console.log(`\n ā ${result.count} emails from @${topDomain}`);
|
|
212
252
|
});
|
|
@@ -217,6 +257,30 @@ test('count_emails (before date)', () => {
|
|
|
217
257
|
console.log(`\n ā ${result.count} emails before 2020`);
|
|
218
258
|
});
|
|
219
259
|
|
|
260
|
+
test('count_emails (flagged false)', () => {
|
|
261
|
+
const result = callTool('count_emails', { flagged: false });
|
|
262
|
+
assert(typeof result.count === 'number', 'count should be a number');
|
|
263
|
+
console.log(`\n ā ${result.count} unflagged emails`);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
test('bulk_move (dryRun)', () => {
|
|
267
|
+
const senders = callTool('get_top_senders', { sampleSize: 20 });
|
|
268
|
+
const topDomain = senders.topDomains[0]?.domain;
|
|
269
|
+
assert(topDomain, 'should have at least one domain');
|
|
270
|
+
const result = callTool('bulk_move', { domain: topDomain, targetMailbox: 'Archive', dryRun: true });
|
|
271
|
+
assert(result.dryRun === true, 'dryRun should be true');
|
|
272
|
+
assert(typeof result.wouldMove === 'number', 'wouldMove should be a number');
|
|
273
|
+
console.log(`\n ā would move ${result.wouldMove} emails from @${topDomain}`);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
test('bulk_delete (dryRun)', () => {
|
|
277
|
+
const result = callTool('bulk_delete', { before: '2015-01-01', dryRun: true });
|
|
278
|
+
assert(result.dryRun === true, 'dryRun should be true');
|
|
279
|
+
assert(typeof result.wouldDelete === 'number', 'wouldDelete should be a number');
|
|
280
|
+
console.log(`\n ā would delete ${result.wouldDelete} emails before 2015`);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// āāā Write Operations āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
220
284
|
console.log('\nāļø Write Operations (flag/mark only ā no deletions)');
|
|
221
285
|
|
|
222
286
|
test('flag_email and unflag_email', () => {
|
|
@@ -241,10 +305,35 @@ test('mark_as_read and mark_as_unread', () => {
|
|
|
241
305
|
console.log(`\n ā marked read/unread uid ${uid}`);
|
|
242
306
|
});
|
|
243
307
|
|
|
308
|
+
// āāā Mailbox Management āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
309
|
+
console.log('\nšļø Mailbox Management');
|
|
310
|
+
|
|
311
|
+
test('create_mailbox', () => {
|
|
312
|
+
const result = callTool('create_mailbox', { name: 'mcp-test-folder' });
|
|
313
|
+
assert(result.created === 'mcp-test-folder', 'should confirm creation');
|
|
314
|
+
console.log(`\n ā created: ${result.created}`);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
test('rename_mailbox', () => {
|
|
318
|
+
const result = callTool('rename_mailbox', { oldName: 'mcp-test-folder', newName: 'mcp-test-folder-renamed' });
|
|
319
|
+
assert(result.renamed.from === 'mcp-test-folder', 'from should match old name');
|
|
320
|
+
assert(result.renamed.to === 'mcp-test-folder-renamed', 'to should match new name');
|
|
321
|
+
console.log(`\n ā renamed: ${result.renamed.from} ā ${result.renamed.to}`);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
test('delete_mailbox', () => {
|
|
325
|
+
const result = callTool('delete_mailbox', { name: 'mcp-test-folder-renamed' });
|
|
326
|
+
assert(result.deleted === 'mcp-test-folder-renamed', 'should confirm deletion');
|
|
327
|
+
console.log(`\n ā deleted: ${result.deleted}`);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
// āāā Destructive (skipped) āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
244
331
|
console.log('\nā ļø Destructive Tests (skipped by default)');
|
|
245
|
-
console.log(' Skipping: bulk_move (
|
|
246
|
-
console.log(' Skipping:
|
|
247
|
-
console.log(' Skipping:
|
|
332
|
+
console.log(' Skipping: bulk_move (live)');
|
|
333
|
+
console.log(' Skipping: bulk_delete (live)');
|
|
334
|
+
console.log(' Skipping: bulk_mark_read (live)');
|
|
335
|
+
console.log(' Skipping: bulk_mark_unread (live)');
|
|
336
|
+
console.log(' Skipping: bulk_flag (live)');
|
|
248
337
|
console.log(' Skipping: bulk_delete_by_sender');
|
|
249
338
|
console.log(' Skipping: bulk_delete_by_subject');
|
|
250
339
|
console.log(' Skipping: delete_older_than');
|