icloud-mcp 1.7.0 → 1.8.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.
Files changed (2) hide show
  1. package/index.js +56 -2
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1119,6 +1119,25 @@ function findTextPart(node) {
1119
1119
  return null;
1120
1120
  }
1121
1121
 
1122
+ function findAttachments(node, parts = []) {
1123
+ if (node.childNodes) {
1124
+ for (const child of node.childNodes) findAttachments(child, parts);
1125
+ } else {
1126
+ const filename = node.dispositionParameters?.filename ?? node.parameters?.name ?? null;
1127
+ const isTextBody = (node.type === 'text/plain' || node.type === 'text/html') && node.disposition !== 'attachment';
1128
+ if (node.disposition === 'attachment' || node.disposition === 'inline' || (filename && !isTextBody)) {
1129
+ parts.push({
1130
+ partId: node.part ?? 'TEXT',
1131
+ filename,
1132
+ mimeType: node.type ?? 'application/octet-stream',
1133
+ size: node.size ?? 0,
1134
+ disposition: node.disposition ?? 'attachment'
1135
+ });
1136
+ }
1137
+ }
1138
+ return parts;
1139
+ }
1140
+
1122
1141
  // ─── Email content fetcher (MIME-aware) ───────────────────────────────────────
1123
1142
 
1124
1143
  async function getEmailContent(uid, mailbox = 'INBOX') {
@@ -1205,6 +1224,22 @@ async function getEmailContent(uid, mailbox = 'INBOX') {
1205
1224
  };
1206
1225
  }
1207
1226
 
1227
+ async function listAttachments(uid, mailbox = 'INBOX') {
1228
+ const client = createRateLimitedClient();
1229
+ await client.connect();
1230
+ await client.mailboxOpen(mailbox);
1231
+ const meta = await client.fetchOne(uid, { envelope: true, bodyStructure: true }, { uid: true });
1232
+ await client.logout();
1233
+ if (!meta) return { uid, subject: null, attachmentCount: 0, attachments: [] };
1234
+ const attachments = meta.bodyStructure ? findAttachments(meta.bodyStructure) : [];
1235
+ return {
1236
+ uid: meta.uid,
1237
+ subject: meta.envelope.subject,
1238
+ attachmentCount: attachments.length,
1239
+ attachments
1240
+ };
1241
+ }
1242
+
1208
1243
  async function flagEmail(uid, flagged, mailbox = 'INBOX') {
1209
1244
  const client = createRateLimitedClient();
1210
1245
  await client.connect();
@@ -1309,7 +1344,12 @@ function buildQuery(filters) {
1309
1344
  if (filters.flagged === false) query.unflagged = true;
1310
1345
  if (filters.larger) query.larger = filters.larger * 1024;
1311
1346
  if (filters.smaller) query.smaller = filters.smaller * 1024;
1312
- if (filters.hasAttachment) query.header = ['Content-Type', 'multipart/mixed'];
1347
+ if (filters.hasAttachment) {
1348
+ query.or = [
1349
+ { header: { 'Content-Disposition': 'attachment' } },
1350
+ { header: { 'Content-Type': 'multipart/mixed' } }
1351
+ ];
1352
+ }
1313
1353
  if (Object.keys(query).length === 0) query.all = true;
1314
1354
  return query;
1315
1355
  }
@@ -1421,7 +1461,7 @@ function logClear() {
1421
1461
 
1422
1462
  async function main() {
1423
1463
  const server = new Server(
1424
- { name: 'icloud-mail', version: '1.7.0' },
1464
+ { name: 'icloud-mail', version: '1.8.0' },
1425
1465
  { capabilities: { tools: {} } }
1426
1466
  );
1427
1467
 
@@ -1788,6 +1828,18 @@ async function main() {
1788
1828
  name: 'log_clear',
1789
1829
  description: 'Clear the session log and start fresh. Use this at the start of a new task.',
1790
1830
  inputSchema: { type: 'object', properties: {} }
1831
+ },
1832
+ {
1833
+ name: 'list_attachments',
1834
+ description: 'List all attachments in an email without downloading them. Returns filename, MIME type, size, and IMAP part ID for each attachment.',
1835
+ inputSchema: {
1836
+ type: 'object',
1837
+ properties: {
1838
+ uid: { type: 'number', description: 'Email UID' },
1839
+ mailbox: { type: 'string', description: 'Mailbox name (default INBOX)' }
1840
+ },
1841
+ required: ['uid']
1842
+ }
1791
1843
  }
1792
1844
  ]
1793
1845
  }));
@@ -1817,6 +1869,8 @@ async function main() {
1817
1869
  result = await withTimeout('read_inbox', TIMEOUT.FETCH, () => fetchEmails(args.mailbox || 'INBOX', args.limit || 10, args.onlyUnread || false, args.page || 1));
1818
1870
  } else if (name === 'get_email') {
1819
1871
  result = await withTimeout('get_email', TIMEOUT.FETCH, () => getEmailContent(args.uid, args.mailbox || 'INBOX'));
1872
+ } else if (name === 'list_attachments') {
1873
+ result = await withTimeout('list_attachments', TIMEOUT.FETCH, () => listAttachments(args.uid, args.mailbox || 'INBOX'));
1820
1874
  } else if (name === 'search_emails') {
1821
1875
  const { query, mailbox, limit, ...filters } = args;
1822
1876
  result = await withTimeout('search_emails', TIMEOUT.FETCH, () => searchEmails(query, mailbox || 'INBOX', limit || 10, filters));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "icloud-mcp",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "A Model Context Protocol (MCP) server for iCloud Mail",
5
5
  "main": "index.js",
6
6
  "bin": {