@agenticmail/mcp 0.5.49 → 0.5.51

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/dist/index.js +374 -279
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@
3
3
  // src/index.ts
4
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
6
7
 
7
8
  // src/pending-followup.ts
8
9
  var STEP_DELAYS_MS = [
@@ -1064,22 +1065,22 @@ function mcpBuildSecuritySection(security, attachments) {
1064
1065
  --- Security ---
1065
1066
  ${lines.join("\n")}`;
1066
1067
  }
1067
- async function handleToolCall(name, args) {
1068
+ async function handleToolCall(name, args2) {
1068
1069
  recordToolCall(name);
1069
1070
  const useMaster = MASTER_KEY_TOOLS.has(name);
1070
1071
  switch (name) {
1071
1072
  case "send_email": {
1072
1073
  const sendBody = {
1073
- to: args.to,
1074
- subject: args.subject,
1075
- text: args.text ?? "",
1076
- html: args.html,
1077
- cc: args.cc,
1078
- inReplyTo: args.inReplyTo,
1079
- references: args.references
1074
+ to: args2.to,
1075
+ subject: args2.subject,
1076
+ text: args2.text ?? "",
1077
+ html: args2.html,
1078
+ cc: args2.cc,
1079
+ inReplyTo: args2.inReplyTo,
1080
+ references: args2.references
1080
1081
  };
1081
- if (Array.isArray(args.attachments) && args.attachments.length > 0) {
1082
- sendBody.attachments = args.attachments.map((a) => ({
1082
+ if (Array.isArray(args2.attachments) && args2.attachments.length > 0) {
1083
+ sendBody.attachments = args2.attachments.map((a) => ({
1083
1084
  filename: a.filename,
1084
1085
  content: a.content,
1085
1086
  contentType: a.contentType,
@@ -1088,7 +1089,7 @@ async function handleToolCall(name, args) {
1088
1089
  }
1089
1090
  const result = await apiRequest("POST", "/mail/send", sendBody);
1090
1091
  if (result?.blocked && result?.pendingId) {
1091
- scheduleFollowUp(result.pendingId, String(args.to), String(args.subject || "(no subject)"), makePendingCheck(result.pendingId));
1092
+ scheduleFollowUp(result.pendingId, String(args2.to), String(args2.subject || "(no subject)"), makePendingCheck(result.pendingId));
1092
1093
  return `Email NOT sent \u2014 blocked by outbound guard.
1093
1094
  ${result.summary}
1094
1095
 
@@ -1112,8 +1113,8 @@ ${result.outboundWarnings.map((w) => ` [${w.severity?.toUpperCase()}] ${w.descr
1112
1113
  return response;
1113
1114
  }
1114
1115
  case "list_inbox": {
1115
- const limit = Math.min(Math.max(Number(args.limit) || 20, 1), 100);
1116
- const offset = Math.max(Number(args.offset) || 0, 0);
1116
+ const limit = Math.min(Math.max(Number(args2.limit) || 20, 1), 100);
1117
+ const offset = Math.max(Number(args2.offset) || 0, 0);
1117
1118
  const result = await apiRequest("GET", `/mail/inbox?limit=${limit}&offset=${offset}`);
1118
1119
  if (!result?.messages?.length) {
1119
1120
  return "Inbox is empty.";
@@ -1125,7 +1126,7 @@ ${result.outboundWarnings.map((w) => ` [${w.severity?.toUpperCase()}] ${w.descr
1125
1126
  ${lines.join("\n")}`;
1126
1127
  }
1127
1128
  case "read_email": {
1128
- const uid = Number(args.uid);
1129
+ const uid = Number(args2.uid);
1129
1130
  if (!uid || uid < 1 || !Number.isInteger(uid)) {
1130
1131
  throw new Error("uid must be a positive integer");
1131
1132
  }
@@ -1153,7 +1154,7 @@ ${lines.join("\n")}`;
1153
1154
  return lines.filter((line) => line !== null).join("\n");
1154
1155
  }
1155
1156
  case "delete_email": {
1156
- const uid = Number(args.uid);
1157
+ const uid = Number(args2.uid);
1157
1158
  if (!uid || uid < 1 || !Number.isInteger(uid)) {
1158
1159
  throw new Error("uid must be a positive integer");
1159
1160
  }
@@ -1161,7 +1162,7 @@ ${lines.join("\n")}`;
1161
1162
  return `Email UID ${uid} deleted successfully.`;
1162
1163
  }
1163
1164
  case "search_emails": {
1164
- const { from, to, subject, text, since, before, seen, searchRelay } = args;
1165
+ const { from, to, subject, text, since, before, seen, searchRelay } = args2;
1165
1166
  const result = await apiRequest("POST", "/mail/search", { from, to, subject, text, since, before, seen, searchRelay });
1166
1167
  const lines = [];
1167
1168
  if (result?.uids?.length) {
@@ -1183,7 +1184,7 @@ Connected account (${result.relayResults[0].account}): ${result.relayResults.len
1183
1184
  return lines.join("\n");
1184
1185
  }
1185
1186
  case "import_relay_email": {
1186
- const uid = Number(args.uid);
1187
+ const uid = Number(args2.uid);
1187
1188
  if (!uid || uid < 1 || !Number.isInteger(uid)) {
1188
1189
  throw new Error("uid must be a positive integer (relay UID from search results)");
1189
1190
  }
@@ -1191,7 +1192,7 @@ Connected account (${result.relayResults[0].account}): ${result.relayResults.len
1191
1192
  return result?.ok ? "Email imported to local inbox. You can now use list_inbox to find it and reply_email to continue the thread." : `Import failed: ${result?.error || "unknown error"}`;
1192
1193
  }
1193
1194
  case "reply_email": {
1194
- const uid = Number(args.uid);
1195
+ const uid = Number(args2.uid);
1195
1196
  if (!uid || uid < 1) throw new Error("uid must be a positive integer");
1196
1197
  const original = await apiRequest("GET", `/mail/messages/${uid}`);
1197
1198
  if (!original) throw new Error("Original email not found");
@@ -1202,12 +1203,12 @@ Connected account (${result.relayResults[0].account}): ${result.relayResults.len
1202
1203
  const refs = Array.isArray(original.references) ? [...original.references] : [];
1203
1204
  if (original.messageId) refs.push(original.messageId);
1204
1205
  const quotedBody = (original.text || "").split("\n").map((l) => `> ${l}`).join("\n");
1205
- const fullText = `${args.text}
1206
+ const fullText = `${args2.text}
1206
1207
 
1207
1208
  On ${original.date}, ${replyTo} wrote:
1208
1209
  ${quotedBody}`;
1209
1210
  let to = replyTo;
1210
- if (args.replyAll) {
1211
+ if (args2.replyAll) {
1211
1212
  const allTo = [...original.to || [], ...original.cc || []].map((a) => a.address).filter(Boolean);
1212
1213
  to = [replyTo, ...allTo].filter((v, i, a) => v && a.indexOf(v) === i).join(", ");
1213
1214
  }
@@ -1215,7 +1216,7 @@ ${quotedBody}`;
1215
1216
  to,
1216
1217
  subject,
1217
1218
  text: fullText,
1218
- html: args.html,
1219
+ html: args2.html,
1219
1220
  inReplyTo: original.messageId,
1220
1221
  references: refs
1221
1222
  };
@@ -1244,21 +1245,21 @@ ${sendResult.outboundWarnings.map((w) => ` [${w.severity?.toUpperCase()}] ${w.d
1244
1245
  return response;
1245
1246
  }
1246
1247
  case "forward_email": {
1247
- const uid = Number(args.uid);
1248
+ const uid = Number(args2.uid);
1248
1249
  if (!uid || uid < 1) throw new Error("uid must be a positive integer");
1249
1250
  const orig = await apiRequest("GET", `/mail/messages/${uid}`);
1250
1251
  if (!orig) throw new Error("Email not found");
1251
1252
  const fwdSubject = (orig.subject ?? "").startsWith("Fwd:") ? orig.subject : `Fwd: ${orig.subject}`;
1252
1253
  const origFrom = orig.from?.[0]?.address ?? "unknown";
1253
1254
  const origTo = (orig.to || []).map((a) => a.address).join(", ");
1254
- const fwdBody = `${args.text ? args.text + "\n\n" : ""}---------- Forwarded message ----------
1255
+ const fwdBody = `${args2.text ? args2.text + "\n\n" : ""}---------- Forwarded message ----------
1255
1256
  From: ${origFrom}
1256
1257
  To: ${origTo}
1257
1258
  Date: ${orig.date}
1258
1259
  Subject: ${orig.subject}
1259
1260
 
1260
1261
  ${orig.text || ""}`;
1261
- const fwdSendBody = { to: args.to, subject: fwdSubject, text: fwdBody };
1262
+ const fwdSendBody = { to: args2.to, subject: fwdSubject, text: fwdBody };
1262
1263
  if (Array.isArray(orig.attachments) && orig.attachments.length > 0) {
1263
1264
  fwdSendBody.attachments = orig.attachments.map((a) => ({
1264
1265
  filename: a.filename,
@@ -1269,7 +1270,7 @@ ${orig.text || ""}`;
1269
1270
  }
1270
1271
  const fwdResult = await apiRequest("POST", "/mail/send", fwdSendBody);
1271
1272
  if (fwdResult?.blocked && fwdResult?.pendingId) {
1272
- scheduleFollowUp(fwdResult.pendingId, String(args.to), fwdSubject, makePendingCheck(fwdResult.pendingId));
1273
+ scheduleFollowUp(fwdResult.pendingId, String(args2.to), fwdSubject, makePendingCheck(fwdResult.pendingId));
1273
1274
  return `Forward NOT sent \u2014 blocked by outbound guard.
1274
1275
  ${fwdResult.summary}
1275
1276
 
@@ -1282,7 +1283,7 @@ You MUST now:
1282
1283
  3. If this forward is urgent or has a deadline, tell your owner about the time sensitivity.
1283
1284
  4. Periodically check with manage_pending_emails(action='list') and follow up with your owner if still pending.`;
1284
1285
  }
1285
- let response = `Forwarded to ${args.to}. Message ID: ${fwdResult?.messageId ?? "unknown"}`;
1286
+ let response = `Forwarded to ${args2.to}. Message ID: ${fwdResult?.messageId ?? "unknown"}`;
1286
1287
  if (fwdResult?.outboundWarnings?.length) {
1287
1288
  response += `
1288
1289
 
@@ -1292,19 +1293,19 @@ ${fwdResult.outboundWarnings.map((w) => ` [${w.severity?.toUpperCase()}] ${w.de
1292
1293
  return response;
1293
1294
  }
1294
1295
  case "move_email": {
1295
- const uid = Number(args.uid);
1296
+ const uid = Number(args2.uid);
1296
1297
  if (!uid || uid < 1) throw new Error("uid must be a positive integer");
1297
- await apiRequest("POST", `/mail/messages/${uid}/move`, { from: args.from || "INBOX", to: args.to });
1298
- return `Moved message UID ${uid} to ${args.to}`;
1298
+ await apiRequest("POST", `/mail/messages/${uid}/move`, { from: args2.from || "INBOX", to: args2.to });
1299
+ return `Moved message UID ${uid} to ${args2.to}`;
1299
1300
  }
1300
1301
  case "mark_unread": {
1301
- const uid = Number(args.uid);
1302
+ const uid = Number(args2.uid);
1302
1303
  if (!uid || uid < 1) throw new Error("uid must be a positive integer");
1303
1304
  await apiRequest("POST", `/mail/messages/${uid}/unseen`);
1304
1305
  return `Marked message UID ${uid} as unread`;
1305
1306
  }
1306
1307
  case "mark_read": {
1307
- const uid = Number(args.uid);
1308
+ const uid = Number(args2.uid);
1308
1309
  if (!uid || uid < 1) throw new Error("uid must be a positive integer");
1309
1310
  await apiRequest("POST", `/mail/messages/${uid}/seen`);
1310
1311
  return `Marked message UID ${uid} as read`;
@@ -1315,74 +1316,74 @@ ${fwdResult.outboundWarnings.map((w) => ` [${w.severity?.toUpperCase()}] ${w.de
1315
1316
  return result.folders.map((f) => `${f.path}${f.specialUse ? ` (${f.specialUse})` : ""}`).join("\n");
1316
1317
  }
1317
1318
  case "list_folder": {
1318
- const folder = encodeURIComponent(String(args.folder));
1319
- const limit = Math.min(Math.max(Number(args.limit) || 20, 1), 100);
1320
- const offset = Math.max(Number(args.offset) || 0, 0);
1319
+ const folder = encodeURIComponent(String(args2.folder));
1320
+ const limit = Math.min(Math.max(Number(args2.limit) || 20, 1), 100);
1321
+ const offset = Math.max(Number(args2.offset) || 0, 0);
1321
1322
  const result = await apiRequest("GET", `/mail/folders/${folder}?limit=${limit}&offset=${offset}`);
1322
- if (!result?.messages?.length) return `Folder "${args.folder}" is empty.`;
1323
+ if (!result?.messages?.length) return `Folder "${args2.folder}" is empty.`;
1323
1324
  const lines = result.messages.map((m, i) => `${i + 1}. [UID:${m.uid}] From: ${m.from?.[0]?.address ?? "unknown"} | Subject: ${m.subject} | Date: ${m.date}`);
1324
- return `${args.folder} (${result.total} total):
1325
+ return `${args2.folder} (${result.total} total):
1325
1326
  ${lines.join("\n")}`;
1326
1327
  }
1327
1328
  case "batch_delete": {
1328
- const uids = args.uids;
1329
+ const uids = args2.uids;
1329
1330
  if (!Array.isArray(uids) || uids.length === 0) throw new Error("uids array required");
1330
- await apiRequest("POST", "/mail/batch/delete", { uids, folder: args.folder });
1331
+ await apiRequest("POST", "/mail/batch/delete", { uids, folder: args2.folder });
1331
1332
  return `Deleted ${uids.length} messages.`;
1332
1333
  }
1333
1334
  case "batch_mark_read": {
1334
- const uids = args.uids;
1335
+ const uids = args2.uids;
1335
1336
  if (!Array.isArray(uids) || uids.length === 0) throw new Error("uids array required");
1336
- await apiRequest("POST", "/mail/batch/seen", { uids, folder: args.folder });
1337
+ await apiRequest("POST", "/mail/batch/seen", { uids, folder: args2.folder });
1337
1338
  return `Marked ${uids.length} messages as read.`;
1338
1339
  }
1339
1340
  case "manage_contacts": {
1340
- if (args.action === "list") {
1341
+ if (args2.action === "list") {
1341
1342
  const r = await apiRequest("GET", "/contacts");
1342
1343
  if (!r?.contacts?.length) return "No contacts.";
1343
1344
  return r.contacts.map((c) => `${c.name || "(no name)"} <${c.email}>`).join("\n");
1344
1345
  }
1345
- if (args.action === "add") {
1346
- if (!args.email) throw new Error("email is required");
1347
- await apiRequest("POST", "/contacts", { email: args.email, name: args.name });
1348
- return `Contact added: ${args.name || ""} <${args.email}>`;
1346
+ if (args2.action === "add") {
1347
+ if (!args2.email) throw new Error("email is required");
1348
+ await apiRequest("POST", "/contacts", { email: args2.email, name: args2.name });
1349
+ return `Contact added: ${args2.name || ""} <${args2.email}>`;
1349
1350
  }
1350
- if (args.action === "delete") {
1351
- if (!args.id) throw new Error("id is required");
1352
- await apiRequest("DELETE", `/contacts/${args.id}`);
1351
+ if (args2.action === "delete") {
1352
+ if (!args2.id) throw new Error("id is required");
1353
+ await apiRequest("DELETE", `/contacts/${args2.id}`);
1353
1354
  return "Contact deleted.";
1354
1355
  }
1355
1356
  throw new Error("Invalid action");
1356
1357
  }
1357
1358
  case "manage_drafts": {
1358
- if (args.action === "list") {
1359
+ if (args2.action === "list") {
1359
1360
  const r = await apiRequest("GET", "/drafts");
1360
1361
  if (!r?.drafts?.length) return "No drafts.";
1361
1362
  return r.drafts.map((d) => `[${d.id}] To: ${d.to_addr || "?"} | Subject: ${d.subject || "?"}`).join("\n");
1362
1363
  }
1363
- if (args.action === "create") {
1364
- const r = await apiRequest("POST", "/drafts", { to: args.to, subject: args.subject, text: args.text });
1364
+ if (args2.action === "create") {
1365
+ const r = await apiRequest("POST", "/drafts", { to: args2.to, subject: args2.subject, text: args2.text });
1365
1366
  return `Draft created: ${r?.id}`;
1366
1367
  }
1367
- if (args.action === "update") {
1368
- if (!args.id) throw new Error("id is required");
1369
- await apiRequest("PUT", `/drafts/${args.id}`, { to: args.to, subject: args.subject, text: args.text });
1370
- return `Draft ${args.id} updated.`;
1368
+ if (args2.action === "update") {
1369
+ if (!args2.id) throw new Error("id is required");
1370
+ await apiRequest("PUT", `/drafts/${args2.id}`, { to: args2.to, subject: args2.subject, text: args2.text });
1371
+ return `Draft ${args2.id} updated.`;
1371
1372
  }
1372
- if (args.action === "send") {
1373
- if (!args.id) throw new Error("id is required");
1374
- const r = await apiRequest("POST", `/drafts/${args.id}/send`);
1373
+ if (args2.action === "send") {
1374
+ if (!args2.id) throw new Error("id is required");
1375
+ const r = await apiRequest("POST", `/drafts/${args2.id}/send`);
1375
1376
  return `Draft sent. Message ID: ${r?.messageId ?? "unknown"}`;
1376
1377
  }
1377
- if (args.action === "delete") {
1378
- if (!args.id) throw new Error("id is required");
1379
- await apiRequest("DELETE", `/drafts/${args.id}`);
1378
+ if (args2.action === "delete") {
1379
+ if (!args2.id) throw new Error("id is required");
1380
+ await apiRequest("DELETE", `/drafts/${args2.id}`);
1380
1381
  return "Draft deleted.";
1381
1382
  }
1382
1383
  throw new Error("Invalid action");
1383
1384
  }
1384
1385
  case "manage_scheduled": {
1385
- const action = args.action || "create";
1386
+ const action = args2.action || "create";
1386
1387
  if (action === "list") {
1387
1388
  const r2 = await apiRequest("GET", "/scheduled");
1388
1389
  if (!r2?.scheduled?.length) return "No scheduled emails.";
@@ -1391,61 +1392,61 @@ ${lines.join("\n")}`;
1391
1392
  ).join("\n");
1392
1393
  }
1393
1394
  if (action === "cancel") {
1394
- if (!args.id) throw new Error("id is required");
1395
- await apiRequest("DELETE", `/scheduled/${args.id}`);
1395
+ if (!args2.id) throw new Error("id is required");
1396
+ await apiRequest("DELETE", `/scheduled/${args2.id}`);
1396
1397
  return "Scheduled email cancelled.";
1397
1398
  }
1398
1399
  const r = await apiRequest("POST", "/scheduled", {
1399
- to: args.to,
1400
- subject: args.subject,
1401
- text: args.text,
1402
- sendAt: args.sendAt
1400
+ to: args2.to,
1401
+ subject: args2.subject,
1402
+ text: args2.text,
1403
+ sendAt: args2.sendAt
1403
1404
  });
1404
1405
  return `Email scheduled for ${r?.sendAt}. ID: ${r?.id}`;
1405
1406
  }
1406
1407
  case "create_folder": {
1407
- if (!args.name) throw new Error("name is required");
1408
- await apiRequest("POST", "/mail/folders", { name: args.name });
1409
- return `Folder "${args.name}" created successfully.`;
1408
+ if (!args2.name) throw new Error("name is required");
1409
+ await apiRequest("POST", "/mail/folders", { name: args2.name });
1410
+ return `Folder "${args2.name}" created successfully.`;
1410
1411
  }
1411
1412
  case "manage_tags": {
1412
- const action = args.action;
1413
+ const action = args2.action;
1413
1414
  if (action === "list") {
1414
1415
  const r = await apiRequest("GET", "/tags");
1415
1416
  if (!r?.tags?.length) return "No tags.";
1416
1417
  return r.tags.map((t) => `[${t.id.slice(0, 8)}] ${t.name} (${t.color})`).join("\n");
1417
1418
  }
1418
1419
  if (action === "create") {
1419
- if (!args.name) throw new Error("name is required");
1420
- const r = await apiRequest("POST", "/tags", { name: args.name, color: args.color });
1421
- return `Tag "${args.name}" created (${r?.color}). ID: ${r?.id}`;
1420
+ if (!args2.name) throw new Error("name is required");
1421
+ const r = await apiRequest("POST", "/tags", { name: args2.name, color: args2.color });
1422
+ return `Tag "${args2.name}" created (${r?.color}). ID: ${r?.id}`;
1422
1423
  }
1423
1424
  if (action === "delete") {
1424
- if (!args.id) throw new Error("id is required");
1425
- await apiRequest("DELETE", `/tags/${args.id}`);
1425
+ if (!args2.id) throw new Error("id is required");
1426
+ await apiRequest("DELETE", `/tags/${args2.id}`);
1426
1427
  return "Tag deleted.";
1427
1428
  }
1428
1429
  if (action === "tag_message") {
1429
- if (!args.id || !args.uid) throw new Error("id and uid are required");
1430
- await apiRequest("POST", `/tags/${args.id}/messages`, { uid: args.uid, folder: args.folder });
1431
- return `Tagged message UID ${args.uid} with tag ${args.id}`;
1430
+ if (!args2.id || !args2.uid) throw new Error("id and uid are required");
1431
+ await apiRequest("POST", `/tags/${args2.id}/messages`, { uid: args2.uid, folder: args2.folder });
1432
+ return `Tagged message UID ${args2.uid} with tag ${args2.id}`;
1432
1433
  }
1433
1434
  if (action === "untag_message") {
1434
- if (!args.id || !args.uid) throw new Error("id and uid are required");
1435
- const folder = args.folder || "INBOX";
1436
- await apiRequest("DELETE", `/tags/${args.id}/messages/${args.uid}?folder=${encodeURIComponent(folder)}`);
1437
- return `Removed tag from message UID ${args.uid} in ${folder}`;
1435
+ if (!args2.id || !args2.uid) throw new Error("id and uid are required");
1436
+ const folder = args2.folder || "INBOX";
1437
+ await apiRequest("DELETE", `/tags/${args2.id}/messages/${args2.uid}?folder=${encodeURIComponent(folder)}`);
1438
+ return `Removed tag from message UID ${args2.uid} in ${folder}`;
1438
1439
  }
1439
1440
  if (action === "get_messages") {
1440
- if (!args.id) throw new Error("id is required");
1441
- const r = await apiRequest("GET", `/tags/${args.id}/messages`);
1441
+ if (!args2.id) throw new Error("id is required");
1442
+ const r = await apiRequest("GET", `/tags/${args2.id}/messages`);
1442
1443
  if (!r?.messages?.length) return `No messages with this tag.`;
1443
1444
  return `Tag "${r.tag.name}" \u2014 ${r.messages.length} messages:
1444
1445
  ${r.messages.map((m) => ` UID ${m.uid} (${m.folder})`).join("\n")}`;
1445
1446
  }
1446
1447
  if (action === "get_message_tags") {
1447
- if (!args.uid) throw new Error("uid is required");
1448
- const r = await apiRequest("GET", `/messages/${args.uid}/tags`);
1448
+ if (!args2.uid) throw new Error("uid is required");
1449
+ const r = await apiRequest("GET", `/messages/${args2.uid}/tags`);
1449
1450
  if (!r?.tags?.length) return "No tags on this message.";
1450
1451
  return r.tags.map((t) => `[${t.id.slice(0, 8)}] ${t.name} (${t.color})`).join("\n");
1451
1452
  }
@@ -1453,9 +1454,9 @@ ${r.messages.map((m) => ` UID ${m.uid} (${m.folder})`).join("\n")}`;
1453
1454
  }
1454
1455
  case "create_account": {
1455
1456
  const result = await apiRequest("POST", "/accounts", {
1456
- name: args.name,
1457
- domain: args.domain,
1458
- role: args.role
1457
+ name: args2.name,
1458
+ domain: args2.domain,
1459
+ role: args2.role
1459
1460
  }, useMaster);
1460
1461
  if (!result) throw new Error("No response from account creation");
1461
1462
  return [
@@ -1469,16 +1470,16 @@ ${r.messages.map((m) => ` UID ${m.uid} (${m.folder})`).join("\n")}`;
1469
1470
  }
1470
1471
  case "setup_email_relay": {
1471
1472
  const result = await apiRequest("POST", "/gateway/relay", {
1472
- provider: args.provider,
1473
- email: args.email,
1474
- password: args.password,
1475
- smtpHost: args.smtpHost,
1476
- smtpPort: args.smtpPort,
1477
- imapHost: args.imapHost,
1478
- imapPort: args.imapPort,
1479
- agentName: args.agentName,
1480
- agentRole: args.agentRole,
1481
- skipDefaultAgent: args.skipDefaultAgent
1473
+ provider: args2.provider,
1474
+ email: args2.email,
1475
+ password: args2.password,
1476
+ smtpHost: args2.smtpHost,
1477
+ smtpPort: args2.smtpPort,
1478
+ imapHost: args2.imapHost,
1479
+ imapPort: args2.imapPort,
1480
+ agentName: args2.agentName,
1481
+ agentRole: args2.agentRole,
1482
+ skipDefaultAgent: args2.skipDefaultAgent
1482
1483
  }, useMaster);
1483
1484
  if (!result) throw new Error("No response from relay setup");
1484
1485
  const lines = [
@@ -1498,11 +1499,11 @@ ${r.messages.map((m) => ` UID ${m.uid} (${m.folder})`).join("\n")}`;
1498
1499
  }
1499
1500
  case "setup_email_domain": {
1500
1501
  const result = await apiRequest("POST", "/gateway/domain", {
1501
- cloudflareToken: args.cloudflareToken,
1502
- cloudflareAccountId: args.cloudflareAccountId,
1503
- domain: args.domain,
1504
- purchase: args.purchase,
1505
- gmailRelay: args.gmailRelay
1502
+ cloudflareToken: args2.cloudflareToken,
1503
+ cloudflareAccountId: args2.cloudflareAccountId,
1504
+ domain: args2.domain,
1505
+ purchase: args2.purchase,
1506
+ gmailRelay: args2.gmailRelay
1506
1507
  }, useMaster);
1507
1508
  if (!result) throw new Error("No response from domain setup");
1508
1509
  const lines = [
@@ -1542,8 +1543,8 @@ ${r.messages.map((m) => ` UID ${m.uid} (${m.folder})`).join("\n")}`;
1542
1543
  }
1543
1544
  case "setup_gmail_alias": {
1544
1545
  const result = await apiRequest("POST", "/gateway/domain/alias-setup", {
1545
- agentEmail: args.agentEmail,
1546
- agentDisplayName: args.agentDisplayName
1546
+ agentEmail: args2.agentEmail,
1547
+ agentDisplayName: args2.agentDisplayName
1547
1548
  }, useMaster);
1548
1549
  if (!result?.instructions) throw new Error("No response from alias setup");
1549
1550
  const lines = [
@@ -1580,8 +1581,8 @@ ${r.messages.map((m) => ` UID ${m.uid} (${m.folder})`).join("\n")}`;
1580
1581
  }
1581
1582
  case "purchase_domain": {
1582
1583
  const result = await apiRequest("POST", "/gateway/domain/purchase", {
1583
- keywords: args.keywords,
1584
- tld: args.tld
1584
+ keywords: args2.keywords,
1585
+ tld: args2.tld
1585
1586
  }, useMaster);
1586
1587
  if (!result?.domains?.length) return "No domains found.";
1587
1588
  const lines = result.domains.map(
@@ -1603,7 +1604,7 @@ ${lines.join("\n")}`;
1603
1604
  return lines.join("\n");
1604
1605
  }
1605
1606
  case "send_test_email": {
1606
- const result = await apiRequest("POST", "/gateway/test", { to: args.to }, useMaster);
1607
+ const result = await apiRequest("POST", "/gateway/test", { to: args2.to }, useMaster);
1607
1608
  return `Test email sent! Message ID: ${result?.messageId ?? "unknown"}`;
1608
1609
  }
1609
1610
  case "list_agents": {
@@ -1615,7 +1616,7 @@ ${lines.join("\n")}`;
1615
1616
  ${lines.join("\n")}`;
1616
1617
  }
1617
1618
  case "message_agent": {
1618
- const agentName = String(args.agent ?? "").toLowerCase().trim();
1619
+ const agentName = String(args2.agent ?? "").toLowerCase().trim();
1619
1620
  if (!agentName) throw new Error("agent name is required");
1620
1621
  try {
1621
1622
  await apiRequest("GET", `/accounts/directory/${encodeURIComponent(agentName)}`);
@@ -1623,9 +1624,9 @@ ${lines.join("\n")}`;
1623
1624
  throw new Error(`Agent "${agentName}" not found. Use list_agents to see available agents.`);
1624
1625
  }
1625
1626
  const to = `${agentName}@localhost`;
1626
- const priority = String(args.priority ?? "normal");
1627
- const subject = priority === "urgent" ? `[URGENT] ${args.subject}` : priority === "high" ? `[HIGH] ${args.subject}` : String(args.subject);
1628
- const result = await apiRequest("POST", "/mail/send", { to, subject, text: args.text });
1627
+ const priority = String(args2.priority ?? "normal");
1628
+ const subject = priority === "urgent" ? `[URGENT] ${args2.subject}` : priority === "high" ? `[HIGH] ${args2.subject}` : String(args2.subject);
1629
+ const result = await apiRequest("POST", "/mail/send", { to, subject, text: args2.text });
1629
1630
  return `Message sent to ${to}. Message ID: ${result?.messageId ?? "unknown"}`;
1630
1631
  }
1631
1632
  case "check_messages": {
@@ -1650,13 +1651,13 @@ ${lines.join("\n")}`;
1650
1651
  ${details.join("\n")}${more}`;
1651
1652
  }
1652
1653
  case "delete_agent": {
1653
- const agentName = String(args.name ?? "").trim();
1654
+ const agentName = String(args2.name ?? "").trim();
1654
1655
  if (!agentName) throw new Error("name is required");
1655
1656
  const agents = await apiRequest("GET", "/accounts", void 0, true);
1656
1657
  const fullAgent = agents?.agents?.find((a) => a.name === agentName);
1657
1658
  if (!fullAgent) throw new Error(`Agent "${agentName}" not found`);
1658
1659
  const qs = new URLSearchParams({ archive: "true", deletedBy: "mcp-tool" });
1659
- if (args.reason) qs.set("reason", String(args.reason));
1660
+ if (args2.reason) qs.set("reason", String(args2.reason));
1660
1661
  const report = await apiRequest("DELETE", `/accounts/${fullAgent.id}?${qs.toString()}`, void 0, true);
1661
1662
  const lines = [
1662
1663
  `Agent "${agentName}" deleted successfully.`,
@@ -1670,8 +1671,8 @@ ${details.join("\n")}${more}`;
1670
1671
  return lines.join("\n");
1671
1672
  }
1672
1673
  case "deletion_reports": {
1673
- if (args.id) {
1674
- const report = await apiRequest("GET", `/accounts/deletions/${encodeURIComponent(String(args.id))}`, void 0, true);
1674
+ if (args2.id) {
1675
+ const report = await apiRequest("GET", `/accounts/deletions/${encodeURIComponent(String(args2.id))}`, void 0, true);
1675
1676
  if (!report) throw new Error("Deletion report not found");
1676
1677
  const lines2 = [
1677
1678
  `Deletion Report: ${report.id}`,
@@ -1699,52 +1700,52 @@ ${details.join("\n")}${more}`;
1699
1700
  ${lines.join("\n")}`;
1700
1701
  }
1701
1702
  case "manage_signatures": {
1702
- if (args.action === "list") {
1703
+ if (args2.action === "list") {
1703
1704
  const r = await apiRequest("GET", "/signatures");
1704
1705
  if (!r?.signatures?.length) return "No signatures.";
1705
1706
  return r.signatures.map((s) => `[${s.id}] ${s.name}${s.isDefault ? " (default)" : ""}: ${s.text}`).join("\n");
1706
1707
  }
1707
- if (args.action === "create") {
1708
- if (!args.name || !args.text) throw new Error("name and text are required");
1709
- const r = await apiRequest("POST", "/signatures", { name: args.name, text: args.text, isDefault: args.isDefault });
1710
- return `Signature "${args.name}" created. ID: ${r?.id}`;
1708
+ if (args2.action === "create") {
1709
+ if (!args2.name || !args2.text) throw new Error("name and text are required");
1710
+ const r = await apiRequest("POST", "/signatures", { name: args2.name, text: args2.text, isDefault: args2.isDefault });
1711
+ return `Signature "${args2.name}" created. ID: ${r?.id}`;
1711
1712
  }
1712
- if (args.action === "delete") {
1713
- if (!args.id) throw new Error("id is required");
1714
- await apiRequest("DELETE", `/signatures/${args.id}`);
1713
+ if (args2.action === "delete") {
1714
+ if (!args2.id) throw new Error("id is required");
1715
+ await apiRequest("DELETE", `/signatures/${args2.id}`);
1715
1716
  return "Signature deleted.";
1716
1717
  }
1717
1718
  throw new Error("Invalid action. Use: list, create, or delete");
1718
1719
  }
1719
1720
  case "manage_templates": {
1720
- if (args.action === "list") {
1721
+ if (args2.action === "list") {
1721
1722
  const r = await apiRequest("GET", "/templates");
1722
1723
  if (!r?.templates?.length) return "No templates.";
1723
1724
  return r.templates.map((t) => `[${t.id}] ${t.name}: ${t.subject}`).join("\n");
1724
1725
  }
1725
- if (args.action === "create") {
1726
- if (!args.name || !args.subject || !args.text) throw new Error("name, subject, and text are required");
1727
- const r = await apiRequest("POST", "/templates", { name: args.name, subject: args.subject, text: args.text });
1728
- return `Template "${args.name}" created. ID: ${r?.id}`;
1726
+ if (args2.action === "create") {
1727
+ if (!args2.name || !args2.subject || !args2.text) throw new Error("name, subject, and text are required");
1728
+ const r = await apiRequest("POST", "/templates", { name: args2.name, subject: args2.subject, text: args2.text });
1729
+ return `Template "${args2.name}" created. ID: ${r?.id}`;
1729
1730
  }
1730
- if (args.action === "delete") {
1731
- if (!args.id) throw new Error("id is required");
1732
- await apiRequest("DELETE", `/templates/${args.id}`);
1731
+ if (args2.action === "delete") {
1732
+ if (!args2.id) throw new Error("id is required");
1733
+ await apiRequest("DELETE", `/templates/${args2.id}`);
1733
1734
  return "Template deleted.";
1734
1735
  }
1735
1736
  throw new Error("Invalid action. Use: list, create, or delete");
1736
1737
  }
1737
1738
  case "batch_mark_unread": {
1738
- const uids = args.uids;
1739
+ const uids = args2.uids;
1739
1740
  if (!Array.isArray(uids) || uids.length === 0) throw new Error("uids array required");
1740
- await apiRequest("POST", "/mail/batch/unseen", { uids, folder: args.folder });
1741
+ await apiRequest("POST", "/mail/batch/unseen", { uids, folder: args2.folder });
1741
1742
  return `Marked ${uids.length} messages as unread.`;
1742
1743
  }
1743
1744
  case "batch_move": {
1744
- const uids = args.uids;
1745
+ const uids = args2.uids;
1745
1746
  if (!Array.isArray(uids) || uids.length === 0) throw new Error("uids array required");
1746
- await apiRequest("POST", "/mail/batch/move", { uids, from: args.from || "INBOX", to: args.to });
1747
- return `Moved ${uids.length} messages to ${args.to}.`;
1747
+ await apiRequest("POST", "/mail/batch/move", { uids, from: args2.from || "INBOX", to: args2.to });
1748
+ return `Moved ${uids.length} messages to ${args2.to}.`;
1748
1749
  }
1749
1750
  case "whoami": {
1750
1751
  const result = await apiRequest("GET", "/accounts/me");
@@ -1759,8 +1760,8 @@ ${lines.join("\n")}`;
1759
1760
  ].filter(Boolean).join("\n");
1760
1761
  }
1761
1762
  case "update_metadata": {
1762
- if (!args.metadata || typeof args.metadata !== "object") throw new Error("metadata object is required");
1763
- const result = await apiRequest("PATCH", "/accounts/me", { metadata: args.metadata });
1763
+ if (!args2.metadata || typeof args2.metadata !== "object") throw new Error("metadata object is required");
1764
+ const result = await apiRequest("PATCH", "/accounts/me", { metadata: args2.metadata });
1764
1765
  return `Metadata updated successfully. Agent: ${result?.name ?? "unknown"}`;
1765
1766
  }
1766
1767
  case "check_health": {
@@ -1769,7 +1770,7 @@ ${lines.join("\n")}`;
1769
1770
  return `\u{1F380} AgenticMail server: ${result.status ?? "ok"}${result.stalwart ? `, Stalwart: ${result.stalwart}` : ""}`;
1770
1771
  }
1771
1772
  case "wait_for_email": {
1772
- const timeoutSec = Math.min(Math.max(Number(args.timeout) || 120, 5), 300);
1773
+ const timeoutSec = Math.min(Math.max(Number(args2.timeout) || 120, 5), 300);
1773
1774
  const controller = new AbortController();
1774
1775
  const timer = setTimeout(() => controller.abort(), timeoutSec * 1e3);
1775
1776
  try {
@@ -1884,9 +1885,9 @@ ${lines.join("\n")}`;
1884
1885
  }
1885
1886
  }
1886
1887
  case "batch_read": {
1887
- const uids = args.uids;
1888
+ const uids = args2.uids;
1888
1889
  if (!Array.isArray(uids) || uids.length === 0) throw new Error("uids array required");
1889
- const result = await apiRequest("POST", "/mail/batch/read", { uids, folder: args.folder });
1890
+ const result = await apiRequest("POST", "/mail/batch/read", { uids, folder: args2.folder });
1890
1891
  if (!result?.messages?.length) return "No messages found for the given UIDs.";
1891
1892
  const lines = result.messages.map((m) => {
1892
1893
  const from = m.from?.map((a) => a.address).join(", ") ?? "unknown";
@@ -1899,10 +1900,10 @@ ${lines.join("\n\n---\n\n")}`;
1899
1900
  }
1900
1901
  case "inbox_digest": {
1901
1902
  const qs = new URLSearchParams();
1902
- if (args.limit) qs.set("limit", String(args.limit));
1903
- if (args.offset) qs.set("offset", String(args.offset));
1904
- if (args.folder) qs.set("folder", String(args.folder));
1905
- if (args.previewLength) qs.set("previewLength", String(args.previewLength));
1903
+ if (args2.limit) qs.set("limit", String(args2.limit));
1904
+ if (args2.offset) qs.set("offset", String(args2.offset));
1905
+ if (args2.folder) qs.set("folder", String(args2.folder));
1906
+ if (args2.previewLength) qs.set("previewLength", String(args2.previewLength));
1906
1907
  const query = qs.toString();
1907
1908
  const result = await apiRequest("GET", `/mail/digest${query ? "?" + query : ""}`);
1908
1909
  if (!result?.messages?.length) return "Inbox is empty.";
@@ -1916,16 +1917,16 @@ ${lines.join("\n\n---\n\n")}`;
1916
1917
  ${lines.join("\n")}`;
1917
1918
  }
1918
1919
  case "template_send": {
1919
- const result = await apiRequest("POST", `/templates/${args.id}/send`, {
1920
- to: args.to,
1921
- variables: args.variables,
1922
- cc: args.cc,
1923
- bcc: args.bcc
1920
+ const result = await apiRequest("POST", `/templates/${args2.id}/send`, {
1921
+ to: args2.to,
1922
+ variables: args2.variables,
1923
+ cc: args2.cc,
1924
+ bcc: args2.bcc
1924
1925
  });
1925
1926
  return `Template email sent. Message ID: ${result?.messageId ?? "unknown"}`;
1926
1927
  }
1927
1928
  case "manage_rules": {
1928
- if (args.action === "list") {
1929
+ if (args2.action === "list") {
1929
1930
  const r = await apiRequest("GET", "/rules");
1930
1931
  if (!r?.rules?.length) return "No email rules configured.";
1931
1932
  return r.rules.map(
@@ -1934,25 +1935,25 @@ ${lines.join("\n")}`;
1934
1935
  Actions: ${JSON.stringify(rule.actions)}`
1935
1936
  ).join("\n");
1936
1937
  }
1937
- if (args.action === "create") {
1938
+ if (args2.action === "create") {
1938
1939
  const r = await apiRequest("POST", "/rules", {
1939
- name: args.name,
1940
- priority: args.priority,
1941
- conditions: args.conditions,
1942
- actions: args.actions
1940
+ name: args2.name,
1941
+ priority: args2.priority,
1942
+ conditions: args2.conditions,
1943
+ actions: args2.actions
1943
1944
  });
1944
1945
  return `Rule "${r?.name}" created. ID: ${r?.id}`;
1945
1946
  }
1946
- if (args.action === "delete") {
1947
- if (!args.id) throw new Error("id is required");
1948
- await apiRequest("DELETE", `/rules/${args.id}`);
1947
+ if (args2.action === "delete") {
1948
+ if (!args2.id) throw new Error("id is required");
1949
+ await apiRequest("DELETE", `/rules/${args2.id}`);
1949
1950
  return "Rule deleted.";
1950
1951
  }
1951
1952
  throw new Error("Invalid action. Use: list, create, or delete");
1952
1953
  }
1953
1954
  case "cleanup_agents": {
1954
- if (args.action === "list_inactive") {
1955
- const qs = args.hours ? `?hours=${args.hours}` : "";
1955
+ if (args2.action === "list_inactive") {
1956
+ const qs = args2.hours ? `?hours=${args2.hours}` : "";
1956
1957
  const r = await apiRequest("GET", `/accounts/inactive${qs}`, void 0, true);
1957
1958
  if (!r?.agents?.length) return "No inactive agents found. All agents are either active or persistent.";
1958
1959
  return `${r.count} inactive agent(s):
@@ -1960,8 +1961,8 @@ ${r.agents.map(
1960
1961
  (a) => ` ${a.name} (${a.email}) \u2014 last active: ${a.last_activity_at || "never"}, persistent: ${a.persistent}`
1961
1962
  ).join("\n")}`;
1962
1963
  }
1963
- if (args.action === "cleanup") {
1964
- const r = await apiRequest("POST", "/accounts/cleanup", { hours: args.hours, dryRun: args.dryRun }, true);
1964
+ if (args2.action === "cleanup") {
1965
+ const r = await apiRequest("POST", "/accounts/cleanup", { hours: args2.hours, dryRun: args2.dryRun }, true);
1965
1966
  if (r?.dryRun) {
1966
1967
  if (!r.count) return "No inactive agents to clean up. All agents are either active or persistent.";
1967
1968
  return `Would delete ${r.count} agent(s): ${r.wouldDelete.map((a) => a.name).join(", ")}`;
@@ -1969,39 +1970,39 @@ ${r.agents.map(
1969
1970
  if (!r?.count) return "No inactive agents to clean up. All agents are either active or persistent.";
1970
1971
  return `Deleted ${r.count} agent(s): ${r.deleted.join(", ")}`;
1971
1972
  }
1972
- if (args.action === "set_persistent") {
1973
- if (!args.agentId) throw new Error("agentId is required");
1974
- await apiRequest("PATCH", `/accounts/${args.agentId}/persistent`, { persistent: args.persistent !== false }, true);
1975
- return `Agent ${args.agentId} persistent flag set to ${args.persistent !== false}`;
1973
+ if (args2.action === "set_persistent") {
1974
+ if (!args2.agentId) throw new Error("agentId is required");
1975
+ await apiRequest("PATCH", `/accounts/${args2.agentId}/persistent`, { persistent: args2.persistent !== false }, true);
1976
+ return `Agent ${args2.agentId} persistent flag set to ${args2.persistent !== false}`;
1976
1977
  }
1977
1978
  throw new Error("Invalid action. Use: list_inactive, cleanup, or set_persistent");
1978
1979
  }
1979
1980
  case "check_tasks": {
1980
- let endpoint = args.direction === "outgoing" ? "/tasks/assigned" : "/tasks/pending";
1981
- if (args.direction !== "outgoing" && args.assignee) {
1982
- endpoint += `?assignee=${encodeURIComponent(args.assignee)}`;
1981
+ let endpoint = args2.direction === "outgoing" ? "/tasks/assigned" : "/tasks/pending";
1982
+ if (args2.direction !== "outgoing" && args2.assignee) {
1983
+ endpoint += `?assignee=${encodeURIComponent(args2.assignee)}`;
1983
1984
  }
1984
1985
  const r = await apiRequest("GET", endpoint);
1985
- if (!r?.tasks?.length) return args.direction === "outgoing" ? "No tasks assigned by you." : "No pending tasks.";
1986
+ if (!r?.tasks?.length) return args2.direction === "outgoing" ? "No tasks assigned by you." : "No pending tasks.";
1986
1987
  return `${r.count} tasks:
1987
1988
  ${r.tasks.map(
1988
1989
  (t) => ` [${t.id.slice(0, 8)}] ${t.taskType} \u2014 status: ${t.status}, payload: ${JSON.stringify(t.payload).slice(0, 100)}`
1989
1990
  ).join("\n")}`;
1990
1991
  }
1991
1992
  case "claim_task": {
1992
- const r = await apiRequest("POST", `/tasks/${args.id}/claim`);
1993
+ const r = await apiRequest("POST", `/tasks/${args2.id}/claim`);
1993
1994
  return `Task ${r?.id} claimed. Payload: ${JSON.stringify(r?.payload)}`;
1994
1995
  }
1995
1996
  case "submit_result": {
1996
- await apiRequest("POST", `/tasks/${args.id}/result`, { result: args.result });
1997
- return `Result submitted for task ${args.id}.`;
1997
+ await apiRequest("POST", `/tasks/${args2.id}/result`, { result: args2.result });
1998
+ return `Result submitted for task ${args2.id}.`;
1998
1999
  }
1999
2000
  case "call_agent": {
2000
- const timeoutSec = Math.min(Math.max(Number(args.timeout) || 180, 5), 300);
2001
+ const timeoutSec = Math.min(Math.max(Number(args2.timeout) || 180, 5), 300);
2001
2002
  const created = await apiRequest("POST", "/tasks/assign", {
2002
- assignee: args.target,
2003
+ assignee: args2.target,
2003
2004
  taskType: "rpc",
2004
- payload: { task: args.task, ...args.payload || {} }
2005
+ payload: { task: args2.task, ...args2.payload || {} }
2005
2006
  });
2006
2007
  if (!created?.id) throw new Error("Failed to create task");
2007
2008
  const taskId = created.id;
@@ -2018,11 +2019,11 @@ ${r.tasks.map(
2018
2019
  return `RPC timed out. Task ID: ${taskId} \u2014 check later with check_tasks.`;
2019
2020
  }
2020
2021
  case "manage_spam": {
2021
- const action = args.action;
2022
+ const action = args2.action;
2022
2023
  if (action === "list") {
2023
2024
  const qs = new URLSearchParams();
2024
- if (args.limit) qs.set("limit", String(args.limit));
2025
- if (args.offset) qs.set("offset", String(args.offset));
2025
+ if (args2.limit) qs.set("limit", String(args2.limit));
2026
+ if (args2.offset) qs.set("offset", String(args2.offset));
2026
2027
  const query = qs.toString();
2027
2028
  const result = await apiRequest("GET", `/mail/spam${query ? "?" + query : ""}`);
2028
2029
  if (!result?.messages?.length) return "Spam folder is empty.";
@@ -2031,21 +2032,21 @@ ${r.tasks.map(
2031
2032
  ${lines.join("\n")}`;
2032
2033
  }
2033
2034
  if (action === "report") {
2034
- const uid = Number(args.uid);
2035
+ const uid = Number(args2.uid);
2035
2036
  if (!uid || uid < 1) throw new Error("uid is required");
2036
- await apiRequest("POST", `/mail/messages/${uid}/spam`, { folder: args.folder || "INBOX" });
2037
+ await apiRequest("POST", `/mail/messages/${uid}/spam`, { folder: args2.folder || "INBOX" });
2037
2038
  return `Message UID ${uid} moved to Spam.`;
2038
2039
  }
2039
2040
  if (action === "not_spam") {
2040
- const uid = Number(args.uid);
2041
+ const uid = Number(args2.uid);
2041
2042
  if (!uid || uid < 1) throw new Error("uid is required");
2042
2043
  await apiRequest("POST", `/mail/messages/${uid}/not-spam`);
2043
2044
  return `Message UID ${uid} moved from Spam to INBOX.`;
2044
2045
  }
2045
2046
  if (action === "score") {
2046
- const uid = Number(args.uid);
2047
+ const uid = Number(args2.uid);
2047
2048
  if (!uid || uid < 1) throw new Error("uid is required");
2048
- const folder = args.folder || "INBOX";
2049
+ const folder = args2.folder || "INBOX";
2049
2050
  const result = await apiRequest("GET", `/mail/messages/${uid}/spam-score?folder=${encodeURIComponent(folder)}`);
2050
2051
  const lines = [
2051
2052
  `Spam Score: ${result.score}/100 (${result.isSpam ? "SPAM" : result.isWarning ? "WARNING" : "CLEAN"})`,
@@ -2062,7 +2063,7 @@ ${lines.join("\n")}`;
2062
2063
  throw new Error("Invalid action. Use: list, report, not_spam, or score");
2063
2064
  }
2064
2065
  case "manage_pending_emails": {
2065
- const action = String(args.action);
2066
+ const action = String(args2.action);
2066
2067
  if (action === "list") {
2067
2068
  const result = await apiRequest("GET", "/mail/pending");
2068
2069
  if (result?.pending) {
@@ -2076,10 +2077,10 @@ ${lines.join("\n")}`;
2076
2077
  ${lines.join("\n")}`);
2077
2078
  }
2078
2079
  if (action === "get") {
2079
- if (!args.id) throw new Error("id is required");
2080
- const result = await apiRequest("GET", `/mail/pending/${encodeURIComponent(String(args.id))}`);
2080
+ if (!args2.id) throw new Error("id is required");
2081
+ const result = await apiRequest("GET", `/mail/pending/${encodeURIComponent(String(args2.id))}`);
2081
2082
  if (!result) throw new Error("Pending email not found");
2082
- if (result.status !== "pending") cancelFollowUp(String(args.id));
2083
+ if (result.status !== "pending") cancelFollowUp(String(args2.id));
2083
2084
  return withReminders(`Pending Email: ${result.id}
2084
2085
  To: ${result.mailOptions?.to}
2085
2086
  Subject: ${result.mailOptions?.subject}
@@ -2096,106 +2097,106 @@ ${result.summary}`);
2096
2097
  // --- SMS / Google Voice Tools ---
2097
2098
  case "sms_setup": {
2098
2099
  const result = await apiRequest("POST", "/sms/setup", {
2099
- phoneNumber: args.phoneNumber,
2100
- forwardingEmail: args.forwardingEmail,
2100
+ phoneNumber: args2.phoneNumber,
2101
+ forwardingEmail: args2.forwardingEmail,
2101
2102
  provider: "google_voice"
2102
2103
  });
2103
2104
  return JSON.stringify(result, null, 2);
2104
2105
  }
2105
2106
  case "sms_send": {
2106
2107
  const result = await apiRequest("POST", "/sms/send", {
2107
- to: args.to,
2108
- body: args.body
2108
+ to: args2.to,
2109
+ body: args2.body
2109
2110
  });
2110
2111
  return JSON.stringify(result, null, 2);
2111
2112
  }
2112
2113
  case "sms_messages": {
2113
2114
  const query = new URLSearchParams();
2114
- if (args.direction) query.set("direction", String(args.direction));
2115
- if (args.limit) query.set("limit", String(args.limit));
2116
- if (args.offset) query.set("offset", String(args.offset));
2115
+ if (args2.direction) query.set("direction", String(args2.direction));
2116
+ if (args2.limit) query.set("limit", String(args2.limit));
2117
+ if (args2.offset) query.set("offset", String(args2.offset));
2117
2118
  const result = await apiRequest("GET", `/sms/messages?${query.toString()}`);
2118
2119
  return JSON.stringify(result, null, 2);
2119
2120
  }
2120
2121
  case "sms_check_code": {
2121
- const query = args.minutes ? `?minutes=${args.minutes}` : "";
2122
+ const query = args2.minutes ? `?minutes=${args2.minutes}` : "";
2122
2123
  const result = await apiRequest("GET", `/sms/verification-code${query}`);
2123
2124
  return JSON.stringify(result, null, 2);
2124
2125
  }
2125
2126
  case "sms_parse_email": {
2126
2127
  const result = await apiRequest("POST", "/sms/parse-email", {
2127
- emailBody: args.emailBody,
2128
- emailFrom: args.emailFrom
2128
+ emailBody: args2.emailBody,
2129
+ emailFrom: args2.emailFrom
2129
2130
  });
2130
2131
  return JSON.stringify(result, null, 2);
2131
2132
  }
2132
2133
  case "storage": {
2133
- const act = args.action;
2134
- const tbl = args.table ? encodeURIComponent(args.table) : "";
2134
+ const act = args2.action;
2135
+ const tbl = args2.table ? encodeURIComponent(args2.table) : "";
2135
2136
  let result;
2136
2137
  switch (act) {
2137
2138
  // DDL
2138
2139
  case "create_table":
2139
- result = await apiRequest("POST", "/storage/tables", { name: args.table, columns: args.columns, indexes: args.indexes, shared: args.shared, description: args.description, timestamps: args.timestamps });
2140
+ result = await apiRequest("POST", "/storage/tables", { name: args2.table, columns: args2.columns, indexes: args2.indexes, shared: args2.shared, description: args2.description, timestamps: args2.timestamps });
2140
2141
  break;
2141
2142
  case "list_tables":
2142
- result = await apiRequest("GET", `/storage/tables?includeShared=${args.includeShared !== false}&includeArchived=${args.includeArchived === true}`);
2143
+ result = await apiRequest("GET", `/storage/tables?includeShared=${args2.includeShared !== false}&includeArchived=${args2.includeArchived === true}`);
2143
2144
  break;
2144
2145
  case "describe_table":
2145
2146
  result = await apiRequest("GET", `/storage/tables/${tbl}/describe`);
2146
2147
  break;
2147
2148
  case "add_column":
2148
- result = await apiRequest("POST", `/storage/tables/${tbl}/columns`, { column: args.column });
2149
+ result = await apiRequest("POST", `/storage/tables/${tbl}/columns`, { column: args2.column });
2149
2150
  break;
2150
2151
  case "drop_column":
2151
- result = await apiRequest("DELETE", `/storage/tables/${tbl}/columns/${encodeURIComponent(args.columnName)}`);
2152
+ result = await apiRequest("DELETE", `/storage/tables/${tbl}/columns/${encodeURIComponent(args2.columnName)}`);
2152
2153
  break;
2153
2154
  case "rename_table":
2154
- result = await apiRequest("POST", `/storage/tables/${tbl}/rename`, { newName: args.newName });
2155
+ result = await apiRequest("POST", `/storage/tables/${tbl}/rename`, { newName: args2.newName });
2155
2156
  break;
2156
2157
  case "rename_column":
2157
- result = await apiRequest("POST", `/storage/tables/${tbl}/rename-column`, { oldName: args.oldName, newName: args.newName });
2158
+ result = await apiRequest("POST", `/storage/tables/${tbl}/rename-column`, { oldName: args2.oldName, newName: args2.newName });
2158
2159
  break;
2159
2160
  case "drop_table":
2160
2161
  result = await apiRequest("DELETE", `/storage/tables/${tbl}`);
2161
2162
  break;
2162
2163
  case "clone_table":
2163
- result = await apiRequest("POST", `/storage/tables/${tbl}/clone`, { newName: args.newName, includeData: args.includeData });
2164
+ result = await apiRequest("POST", `/storage/tables/${tbl}/clone`, { newName: args2.newName, includeData: args2.includeData });
2164
2165
  break;
2165
2166
  case "truncate":
2166
2167
  result = await apiRequest("POST", `/storage/tables/${tbl}/truncate`);
2167
2168
  break;
2168
2169
  // Indexes
2169
2170
  case "create_index":
2170
- result = await apiRequest("POST", `/storage/tables/${tbl}/indexes`, { columns: args.indexColumns || args.columns, unique: args.indexUnique, name: args.indexName, where: args.indexWhere });
2171
+ result = await apiRequest("POST", `/storage/tables/${tbl}/indexes`, { columns: args2.indexColumns || args2.columns, unique: args2.indexUnique, name: args2.indexName, where: args2.indexWhere });
2171
2172
  break;
2172
2173
  case "list_indexes":
2173
2174
  result = await apiRequest("GET", `/storage/tables/${tbl}/indexes`);
2174
2175
  break;
2175
2176
  case "drop_index":
2176
- result = await apiRequest("DELETE", `/storage/tables/${tbl}/indexes/${encodeURIComponent(args.indexName)}`);
2177
+ result = await apiRequest("DELETE", `/storage/tables/${tbl}/indexes/${encodeURIComponent(args2.indexName)}`);
2177
2178
  break;
2178
2179
  case "reindex":
2179
2180
  result = await apiRequest("POST", `/storage/tables/${tbl}/reindex`);
2180
2181
  break;
2181
2182
  // DML
2182
2183
  case "insert":
2183
- result = await apiRequest("POST", "/storage/insert", { table: args.table, rows: args.rows });
2184
+ result = await apiRequest("POST", "/storage/insert", { table: args2.table, rows: args2.rows });
2184
2185
  break;
2185
2186
  case "upsert":
2186
- result = await apiRequest("POST", "/storage/upsert", { table: args.table, rows: args.rows, conflictColumn: args.conflictColumn });
2187
+ result = await apiRequest("POST", "/storage/upsert", { table: args2.table, rows: args2.rows, conflictColumn: args2.conflictColumn });
2187
2188
  break;
2188
2189
  case "query":
2189
- result = await apiRequest("POST", "/storage/query", { table: args.table, where: args.where, orderBy: args.orderBy, limit: args.limit, offset: args.offset, columns: args.selectColumns, distinct: args.distinct, groupBy: args.groupBy, having: args.having });
2190
+ result = await apiRequest("POST", "/storage/query", { table: args2.table, where: args2.where, orderBy: args2.orderBy, limit: args2.limit, offset: args2.offset, columns: args2.selectColumns, distinct: args2.distinct, groupBy: args2.groupBy, having: args2.having });
2190
2191
  break;
2191
2192
  case "aggregate":
2192
- result = await apiRequest("POST", "/storage/aggregate", { table: args.table, where: args.where, operations: args.operations, groupBy: args.groupBy });
2193
+ result = await apiRequest("POST", "/storage/aggregate", { table: args2.table, where: args2.where, operations: args2.operations, groupBy: args2.groupBy });
2193
2194
  break;
2194
2195
  case "update":
2195
- result = await apiRequest("POST", "/storage/update", { table: args.table, where: args.where, set: args.set });
2196
+ result = await apiRequest("POST", "/storage/update", { table: args2.table, where: args2.where, set: args2.set });
2196
2197
  break;
2197
2198
  case "delete_rows":
2198
- result = await apiRequest("POST", "/storage/delete-rows", { table: args.table, where: args.where });
2199
+ result = await apiRequest("POST", "/storage/delete-rows", { table: args2.table, where: args2.where });
2199
2200
  break;
2200
2201
  // Archive
2201
2202
  case "archive_table":
@@ -2206,17 +2207,17 @@ ${result.summary}`);
2206
2207
  break;
2207
2208
  // Import/Export
2208
2209
  case "export":
2209
- result = await apiRequest("POST", `/storage/tables/${tbl}/export`, { format: args.format, where: args.where, limit: args.limit });
2210
+ result = await apiRequest("POST", `/storage/tables/${tbl}/export`, { format: args2.format, where: args2.where, limit: args2.limit });
2210
2211
  break;
2211
2212
  case "import":
2212
- result = await apiRequest("POST", `/storage/tables/${tbl}/import`, { rows: args.rows, onConflict: args.onConflict, conflictColumn: args.conflictColumn });
2213
+ result = await apiRequest("POST", `/storage/tables/${tbl}/import`, { rows: args2.rows, onConflict: args2.onConflict, conflictColumn: args2.conflictColumn });
2213
2214
  break;
2214
2215
  // Raw SQL
2215
2216
  case "sql":
2216
- result = await apiRequest("POST", "/storage/sql", { sql: args.sql, params: args.params });
2217
+ result = await apiRequest("POST", "/storage/sql", { sql: args2.sql, params: args2.params });
2217
2218
  break;
2218
2219
  case "explain":
2219
- result = await apiRequest("POST", "/storage/explain", { sql: args.sql, params: args.params });
2220
+ result = await apiRequest("POST", "/storage/explain", { sql: args2.sql, params: args2.params });
2220
2221
  break;
2221
2222
  // Maintenance
2222
2223
  case "stats":
@@ -2255,8 +2256,8 @@ ${result.summary}`);
2255
2256
  }
2256
2257
  case "sms_record": {
2257
2258
  const result = await apiRequest("POST", "/sms/record", {
2258
- from: args.from,
2259
- body: args.body
2259
+ from: args2.from,
2260
+ body: args2.body
2260
2261
  });
2261
2262
  return JSON.stringify(result, null, 2);
2262
2263
  }
@@ -2322,64 +2323,158 @@ ${lines.join("\n")}`;
2322
2323
 
2323
2324
  // src/index.ts
2324
2325
  import { setTelemetryVersion } from "@agenticmail/core";
2325
- setTelemetryVersion("0.5.39");
2326
- var server = new McpServer({
2327
- name: "\u{1F380} AgenticMail",
2328
- version: "0.2.26",
2329
- description: "\u{1F380} AgenticMail \u2014 Email infrastructure for AI agents. By Ope Olatunji (https://github.com/agenticmail/agenticmail)"
2330
- });
2331
- for (const tool of toolDefinitions) {
2332
- server.tool(
2333
- tool.name,
2334
- tool.description,
2335
- tool.inputSchema,
2336
- async ({ arguments: args }) => {
2337
- try {
2338
- const result = await handleToolCall(tool.name, args);
2339
- return { content: [{ type: "text", text: result }] };
2340
- } catch (err) {
2341
- const message = err instanceof Error ? err.message : String(err);
2342
- return {
2343
- content: [{ type: "text", text: `Error: ${message}` }],
2344
- isError: true
2345
- };
2326
+ import { createServer } from "http";
2327
+ import { randomUUID } from "crypto";
2328
+ setTelemetryVersion("0.5.50");
2329
+ function createMcpServer() {
2330
+ const server = new McpServer({
2331
+ name: "\u{1F380} AgenticMail",
2332
+ version: "0.2.27",
2333
+ description: "\u{1F380} AgenticMail \u2014 Email infrastructure for AI agents. By Ope Olatunji (https://github.com/agenticmail/agenticmail)"
2334
+ });
2335
+ for (const tool of toolDefinitions) {
2336
+ server.tool(
2337
+ tool.name,
2338
+ tool.description,
2339
+ tool.inputSchema,
2340
+ async ({ arguments: args2 }) => {
2341
+ try {
2342
+ const result = await handleToolCall(tool.name, args2);
2343
+ return { content: [{ type: "text", text: result }] };
2344
+ } catch (err) {
2345
+ const message = err instanceof Error ? err.message : String(err);
2346
+ return {
2347
+ content: [{ type: "text", text: `Error: ${message}` }],
2348
+ isError: true
2349
+ };
2350
+ }
2346
2351
  }
2347
- }
2348
- );
2352
+ );
2353
+ }
2354
+ for (const resource of resourceDefinitions) {
2355
+ server.resource(
2356
+ resource.name,
2357
+ resource.uri,
2358
+ { description: resource.description, mimeType: resource.mimeType },
2359
+ async () => {
2360
+ try {
2361
+ const content = await handleResourceRead(resource.uri);
2362
+ return {
2363
+ contents: [{ uri: resource.uri, text: content, mimeType: resource.mimeType }]
2364
+ };
2365
+ } catch (err) {
2366
+ const message = err instanceof Error ? err.message : String(err);
2367
+ return {
2368
+ contents: [{ uri: resource.uri, text: `Error: ${message}`, mimeType: "text/plain" }]
2369
+ };
2370
+ }
2371
+ }
2372
+ );
2373
+ }
2374
+ return server;
2349
2375
  }
2350
- for (const resource of resourceDefinitions) {
2351
- server.resource(
2352
- resource.name,
2353
- resource.uri,
2354
- { description: resource.description, mimeType: resource.mimeType },
2355
- async () => {
2376
+ var args = process.argv.slice(2);
2377
+ var httpFlag = args.includes("--http");
2378
+ var portArg = args.find((a) => a.startsWith("--port="));
2379
+ var httpPort = portArg ? parseInt(portArg.split("=")[1], 10) : parseInt(process.env.MCP_PORT || "", 10) || 8014;
2380
+ if (httpFlag || process.env.MCP_HTTP === "1") {
2381
+ const server = createMcpServer();
2382
+ const transports = /* @__PURE__ */ new Map();
2383
+ const httpServer = createServer(async (req, res) => {
2384
+ const url = new URL(req.url ?? "/", `http://localhost:${httpPort}`);
2385
+ const path = url.pathname;
2386
+ if (path === "/health" && req.method === "GET") {
2387
+ res.writeHead(200, { "Content-Type": "application/json" });
2388
+ res.end(JSON.stringify({ status: "ok", transport: "streamable-http", sessions: transports.size }));
2389
+ return;
2390
+ }
2391
+ if (path !== "/mcp") {
2392
+ res.writeHead(404, { "Content-Type": "application/json" });
2393
+ res.end(JSON.stringify({ error: "Not found. MCP endpoint is POST /mcp" }));
2394
+ return;
2395
+ }
2396
+ if (req.method === "DELETE") {
2397
+ const sessionId = req.headers["mcp-session-id"];
2398
+ if (sessionId && transports.has(sessionId)) {
2399
+ const transport = transports.get(sessionId);
2400
+ await transport.handleRequest(req, res);
2401
+ transports.delete(sessionId);
2402
+ } else {
2403
+ res.writeHead(400, { "Content-Type": "application/json" });
2404
+ res.end(JSON.stringify({ error: "Invalid or missing session ID" }));
2405
+ }
2406
+ return;
2407
+ }
2408
+ if (req.method === "GET") {
2409
+ const sessionId = req.headers["mcp-session-id"];
2410
+ if (sessionId && transports.has(sessionId)) {
2411
+ const transport = transports.get(sessionId);
2412
+ await transport.handleRequest(req, res);
2413
+ } else {
2414
+ res.writeHead(400, { "Content-Type": "application/json" });
2415
+ res.end(JSON.stringify({ error: "Invalid or missing session ID for SSE stream. Send a POST /mcp with initialize first." }));
2416
+ }
2417
+ return;
2418
+ }
2419
+ if (req.method === "POST") {
2420
+ const sessionId = req.headers["mcp-session-id"];
2421
+ if (sessionId && transports.has(sessionId)) {
2422
+ const transport2 = transports.get(sessionId);
2423
+ await transport2.handleRequest(req, res);
2424
+ return;
2425
+ }
2426
+ const transport = new StreamableHTTPServerTransport({
2427
+ sessionIdGenerator: () => randomUUID(),
2428
+ onsessioninitialized: (sid) => {
2429
+ transports.set(sid, transport);
2430
+ }
2431
+ });
2432
+ transport.onclose = () => {
2433
+ const sid = transport.sessionId;
2434
+ if (sid) transports.delete(sid);
2435
+ };
2436
+ const sessionServer = createMcpServer();
2437
+ await sessionServer.connect(transport);
2438
+ await transport.handleRequest(req, res);
2439
+ return;
2440
+ }
2441
+ res.writeHead(405, { "Allow": "GET, POST, DELETE", "Content-Type": "application/json" });
2442
+ res.end(JSON.stringify({ error: "Method not allowed. Use POST /mcp for JSON-RPC, GET /mcp for SSE stream." }));
2443
+ });
2444
+ httpServer.listen(httpPort, () => {
2445
+ console.log(`\u{1F380} AgenticMail MCP Server (Streamable HTTP)`);
2446
+ console.log(` Endpoint: http://localhost:${httpPort}/mcp`);
2447
+ console.log(` Health: http://localhost:${httpPort}/health`);
2448
+ console.log(` Transport: Streamable HTTP (SSE + JSON responses)`);
2449
+ });
2450
+ async function shutdown() {
2451
+ for (const transport of transports.values()) {
2356
2452
  try {
2357
- const content = await handleResourceRead(resource.uri);
2358
- return {
2359
- contents: [{ uri: resource.uri, text: content, mimeType: resource.mimeType }]
2360
- };
2361
- } catch (err) {
2362
- const message = err instanceof Error ? err.message : String(err);
2363
- return {
2364
- contents: [{ uri: resource.uri, text: `Error: ${message}`, mimeType: "text/plain" }]
2365
- };
2453
+ await transport.close();
2454
+ } catch {
2366
2455
  }
2367
2456
  }
2368
- );
2369
- }
2370
- var transport = new StdioServerTransport();
2371
- try {
2372
- await server.connect(transport);
2373
- } catch (err) {
2374
- console.error("[agenticmail-mcp] Failed to start:", err);
2375
- process.exit(1);
2376
- }
2377
- async function shutdown() {
2457
+ httpServer.close();
2458
+ process.exit(0);
2459
+ }
2460
+ process.on("SIGTERM", () => shutdown());
2461
+ process.on("SIGINT", () => shutdown());
2462
+ } else {
2463
+ const server = createMcpServer();
2464
+ const transport = new StdioServerTransport();
2378
2465
  try {
2379
- await server.close();
2380
- } catch {
2466
+ await server.connect(transport);
2467
+ } catch (err) {
2468
+ console.error("[agenticmail-mcp] Failed to start:", err);
2469
+ process.exit(1);
2470
+ }
2471
+ async function shutdown() {
2472
+ try {
2473
+ await server.close();
2474
+ } catch {
2475
+ }
2476
+ process.exit(0);
2381
2477
  }
2382
- process.exit(0);
2478
+ process.on("SIGTERM", () => shutdown());
2479
+ process.on("SIGINT", () => shutdown());
2383
2480
  }
2384
- process.on("SIGTERM", () => shutdown());
2385
- process.on("SIGINT", () => shutdown());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticmail/mcp",
3
- "version": "0.5.49",
3
+ "version": "0.5.51",
4
4
  "description": "MCP server for AgenticMail — give any AI client real email and SMS capabilities",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",