@ni-c/imap-mcp 0.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.
Files changed (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +308 -0
  3. package/dist/analyze.d.ts +129 -0
  4. package/dist/analyze.js +313 -0
  5. package/dist/analyze.js.map +1 -0
  6. package/dist/approval.d.ts +45 -0
  7. package/dist/approval.js +69 -0
  8. package/dist/approval.js.map +1 -0
  9. package/dist/attachments.d.ts +55 -0
  10. package/dist/attachments.js +270 -0
  11. package/dist/attachments.js.map +1 -0
  12. package/dist/audit.d.ts +17 -0
  13. package/dist/audit.js +33 -0
  14. package/dist/audit.js.map +1 -0
  15. package/dist/config.d.ts +75 -0
  16. package/dist/config.js +202 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/confirm.d.ts +59 -0
  19. package/dist/confirm.js +92 -0
  20. package/dist/confirm.js.map +1 -0
  21. package/dist/download.d.ts +23 -0
  22. package/dist/download.js +65 -0
  23. package/dist/download.js.map +1 -0
  24. package/dist/draft.d.ts +34 -0
  25. package/dist/draft.js +119 -0
  26. package/dist/draft.js.map +1 -0
  27. package/dist/errors.d.ts +15 -0
  28. package/dist/errors.js +24 -0
  29. package/dist/errors.js.map +1 -0
  30. package/dist/imap.d.ts +161 -0
  31. package/dist/imap.js +300 -0
  32. package/dist/imap.js.map +1 -0
  33. package/dist/index.d.ts +2 -0
  34. package/dist/index.js +36 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/message.d.ts +51 -0
  37. package/dist/message.js +155 -0
  38. package/dist/message.js.map +1 -0
  39. package/dist/resources.d.ts +16 -0
  40. package/dist/resources.js +89 -0
  41. package/dist/resources.js.map +1 -0
  42. package/dist/result.d.ts +57 -0
  43. package/dist/result.js +193 -0
  44. package/dist/result.js.map +1 -0
  45. package/dist/schema.d.ts +42 -0
  46. package/dist/schema.js +99 -0
  47. package/dist/schema.js.map +1 -0
  48. package/dist/server.d.ts +8 -0
  49. package/dist/server.js +64 -0
  50. package/dist/server.js.map +1 -0
  51. package/dist/stream.d.ts +9 -0
  52. package/dist/stream.js +25 -0
  53. package/dist/stream.js.map +1 -0
  54. package/dist/tool-filter.d.ts +45 -0
  55. package/dist/tool-filter.js +171 -0
  56. package/dist/tool-filter.js.map +1 -0
  57. package/dist/tools/catalogue.d.ts +46 -0
  58. package/dist/tools/catalogue.js +67 -0
  59. package/dist/tools/catalogue.js.map +1 -0
  60. package/dist/tools/read.d.ts +4 -0
  61. package/dist/tools/read.js +576 -0
  62. package/dist/tools/read.js.map +1 -0
  63. package/dist/tools/write.d.ts +5 -0
  64. package/dist/tools/write.js +291 -0
  65. package/dist/tools/write.js.map +1 -0
  66. package/package.json +70 -0
@@ -0,0 +1,291 @@
1
+ import { z } from 'zod';
2
+ import { requestApproval } from '../approval.js';
3
+ import { audit } from '../audit.js';
4
+ import { confirmationPrompt, setResourceKey, } from '../confirm.js';
5
+ import { ToolInputError } from '../errors.js';
6
+ import { withTimeout } from '../imap.js';
7
+ import { buildDraft } from '../draft.js';
8
+ import { jsonResult, run, textResult } from '../result.js';
9
+ import { addressListParam, confirmTokenParam, flagListParam, mailboxParam, optionalMailboxParam, uidListParam, uidParam, } from '../schema.js';
10
+ export function registerWriteTools(server, client, config, confirmations) {
11
+ server.registerTool('set_message_flags', {
12
+ title: 'Add or remove message flags',
13
+ description: 'Adds or removes IMAP flags and keywords on one or more messages: ' +
14
+ '\\Seen to mark read or unread, \\Flagged to star, \\Answered, \\Draft, ' +
15
+ 'or any custom keyword the server accepts. Reversible, so no ' +
16
+ 'confirmation is required — which is why \\Deleted cannot be added ' +
17
+ 'here; use delete_messages, which asks first. Removing \\Deleted is ' +
18
+ 'allowed, since that undoes one. Removing the new-mail keyword makes ' +
19
+ 'those messages show up in list_new_messages again.',
20
+ inputSchema: {
21
+ uids: uidListParam,
22
+ mailbox: optionalMailboxParam,
23
+ add: flagListParam.optional().describe('Flags or keywords to set.'),
24
+ remove: flagListParam
25
+ .optional()
26
+ .describe('Flags or keywords to clear.'),
27
+ },
28
+ annotations: { readOnlyHint: false, destructiveHint: false },
29
+ }, async ({ uids, mailbox, add, remove }) => run(async () => {
30
+ if (add === undefined && remove === undefined) {
31
+ throw new ToolInputError('imap-mcp: give at least one of "add" or "remove".');
32
+ }
33
+ // \Deleted is not a flag like the others: it is half of a deletion.
34
+ // This tool has no confirmation and is annotated destructiveHint:false
35
+ // on the grounds that everything it does can be undone — true of \Seen
36
+ // and \Flagged, not of a flag that the next client to close the folder,
37
+ // or any server with autoexpunge, turns into a permanent removal. Left
38
+ // open it is delete_messages without the dialog, reachable in one call
39
+ // and present in the `essential` preset.
40
+ if (add?.some((flag) => flag.toLowerCase() === '\\deleted')) {
41
+ throw new ToolInputError('imap-mcp: \\Deleted cannot be added here — it marks messages for ' +
42
+ 'permanent removal, which the next client to close the mailbox ' +
43
+ 'may carry out. Use delete_messages, which asks for confirmation. ' +
44
+ 'Moving them to a Trash folder with move_messages is usually what ' +
45
+ 'is meant instead.');
46
+ }
47
+ return client.withMailbox(mailbox, false, async (connection) => {
48
+ if (add !== undefined) {
49
+ await withTimeout(connection.messageFlagsAdd(uids, add, { uid: true }), 'STORE');
50
+ }
51
+ if (remove !== undefined) {
52
+ await withTimeout(connection.messageFlagsRemove(uids, remove, { uid: true }), 'STORE');
53
+ }
54
+ const source = mailbox ?? client.defaultMailbox;
55
+ audit('set_flags', {
56
+ mailbox: source,
57
+ uids,
58
+ added: add,
59
+ removed: remove,
60
+ });
61
+ return jsonResult({
62
+ mailbox: source,
63
+ uids,
64
+ added: add ?? [],
65
+ removed: remove ?? [],
66
+ });
67
+ });
68
+ }));
69
+ server.registerTool('move_messages', {
70
+ title: 'Move or copy messages',
71
+ description: 'Moves messages to another mailbox, or copies them when mode is ' +
72
+ '"copy". Both require confirmation: call once to receive a token, ' +
73
+ 'then again with that token and the same UID list and destination.',
74
+ inputSchema: {
75
+ uids: uidListParam,
76
+ destination: mailboxParam.describe('Mailbox the messages end up in, exactly as listed by list_mailboxes.'),
77
+ mailbox: optionalMailboxParam,
78
+ mode: z
79
+ .enum(['move', 'copy'])
80
+ .optional()
81
+ .describe('"move" (default) removes the originals, "copy" keeps them.'),
82
+ confirm_token: confirmTokenParam,
83
+ },
84
+ annotations: { readOnlyHint: false, destructiveHint: false },
85
+ }, async ({ uids, destination, mailbox, mode, confirm_token }) => run(async () => {
86
+ const copying = mode === 'copy';
87
+ const source = mailbox ?? client.defaultMailbox;
88
+ // Copying is confirmed as well. The old rule — a token for "move",
89
+ // nothing for "copy" — reasoned about deletion, and deletion is not the
90
+ // only thing that cannot be taken back. `destination` is a free-form
91
+ // mailbox name, so on a shared account or a public namespace one
92
+ // unconfirmed call hands every named message to everyone with access to
93
+ // that folder. Disclosure is the irreversible part, and copying is the
94
+ // mode that does it while leaving no trace in the source folder.
95
+ //
96
+ // The key covers the exact UID set and both mailboxes: a confirmation
97
+ // for [1] must not execute [1, 2], where the model picked the second
98
+ // list, and one for Archive must not execute against Public/Shared.
99
+ const key = setResourceKey(`${copying ? 'copy_messages' : 'move_messages'}:${source}:${destination}`, uids.map(String));
100
+ if (!confirmations.consume(key, confirm_token)) {
101
+ return textResult(confirmationPrompt(`${copying ? 'copy' : 'move'} ${uids.length} message(s) between mailboxes`, confirmations.issue(key), confirmations.ttlMinutes, copying
102
+ ? 'Everyone with access to the destination can read the copies, and taking them back does not unsee them.'
103
+ : 'The messages keep their content but get new UIDs, so the current ones stop working.', [
104
+ { label: 'From', value: source },
105
+ { label: 'To', value: destination },
106
+ ]));
107
+ }
108
+ return client.withMailbox(mailbox, false, async (connection) => {
109
+ if (copying) {
110
+ await withTimeout(connection.messageCopy(uids, destination, { uid: true }), 'COPY');
111
+ }
112
+ else {
113
+ await withTimeout(connection.messageMove(uids, destination, { uid: true }), 'MOVE');
114
+ }
115
+ audit(copying ? 'copy' : 'move', {
116
+ from: source,
117
+ to: destination,
118
+ uids,
119
+ });
120
+ return jsonResult({
121
+ action: copying ? 'copied' : 'moved',
122
+ source,
123
+ destination,
124
+ uids,
125
+ });
126
+ });
127
+ }));
128
+ server.registerTool('delete_messages', {
129
+ title: 'Delete messages',
130
+ description: 'Permanently deletes messages: sets \\Deleted and expunges them. On ' +
131
+ 'most servers this does not go to Trash — move them there instead if ' +
132
+ 'that is what is meant. Asks the user to confirm; where the client ' +
133
+ 'cannot show a prompt, it falls back to a two-call token.',
134
+ inputSchema: {
135
+ uids: uidListParam,
136
+ mailbox: optionalMailboxParam,
137
+ confirm_token: confirmTokenParam,
138
+ },
139
+ annotations: { readOnlyHint: false, destructiveHint: true },
140
+ }, async ({ uids, mailbox, confirm_token }) => run(async () => {
141
+ const source = mailbox ?? client.defaultMailbox;
142
+ const approval = await requestApproval(server, confirmations, {
143
+ what: `Permanently delete ${uids.length} message(s) (UIDs ${uids.slice(0, 20).join(', ')}${uids.length > 20 ? ', …' : ''})`,
144
+ consequence: 'The messages are expunged, not moved to Trash. They cannot be recovered from here.',
145
+ resourceKey: setResourceKey(`delete_messages:${source}`, uids.map(String)),
146
+ token: confirm_token,
147
+ details: [{ label: 'Mailbox', value: source }],
148
+ });
149
+ if (!approval.approved)
150
+ return approval.result;
151
+ return client.withMailbox(mailbox, false, async (connection) => {
152
+ await withTimeout(connection.messageDelete(uids, { uid: true }), 'EXPUNGE');
153
+ audit('delete', { mailbox: source, uids });
154
+ return jsonResult({ action: 'deleted', mailbox: source, uids });
155
+ });
156
+ }));
157
+ server.registerTool('manage_mailbox', {
158
+ title: 'Create, rename or delete a mailbox',
159
+ description: 'Creates a folder, renames one, or deletes one. Deleting asks the user ' +
160
+ 'to confirm and takes every message in the folder with it; renaming ' +
161
+ 'uses the two-call token because it is reversible.',
162
+ inputSchema: {
163
+ action: z
164
+ .enum(['create', 'rename', 'delete'])
165
+ .describe('What to do with the mailbox.'),
166
+ mailbox: mailboxParam.describe('The mailbox to create, rename or delete.'),
167
+ new_name: mailboxParam
168
+ .optional()
169
+ .describe('Required for "rename": the full new path.'),
170
+ confirm_token: confirmTokenParam,
171
+ },
172
+ annotations: { readOnlyHint: false, destructiveHint: true },
173
+ }, async ({ action, mailbox, new_name, confirm_token }) => run(async () => {
174
+ if (action === 'rename' && new_name === undefined) {
175
+ throw new ToolInputError('imap-mcp: "rename" needs new_name — the full new mailbox path.');
176
+ }
177
+ if (action === 'delete') {
178
+ const approval = await requestApproval(server, confirmations, {
179
+ what: 'Delete a mailbox',
180
+ consequence: 'Every message in the folder is deleted with it, and it cannot be recovered from here.',
181
+ resourceKey: `manage_mailbox:delete:${mailbox}`,
182
+ token: confirm_token,
183
+ details: [{ label: 'Mailbox', value: mailbox }],
184
+ });
185
+ if (!approval.approved)
186
+ return approval.result;
187
+ }
188
+ else if (action === 'rename') {
189
+ const key = `manage_mailbox:rename:${mailbox}:${new_name ?? ''}`;
190
+ if (!confirmations.consume(key, confirm_token)) {
191
+ return textResult(confirmationPrompt('rename a mailbox', confirmations.issue(key), confirmations.ttlMinutes, 'Clients that cached the old path will have to resynchronise.', [
192
+ { label: 'Mailbox', value: mailbox },
193
+ { label: 'New name', value: new_name ?? '' },
194
+ ]));
195
+ }
196
+ }
197
+ return client.withConnection(async (connection) => {
198
+ if (action === 'create') {
199
+ await withTimeout(connection.mailboxCreate(mailbox), 'CREATE');
200
+ }
201
+ else if (action === 'rename') {
202
+ await withTimeout(connection.mailboxRename(mailbox, new_name), 'RENAME');
203
+ }
204
+ else {
205
+ await withTimeout(connection.mailboxDelete(mailbox), 'DELETE');
206
+ }
207
+ audit(`mailbox_${action}`, { mailbox, new_name });
208
+ return jsonResult({
209
+ action,
210
+ mailbox,
211
+ ...(new_name === undefined ? {} : { new_name }),
212
+ });
213
+ });
214
+ }));
215
+ server.registerTool('save_draft', {
216
+ title: 'Save a draft',
217
+ description: 'Composes a plain-text message and stores it in the Drafts folder. ' +
218
+ 'This server cannot send mail — the draft waits in the mailbox until a ' +
219
+ 'person opens it in their own mail client and sends it from there. ' +
220
+ 'That is deliberate: it keeps the composing useful while leaving the ' +
221
+ 'decision to send with a human.',
222
+ inputSchema: {
223
+ to: addressListParam,
224
+ cc: addressListParam.optional(),
225
+ bcc: addressListParam.optional(),
226
+ subject: z
227
+ .string()
228
+ .max(500)
229
+ .refine((v) => !/[\r\n]/.test(v), 'must not contain line breaks')
230
+ .describe('Subject line.'),
231
+ body: z
232
+ .string()
233
+ .min(1)
234
+ .max(100_000)
235
+ .describe('Plain-text body of the message.'),
236
+ reply_to_uid: uidParam
237
+ .optional()
238
+ .describe('UID of the message being answered; threads the draft through In-Reply-To and References.'),
239
+ mailbox: optionalMailboxParam.describe('Where to look for reply_to_uid. Defaults to the configured mailbox.'),
240
+ },
241
+ annotations: { readOnlyHint: false, destructiveHint: false },
242
+ }, async ({ to, cc, bcc, subject, body, reply_to_uid, mailbox }) => run(async () => {
243
+ const thread = reply_to_uid === undefined
244
+ ? undefined
245
+ : await client.threadHeaders(mailbox, reply_to_uid);
246
+ const draft = buildDraft({
247
+ from: client.user,
248
+ to,
249
+ ...(cc === undefined ? {} : { cc }),
250
+ ...(bcc === undefined ? {} : { bcc }),
251
+ subject,
252
+ body,
253
+ ...(thread === undefined ? {} : { thread }),
254
+ });
255
+ const folder = await resolveDraftsMailbox(client, config);
256
+ await client.withConnection(async (connection) => {
257
+ await withTimeout(connection.append(folder, draft, ['\\Draft', '\\Seen']), 'APPEND');
258
+ });
259
+ audit('save_draft', {
260
+ mailbox: folder,
261
+ recipients: to.length + (cc?.length ?? 0) + (bcc?.length ?? 0),
262
+ in_reply_to: thread?.messageId,
263
+ });
264
+ return jsonResult({
265
+ action: 'draft_saved',
266
+ mailbox: folder,
267
+ recipients: [...to, ...(cc ?? []), ...(bcc ?? [])],
268
+ note: 'The draft is stored but not sent. This server has no way to send mail; open it in your mail client to send it.',
269
+ });
270
+ }));
271
+ }
272
+ /**
273
+ * Finds the Drafts folder.
274
+ *
275
+ * The `\Drafts` special-use flag is the right answer where the server reports
276
+ * it, because folder names are localised — "Entwürfe", "Brouillons" — and
277
+ * guessing wrong creates a stray folder rather than failing loudly.
278
+ */
279
+ async function resolveDraftsMailbox(client, config) {
280
+ if (config.imap.draftsMailbox !== undefined) {
281
+ return config.imap.draftsMailbox;
282
+ }
283
+ const mailboxes = await client.listMailboxes();
284
+ const found = mailboxes.find((box) => box.specialUse === '\\Drafts');
285
+ if (found === undefined) {
286
+ throw new ToolInputError('imap-mcp: this account does not advertise a \\Drafts folder. Call ' +
287
+ 'list_mailboxes to find the right one and set IMAP_DRAFTS_MAILBOX to it.');
288
+ }
289
+ return found.path;
290
+ }
291
+ //# sourceMappingURL=write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@ni-c/imap-mcp",
3
+ "version": "0.2.0",
4
+ "mcpName": "io.github.ni-c/imap-mcp",
5
+ "description": "MCP server for IMAP mailboxes: read, search, organise and draft mail — it cannot send",
6
+ "keywords": [
7
+ "mcp",
8
+ "model-context-protocol",
9
+ "imap",
10
+ "email",
11
+ "mail",
12
+ "mailbox",
13
+ "read-only"
14
+ ],
15
+ "license": "MIT",
16
+ "author": "Willi Thiel",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/ni-c/imap-mcp.git"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/ni-c/imap-mcp/issues"
23
+ },
24
+ "homepage": "https://imap-mcp.ni-c.de",
25
+ "funding": "https://github.com/sponsors/ni-c",
26
+ "type": "module",
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "bin": {
31
+ "imap-mcp": "dist/index.js"
32
+ },
33
+ "main": "dist/index.js",
34
+ "files": [
35
+ "dist"
36
+ ],
37
+ "engines": {
38
+ "node": ">=22"
39
+ },
40
+ "scripts": {
41
+ "prepublishOnly": "npm run lint && npm run build && npm test",
42
+ "prebuild": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
43
+ "build": "tsc",
44
+ "watch": "tsc --watch",
45
+ "lint": "eslint . && prettier --check .",
46
+ "format": "prettier --write .",
47
+ "test": "vitest run",
48
+ "test:coverage": "vitest run --coverage",
49
+ "assets": "node scripts/gen-assets.mjs",
50
+ "assets:check": "node scripts/gen-assets.mjs --check"
51
+ },
52
+ "dependencies": {
53
+ "@modelcontextprotocol/sdk": "^1.30.0",
54
+ "imapflow": "^1.7.6",
55
+ "mailparser": "^3.9.17",
56
+ "zod": "^4.5.4"
57
+ },
58
+ "devDependencies": {
59
+ "@eslint/js": "^10.0.1",
60
+ "@resvg/resvg-js": "^2.6.2",
61
+ "@types/mailparser": "^3.4.6",
62
+ "@types/node": "^26.4.0",
63
+ "@vitest/coverage-v8": "4.1.11",
64
+ "eslint": "^10.9.1",
65
+ "prettier": "^3.9.6",
66
+ "typescript": "^6.0.3",
67
+ "typescript-eslint": "^8.68.0",
68
+ "vitest": "^4.1.11"
69
+ }
70
+ }