mcp-icloud 2.1.3 → 2.1.4
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/email/index.js +2 -2
- package/email/local-client.js +44 -17
- package/package.json +2 -2
package/email/index.js
CHANGED
|
@@ -64,7 +64,7 @@ async function handleReadEmail(args) {
|
|
|
64
64
|
const local = isLocalMode();
|
|
65
65
|
|
|
66
66
|
const email = local
|
|
67
|
-
? await localClient.readEmail(args.uid)
|
|
67
|
+
? await localClient.readEmail(args.uid, folder)
|
|
68
68
|
: await cloudClient.readEmail(args.uid, folder);
|
|
69
69
|
|
|
70
70
|
// Mail.app returns the body as `body`; mailparser returns `text`.
|
|
@@ -167,7 +167,7 @@ async function handleMarkAsRead(args) {
|
|
|
167
167
|
const isRead = args.isRead !== false;
|
|
168
168
|
|
|
169
169
|
if (isLocalMode()) {
|
|
170
|
-
await localClient.markAsRead(args.uid, isRead);
|
|
170
|
+
await localClient.markAsRead(args.uid, isRead, folder);
|
|
171
171
|
} else {
|
|
172
172
|
await cloudClient.markAsRead(args.uid, folder, isRead);
|
|
173
173
|
}
|
package/email/local-client.js
CHANGED
|
@@ -50,15 +50,42 @@ async function listEmails(folder = 'inbox', count = 25) {
|
|
|
50
50
|
return result ? JSON.parse(result) : [];
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/**
|
|
54
|
+
* JXA statements that set `mail` and `msg` to message `emailId`.
|
|
55
|
+
* Mail has no application-level messages collection, so
|
|
56
|
+
* `mail.messages.byId(id)` fails with -1728 (issue #15). A mailbox's
|
|
57
|
+
* `messages.byId(id)` works; the named folder is tried first.
|
|
58
|
+
* @param {string|number} emailId - Email ID
|
|
59
|
+
* @param {string} folder - Folder name
|
|
60
|
+
* @returns {string}
|
|
61
|
+
*/
|
|
62
|
+
function findMessageJXA(emailId, folder) {
|
|
63
|
+
const id = asInt(emailId);
|
|
64
|
+
return `
|
|
65
|
+
const mail = Application('Mail');
|
|
66
|
+
let msg = null;
|
|
67
|
+
for (const account of mail.accounts()) {
|
|
68
|
+
const mailboxes = [account.mailboxes.byName('${escapeJXA(getMailboxName(folder || 'inbox'))}')].concat(account.mailboxes());
|
|
69
|
+
for (const mailbox of mailboxes) {
|
|
70
|
+
if (!mailbox.exists()) continue;
|
|
71
|
+
const candidate = mailbox.messages.byId(${id});
|
|
72
|
+
if (candidate.exists()) { msg = candidate; break; }
|
|
73
|
+
}
|
|
74
|
+
if (msg) break;
|
|
75
|
+
}
|
|
76
|
+
if (!msg) throw new Error('Email not found: ${id}');
|
|
77
|
+
`;
|
|
78
|
+
}
|
|
79
|
+
|
|
53
80
|
/**
|
|
54
81
|
* Read a specific email
|
|
55
82
|
* @param {string} emailId - Email ID
|
|
83
|
+
* @param {string} [folder] - Folder to look in first
|
|
56
84
|
* @returns {Promise<Object>} - Email content
|
|
57
85
|
*/
|
|
58
|
-
async function readEmail(emailId) {
|
|
86
|
+
async function readEmail(emailId, folder = 'inbox') {
|
|
59
87
|
const script = `
|
|
60
|
-
|
|
61
|
-
const msg = mail.messages.byId(${asInt(emailId)});
|
|
88
|
+
${findMessageJXA(emailId, folder)}
|
|
62
89
|
|
|
63
90
|
JSON.stringify({
|
|
64
91
|
id: msg.id(),
|
|
@@ -170,18 +197,18 @@ async function searchEmails({ query, from, subject, folder = 'inbox', count = 25
|
|
|
170
197
|
* Mark email as read/unread
|
|
171
198
|
* @param {string} emailId - Email ID
|
|
172
199
|
* @param {boolean} isRead - Read status
|
|
200
|
+
* @param {string} [folder] - Folder to look in first
|
|
173
201
|
* @returns {Promise<Object>} - Result
|
|
174
202
|
*/
|
|
175
|
-
async function markAsRead(emailId, isRead = true) {
|
|
203
|
+
async function markAsRead(emailId, isRead = true, folder = 'inbox') {
|
|
176
204
|
const script = `
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
return "done"
|
|
205
|
+
${findMessageJXA(emailId, folder)}
|
|
206
|
+
msg = msg.mailbox().messages.byId(${asInt(emailId)});
|
|
207
|
+
msg.readStatus = ${asBool(isRead, true)};
|
|
208
|
+
'done';
|
|
182
209
|
`;
|
|
183
210
|
|
|
184
|
-
await
|
|
211
|
+
await runJXA(script);
|
|
185
212
|
return { success: true, message: `Email marked as ${isRead ? 'read' : 'unread'}` };
|
|
186
213
|
}
|
|
187
214
|
|
|
@@ -216,18 +243,18 @@ async function listFolders() {
|
|
|
216
243
|
/**
|
|
217
244
|
* Delete an email
|
|
218
245
|
* @param {string} emailId - Email ID
|
|
246
|
+
* @param {string} [folder] - Folder to look in first
|
|
219
247
|
* @returns {Promise<Object>} - Result
|
|
220
248
|
*/
|
|
221
|
-
async function deleteEmail(emailId) {
|
|
249
|
+
async function deleteEmail(emailId, folder = 'inbox') {
|
|
222
250
|
const script = `
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
return "deleted"
|
|
251
|
+
${findMessageJXA(emailId, folder)}
|
|
252
|
+
msg = msg.mailbox().messages.byId(${asInt(emailId)});
|
|
253
|
+
mail.delete(msg);
|
|
254
|
+
'deleted';
|
|
228
255
|
`;
|
|
229
256
|
|
|
230
|
-
await
|
|
257
|
+
await runJXA(script);
|
|
231
258
|
return { success: true, message: 'Email deleted' };
|
|
232
259
|
}
|
|
233
260
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-icloud",
|
|
3
3
|
"mcpName": "io.github.MrGo2/icloud-mcp",
|
|
4
|
-
"version": "2.1.
|
|
4
|
+
"version": "2.1.4",
|
|
5
5
|
"description": "MCP server for Apple services - Email, Calendar, Contacts, Reminders, Notes, Messages and Safari - with dual local (AppleScript) and cloud (IMAP/CalDAV/CardDAV) modes",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"bin": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
],
|
|
28
28
|
"scripts": {
|
|
29
29
|
"start": "node index.js",
|
|
30
|
-
"test": "node test/security.test.js && node test/local-output.test.js",
|
|
30
|
+
"test": "node test/security.test.js && node test/local-output.test.js && node test/email-read.test.js",
|
|
31
31
|
"test-mode": "USE_TEST_MODE=true node index.js",
|
|
32
32
|
"inspect": "npx @modelcontextprotocol/inspector node index.js",
|
|
33
33
|
"test:local": "node test/local-output.test.js"
|