@diskd-ai/email-client-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +155 -0
- package/README.md +110 -0
- package/dist/config/loader.d.ts +12 -0
- package/dist/config/loader.js +42 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +512 -0
- package/dist/config/schema.js +66 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/domain/errors.d.ts +40 -0
- package/dist/domain/errors.js +46 -0
- package/dist/domain/errors.js.map +1 -0
- package/dist/domain/result.d.ts +30 -0
- package/dist/domain/result.js +12 -0
- package/dist/domain/result.js.map +1 -0
- package/dist/imap/fetch.d.ts +44 -0
- package/dist/imap/fetch.js +127 -0
- package/dist/imap/fetch.js.map +1 -0
- package/dist/imap/mapper.d.ts +70 -0
- package/dist/imap/mapper.js +140 -0
- package/dist/imap/mapper.js.map +1 -0
- package/dist/imap/pool.d.ts +26 -0
- package/dist/imap/pool.js +92 -0
- package/dist/imap/pool.js.map +1 -0
- package/dist/imap/virtualFolders.d.ts +11 -0
- package/dist/imap/virtualFolders.js +20 -0
- package/dist/imap/virtualFolders.js.map +1 -0
- package/dist/sdk/diskdClient.d.ts +21 -0
- package/dist/sdk/diskdClient.js +39 -0
- package/dist/sdk/diskdClient.js.map +1 -0
- package/dist/server.d.ts +17 -0
- package/dist/server.js +180 -0
- package/dist/server.js.map +1 -0
- package/dist/store/conventions.d.ts +31 -0
- package/dist/store/conventions.js +53 -0
- package/dist/store/conventions.js.map +1 -0
- package/dist/store/driveStore.d.ts +36 -0
- package/dist/store/driveStore.js +95 -0
- package/dist/store/driveStore.js.map +1 -0
- package/dist/store/payloadTypes.d.ts +62 -0
- package/dist/store/payloadTypes.js +11 -0
- package/dist/store/payloadTypes.js.map +1 -0
- package/dist/sync/backoff.d.ts +18 -0
- package/dist/sync/backoff.js +24 -0
- package/dist/sync/backoff.js.map +1 -0
- package/dist/sync/sync.d.ts +85 -0
- package/dist/sync/sync.js +383 -0
- package/dist/sync/sync.js.map +1 -0
- package/dist/sync/watcher.d.ts +43 -0
- package/dist/sync/watcher.js +141 -0
- package/dist/sync/watcher.js.map +1 -0
- package/dist/tools/bulkAction.d.ts +41 -0
- package/dist/tools/bulkAction.js +82 -0
- package/dist/tools/bulkAction.js.map +1 -0
- package/dist/tools/findMailboxFolder.d.ts +33 -0
- package/dist/tools/findMailboxFolder.js +45 -0
- package/dist/tools/findMailboxFolder.js.map +1 -0
- package/dist/tools/getEmail.d.ts +41 -0
- package/dist/tools/getEmail.js +74 -0
- package/dist/tools/getEmail.js.map +1 -0
- package/dist/tools/getEmails.d.ts +38 -0
- package/dist/tools/getEmails.js +72 -0
- package/dist/tools/getEmails.js.map +1 -0
- package/dist/tools/getWatcherStatus.d.ts +9 -0
- package/dist/tools/getWatcherStatus.js +8 -0
- package/dist/tools/getWatcherStatus.js.map +1 -0
- package/dist/tools/listAccounts.d.ts +19 -0
- package/dist/tools/listAccounts.js +18 -0
- package/dist/tools/listAccounts.js.map +1 -0
- package/dist/tools/listEmails.d.ts +70 -0
- package/dist/tools/listEmails.js +101 -0
- package/dist/tools/listEmails.js.map +1 -0
- package/dist/tools/listMailboxFolder.d.ts +33 -0
- package/dist/tools/listMailboxFolder.js +60 -0
- package/dist/tools/listMailboxFolder.js.map +1 -0
- package/dist/tools/moveEmail.d.ts +36 -0
- package/dist/tools/moveEmail.js +52 -0
- package/dist/tools/moveEmail.js.map +1 -0
- package/dist/tools/registry.d.ts +17 -0
- package/dist/tools/registry.js +64 -0
- package/dist/tools/registry.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: list_emails -- paginated metadata listing of a mailbox.
|
|
3
|
+
*
|
|
4
|
+
* Live-IMAP. Combines IMAP UID SEARCH (with optional filters) and
|
|
5
|
+
* envelope-only FETCH for matched UIDs. Pagination is offset-based:
|
|
6
|
+
* the first call returns the highest-UID page, subsequent calls pass
|
|
7
|
+
* the previous page's `nextCursor` (a UID).
|
|
8
|
+
*/
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
import { imapError, notFound } from "../domain/errors.js";
|
|
11
|
+
import { Err, Ok } from "../domain/result.js";
|
|
12
|
+
import { fetchEnvelopesUidRange, withMailboxLock } from "../imap/fetch.js";
|
|
13
|
+
export const listEmailsInput = z
|
|
14
|
+
.object({
|
|
15
|
+
account: z.string().min(1),
|
|
16
|
+
mailbox: z.string().min(1),
|
|
17
|
+
pageSize: z.number().int().min(1).max(200).default(50),
|
|
18
|
+
cursor: z.number().int().nonnegative().nullable().optional(),
|
|
19
|
+
unread: z.boolean().optional(),
|
|
20
|
+
flagged: z.boolean().optional(),
|
|
21
|
+
from: z.string().optional(),
|
|
22
|
+
to: z.string().optional(),
|
|
23
|
+
subject: z.string().optional(),
|
|
24
|
+
since: z.string().datetime().optional(),
|
|
25
|
+
})
|
|
26
|
+
.strict();
|
|
27
|
+
export const listEmails = async (pool, input) => {
|
|
28
|
+
if (!pool.accountIds.includes(input.account))
|
|
29
|
+
return Err(notFound(`account '${input.account}'`));
|
|
30
|
+
const clientR = await pool.forAccount(input.account);
|
|
31
|
+
if (clientR.tag === "Err")
|
|
32
|
+
return clientR;
|
|
33
|
+
const client = clientR.value;
|
|
34
|
+
try {
|
|
35
|
+
return await withMailboxLock(client, input.mailbox, async () => {
|
|
36
|
+
const query = {
|
|
37
|
+
...(input.unread === true ? { unseen: true } : {}),
|
|
38
|
+
...(input.unread === false ? { seen: true } : {}),
|
|
39
|
+
...(input.flagged === true ? { flagged: true } : {}),
|
|
40
|
+
...(input.from ? { from: input.from } : {}),
|
|
41
|
+
...(input.to ? { to: input.to } : {}),
|
|
42
|
+
...(input.subject ? { subject: input.subject } : {}),
|
|
43
|
+
...(input.since ? { since: new Date(input.since) } : {}),
|
|
44
|
+
};
|
|
45
|
+
const allUidsResult = await client.search(query, {
|
|
46
|
+
uid: true,
|
|
47
|
+
});
|
|
48
|
+
const allUids = Array.isArray(allUidsResult)
|
|
49
|
+
? allUidsResult.slice().sort((a, b) => b - a)
|
|
50
|
+
: [];
|
|
51
|
+
const cursor = input.cursor ?? null;
|
|
52
|
+
const startIdx = cursor === null ? 0 : allUids.findIndex((u) => u < cursor);
|
|
53
|
+
const safeStart = startIdx === -1 ? allUids.length : startIdx;
|
|
54
|
+
const pageUids = allUids.slice(safeStart, safeStart + input.pageSize);
|
|
55
|
+
const nextCursor = safeStart + input.pageSize < allUids.length
|
|
56
|
+
? (pageUids[pageUids.length - 1] ?? null)
|
|
57
|
+
: null;
|
|
58
|
+
if (pageUids.length === 0) {
|
|
59
|
+
return Ok({ account: input.account, mailbox: input.mailbox, items: [], nextCursor });
|
|
60
|
+
}
|
|
61
|
+
const minUid = Math.min(...pageUids);
|
|
62
|
+
const maxUid = Math.max(...pageUids);
|
|
63
|
+
const wanted = new Set(pageUids);
|
|
64
|
+
const items = [];
|
|
65
|
+
for await (const env of fetchEnvelopesUidRange(client, minUid, maxUid)) {
|
|
66
|
+
if (!wanted.has(env.uid))
|
|
67
|
+
continue;
|
|
68
|
+
const e = env.envelope ?? {};
|
|
69
|
+
items.push({
|
|
70
|
+
uid: env.uid,
|
|
71
|
+
messageId: e.messageId ?? null,
|
|
72
|
+
subject: e.subject ?? "",
|
|
73
|
+
from: e.from && e.from.length > 0 && e.from[0]
|
|
74
|
+
? {
|
|
75
|
+
name: e.from[0].name && e.from[0].name.length > 0 ? e.from[0].name : null,
|
|
76
|
+
address: e.from[0].address ?? "",
|
|
77
|
+
}
|
|
78
|
+
: null,
|
|
79
|
+
to: (e.to ?? []).map((a) => ({
|
|
80
|
+
name: a.name && a.name.length > 0 ? a.name : null,
|
|
81
|
+
address: a.address ?? "",
|
|
82
|
+
})),
|
|
83
|
+
date: e.date instanceof Date
|
|
84
|
+
? e.date.toISOString()
|
|
85
|
+
: typeof e.date === "string"
|
|
86
|
+
? new Date(e.date).toISOString()
|
|
87
|
+
: "",
|
|
88
|
+
flags: env.flags instanceof Set ? Array.from(env.flags) : [...(env.flags ?? [])],
|
|
89
|
+
hasAttachments: false,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
// Sort by UID descending to match the cursor walk.
|
|
93
|
+
items.sort((a, b) => b.uid - a.uid);
|
|
94
|
+
return Ok({ account: input.account, mailbox: input.mailbox, items, nextCursor });
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
catch (cause) {
|
|
98
|
+
return Err(imapError(input.account, "list_emails failed", cause));
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
//# sourceMappingURL=listEmails.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listEmails.js","sourceRoot":"","sources":["../../src/tools/listEmails.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: list_mailbox_folder -- IMAP folder list per account with
|
|
3
|
+
* unread counts and special-use flags. Live-IMAP read.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { type AppError } from "../domain/errors.js";
|
|
7
|
+
import { type Result } from "../domain/result.js";
|
|
8
|
+
import type { ImapPool } from "../imap/pool.js";
|
|
9
|
+
export declare const listMailboxFolderInput: z.ZodObject<{
|
|
10
|
+
account: z.ZodString;
|
|
11
|
+
includeUnreadCount: z.ZodDefault<z.ZodBoolean>;
|
|
12
|
+
}, "strict", z.ZodTypeAny, {
|
|
13
|
+
account: string;
|
|
14
|
+
includeUnreadCount: boolean;
|
|
15
|
+
}, {
|
|
16
|
+
account: string;
|
|
17
|
+
includeUnreadCount?: boolean | undefined;
|
|
18
|
+
}>;
|
|
19
|
+
export type ListMailboxFolderInput = z.infer<typeof listMailboxFolderInput>;
|
|
20
|
+
export type ListedFolder = {
|
|
21
|
+
readonly path: string;
|
|
22
|
+
readonly name: string;
|
|
23
|
+
readonly delimiter: string;
|
|
24
|
+
readonly specialUse: string | null;
|
|
25
|
+
readonly subscribed: boolean;
|
|
26
|
+
readonly virtual: boolean;
|
|
27
|
+
readonly unreadCount: number | null;
|
|
28
|
+
};
|
|
29
|
+
export type ListMailboxFolderResult = {
|
|
30
|
+
readonly account: string;
|
|
31
|
+
readonly folders: readonly ListedFolder[];
|
|
32
|
+
};
|
|
33
|
+
export declare const listMailboxFolder: (pool: ImapPool, input: ListMailboxFolderInput) => Promise<Result<AppError, ListMailboxFolderResult>>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: list_mailbox_folder -- IMAP folder list per account with
|
|
3
|
+
* unread counts and special-use flags. Live-IMAP read.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { errorMessage, imapError, notFound } from "../domain/errors.js";
|
|
7
|
+
import { Err, Ok } from "../domain/result.js";
|
|
8
|
+
import { withMailboxLock } from "../imap/fetch.js";
|
|
9
|
+
import { isVirtualFolderPath, isVirtualSpecialUse } from "../imap/virtualFolders.js";
|
|
10
|
+
export const listMailboxFolderInput = z
|
|
11
|
+
.object({
|
|
12
|
+
account: z.string().min(1),
|
|
13
|
+
includeUnreadCount: z.boolean().default(false),
|
|
14
|
+
})
|
|
15
|
+
.strict();
|
|
16
|
+
export const listMailboxFolder = async (pool, input) => {
|
|
17
|
+
if (!pool.accountIds.includes(input.account)) {
|
|
18
|
+
return Err(notFound(`account '${input.account}'`));
|
|
19
|
+
}
|
|
20
|
+
const clientR = await pool.forAccount(input.account);
|
|
21
|
+
if (clientR.tag === "Err")
|
|
22
|
+
return clientR;
|
|
23
|
+
const client = clientR.value;
|
|
24
|
+
try {
|
|
25
|
+
const folders = await client.list();
|
|
26
|
+
const out = [];
|
|
27
|
+
for (const f of folders) {
|
|
28
|
+
const specialUse = (f.specialUse ?? null);
|
|
29
|
+
const virtual = isVirtualFolderPath(f.path) || isVirtualSpecialUse(specialUse);
|
|
30
|
+
let unreadCount = null;
|
|
31
|
+
if (input.includeUnreadCount && !virtual) {
|
|
32
|
+
try {
|
|
33
|
+
const status = await client.status(f.path, { unseen: true });
|
|
34
|
+
unreadCount = Number(status.unseen ?? 0);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
unreadCount = null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
out.push({
|
|
41
|
+
path: f.path,
|
|
42
|
+
name: f.name,
|
|
43
|
+
delimiter: f.delimiter ?? "/",
|
|
44
|
+
specialUse,
|
|
45
|
+
subscribed: f.subscribed ?? false,
|
|
46
|
+
virtual,
|
|
47
|
+
unreadCount,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return Ok({ account: input.account, folders: out });
|
|
51
|
+
}
|
|
52
|
+
catch (cause) {
|
|
53
|
+
return Err(imapError(input.account, errorMessage({ kind: "ImapError", accountId: input.account, message: "list" }), cause));
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
// Note: client.list() does not require a per-mailbox lock.
|
|
57
|
+
void withMailboxLock; // silence unused import marker if list doesn't need lock
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=listMailboxFolder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listMailboxFolder.js","sourceRoot":"","sources":["../../src/tools/listMailboxFolder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: move_email -- IMAP MOVE one message between folders.
|
|
3
|
+
*
|
|
4
|
+
* Refuses virtual mailboxes as the source (Gmail "[Gmail]/All Mail",
|
|
5
|
+
* Starred, etc.) -- callers should use `find_mailbox_folder` first to
|
|
6
|
+
* resolve the real folder.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { type AppError } from "../domain/errors.js";
|
|
10
|
+
import { type Result } from "../domain/result.js";
|
|
11
|
+
import type { ImapPool } from "../imap/pool.js";
|
|
12
|
+
export declare const moveEmailInput: z.ZodObject<{
|
|
13
|
+
account: z.ZodString;
|
|
14
|
+
sourceMailbox: z.ZodString;
|
|
15
|
+
targetMailbox: z.ZodString;
|
|
16
|
+
uid: z.ZodNumber;
|
|
17
|
+
}, "strict", z.ZodTypeAny, {
|
|
18
|
+
uid: number;
|
|
19
|
+
account: string;
|
|
20
|
+
sourceMailbox: string;
|
|
21
|
+
targetMailbox: string;
|
|
22
|
+
}, {
|
|
23
|
+
uid: number;
|
|
24
|
+
account: string;
|
|
25
|
+
sourceMailbox: string;
|
|
26
|
+
targetMailbox: string;
|
|
27
|
+
}>;
|
|
28
|
+
export type MoveEmailInput = z.infer<typeof moveEmailInput>;
|
|
29
|
+
export type MoveEmailResult = {
|
|
30
|
+
readonly account: string;
|
|
31
|
+
readonly sourceMailbox: string;
|
|
32
|
+
readonly targetMailbox: string;
|
|
33
|
+
readonly uid: number;
|
|
34
|
+
readonly newUid: number | null;
|
|
35
|
+
};
|
|
36
|
+
export declare const moveEmail: (pool: ImapPool, input: MoveEmailInput) => Promise<Result<AppError, MoveEmailResult>>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: move_email -- IMAP MOVE one message between folders.
|
|
3
|
+
*
|
|
4
|
+
* Refuses virtual mailboxes as the source (Gmail "[Gmail]/All Mail",
|
|
5
|
+
* Starred, etc.) -- callers should use `find_mailbox_folder` first to
|
|
6
|
+
* resolve the real folder.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { imapError, notFound, virtualFolderRefused } from "../domain/errors.js";
|
|
10
|
+
import { Err, Ok } from "../domain/result.js";
|
|
11
|
+
import { withMailboxLock } from "../imap/fetch.js";
|
|
12
|
+
import { isVirtualFolderPath } from "../imap/virtualFolders.js";
|
|
13
|
+
export const moveEmailInput = z
|
|
14
|
+
.object({
|
|
15
|
+
account: z.string().min(1),
|
|
16
|
+
sourceMailbox: z.string().min(1),
|
|
17
|
+
targetMailbox: z.string().min(1),
|
|
18
|
+
uid: z.number().int().positive(),
|
|
19
|
+
})
|
|
20
|
+
.strict();
|
|
21
|
+
export const moveEmail = async (pool, input) => {
|
|
22
|
+
if (!pool.accountIds.includes(input.account))
|
|
23
|
+
return Err(notFound(`account '${input.account}'`));
|
|
24
|
+
if (isVirtualFolderPath(input.sourceMailbox)) {
|
|
25
|
+
return Err(virtualFolderRefused(input.sourceMailbox));
|
|
26
|
+
}
|
|
27
|
+
const clientR = await pool.forAccount(input.account);
|
|
28
|
+
if (clientR.tag === "Err")
|
|
29
|
+
return clientR;
|
|
30
|
+
const client = clientR.value;
|
|
31
|
+
try {
|
|
32
|
+
return await withMailboxLock(client, input.sourceMailbox, async () => {
|
|
33
|
+
const result = await client.messageMove([input.uid], input.targetMailbox, { uid: true });
|
|
34
|
+
if (result === false) {
|
|
35
|
+
return Err(imapError(input.account, "IMAP MOVE returned false (server refused)"));
|
|
36
|
+
}
|
|
37
|
+
const uidMap = result.uidMap;
|
|
38
|
+
const newUid = uidMap?.get(input.uid) ?? null;
|
|
39
|
+
return Ok({
|
|
40
|
+
account: input.account,
|
|
41
|
+
sourceMailbox: input.sourceMailbox,
|
|
42
|
+
targetMailbox: input.targetMailbox,
|
|
43
|
+
uid: input.uid,
|
|
44
|
+
newUid,
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
catch (cause) {
|
|
49
|
+
return Err(imapError(input.account, "move_email failed", cause));
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=moveEmail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moveEmail.js","sourceRoot":"","sources":["../../src/tools/moveEmail.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAiB,SAAS,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC/F,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAEhE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC;KAC5B,MAAM,CAAC;IACN,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAChC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAChC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC;KACD,MAAM,EAAE,CAAC;AAWZ,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,EAC5B,IAAc,EACd,KAAqB,EACuB,EAAE;IAC9C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;QAAE,OAAO,GAAG,CAAC,QAAQ,CAAC,YAAY,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IACjG,IAAI,mBAAmB,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC;QAC7C,OAAO,GAAG,CAAC,oBAAoB,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACrD,IAAI,OAAO,CAAC,GAAG,KAAK,KAAK;QAAE,OAAO,OAAO,CAAC;IAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAC7B,IAAI,CAAC;QACH,OAAO,MAAM,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,EAAE,KAAK,IAAI,EAAE;YACnE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,aAAa,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;YACzF,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBACrB,OAAO,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,2CAA2C,CAAC,CAAC,CAAC;YACpF,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAyC,CAAC;YAChE,MAAM,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;YAC9C,OAAO,EAAE,CAAC;gBACR,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,aAAa,EAAE,KAAK,CAAC,aAAa;gBAClC,aAAa,EAAE,KAAK,CAAC,aAAa;gBAClC,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,MAAM;aACP,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,mBAAmB,EAAE,KAAK,CAAC,CAAC,CAAC;IACnE,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bind tool implementations to the MCP server using the modern
|
|
3
|
+
* `registerTool(name, config, cb)` API. Each handler returns
|
|
4
|
+
* `{content:[{type:'text', text}]}` (success) or `{isError:true, ...}`
|
|
5
|
+
* (typed AppError). Stringified JSON keeps the transport simple for
|
|
6
|
+
* any client; agents parse it.
|
|
7
|
+
*/
|
|
8
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9
|
+
import type { Account } from "../config/schema.js";
|
|
10
|
+
import type { ImapPool } from "../imap/pool.js";
|
|
11
|
+
import type { Watcher } from "../sync/watcher.js";
|
|
12
|
+
export type ToolDeps = {
|
|
13
|
+
readonly accounts: readonly Account[];
|
|
14
|
+
readonly imapPool: ImapPool;
|
|
15
|
+
readonly watcher: Watcher;
|
|
16
|
+
};
|
|
17
|
+
export declare const registerTools: (server: McpServer, deps: ToolDeps) => void;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bind tool implementations to the MCP server using the modern
|
|
3
|
+
* `registerTool(name, config, cb)` API. Each handler returns
|
|
4
|
+
* `{content:[{type:'text', text}]}` (success) or `{isError:true, ...}`
|
|
5
|
+
* (typed AppError). Stringified JSON keeps the transport simple for
|
|
6
|
+
* any client; agents parse it.
|
|
7
|
+
*/
|
|
8
|
+
import { errorMessage } from "../domain/errors.js";
|
|
9
|
+
import { bulkAction, bulkActionInput } from "./bulkAction.js";
|
|
10
|
+
import { findMailboxFolder, findMailboxFolderInput } from "./findMailboxFolder.js";
|
|
11
|
+
import { getEmail, getEmailInput } from "./getEmail.js";
|
|
12
|
+
import { getEmails, getEmailsInput } from "./getEmails.js";
|
|
13
|
+
import { getWatcherStatus, getWatcherStatusInput } from "./getWatcherStatus.js";
|
|
14
|
+
import { listAccounts, listAccountsInput } from "./listAccounts.js";
|
|
15
|
+
import { listEmails, listEmailsInput } from "./listEmails.js";
|
|
16
|
+
import { listMailboxFolder, listMailboxFolderInput } from "./listMailboxFolder.js";
|
|
17
|
+
import { moveEmail, moveEmailInput } from "./moveEmail.js";
|
|
18
|
+
const ok = (value) => ({
|
|
19
|
+
content: [{ type: "text", text: JSON.stringify(value, null, 2) }],
|
|
20
|
+
});
|
|
21
|
+
const err = (e) => ({
|
|
22
|
+
content: [{ type: "text", text: errorMessage(e) }],
|
|
23
|
+
isError: true,
|
|
24
|
+
});
|
|
25
|
+
const fromResult = (r) => r.tag === "Ok" ? ok(r.value) : err(r.error);
|
|
26
|
+
export const registerTools = (server, deps) => {
|
|
27
|
+
server.registerTool("list_accounts", {
|
|
28
|
+
description: "List all configured email accounts. Call this first to discover available account names for use with other tools.",
|
|
29
|
+
inputSchema: listAccountsInput.shape,
|
|
30
|
+
}, async () => ok(listAccounts(deps.accounts)));
|
|
31
|
+
server.registerTool("list_mailbox_folder", {
|
|
32
|
+
description: "List all mailbox folders for an account with unread counts and special-use flags. Use list_accounts first to get the account name.",
|
|
33
|
+
inputSchema: listMailboxFolderInput.shape,
|
|
34
|
+
}, async (args) => fromResult(await listMailboxFolder(deps.imapPool, args)));
|
|
35
|
+
server.registerTool("find_mailbox_folder", {
|
|
36
|
+
description: "Find which real mailbox folder(s) an email belongs to. Required before move_email or delete_email when the email was found in a virtual folder (e.g., 'All Mail', 'Starred').",
|
|
37
|
+
inputSchema: findMailboxFolderInput.shape,
|
|
38
|
+
}, async (args) => fromResult(await findMailboxFolder(deps.imapPool, args)));
|
|
39
|
+
server.registerTool("list_emails", {
|
|
40
|
+
description: "List emails in a mailbox with optional filters. Returns paginated metadata (read/unread, flagged, attachments, labels). Use get_email for full body content.",
|
|
41
|
+
inputSchema: listEmailsInput.shape,
|
|
42
|
+
}, async (args) => fromResult(await listEmails(deps.imapPool, args)));
|
|
43
|
+
server.registerTool("get_email", {
|
|
44
|
+
description: "Get the full content of a specific email by UID. Does NOT mark it seen (BODY.PEEK). format=text strips HTML, format=stripped also drops quoted replies and signatures. Set markRead=true to flip \\Seen.",
|
|
45
|
+
inputSchema: getEmailInput.shape,
|
|
46
|
+
}, async (args) => fromResult(await getEmail(deps.imapPool, args)));
|
|
47
|
+
server.registerTool("get_emails", {
|
|
48
|
+
description: "Fetch multiple emails in one call (max 20). More efficient than repeated get_email when triaging. Defaults to format=text. Does NOT mark seen.",
|
|
49
|
+
inputSchema: getEmailsInput.shape,
|
|
50
|
+
}, async (args) => fromResult(await getEmails(deps.imapPool, args)));
|
|
51
|
+
server.registerTool("move_email", {
|
|
52
|
+
description: "Move an email to a different mailbox folder. sourceMailbox must be a real folder (not 'All Mail'). Use find_mailbox_folder if the email was discovered in a virtual folder.",
|
|
53
|
+
inputSchema: moveEmailInput.shape,
|
|
54
|
+
}, async (args) => fromResult(await moveEmail(deps.imapPool, args)));
|
|
55
|
+
server.registerTool("bulk_action", {
|
|
56
|
+
description: "Batch operation on multiple emails by UID list. Supports mark_read, mark_unread, flag, unflag, move, delete. Max 100 UIDs.",
|
|
57
|
+
inputSchema: bulkActionInput.shape,
|
|
58
|
+
}, async (args) => fromResult(await bulkAction(deps.imapPool, args)));
|
|
59
|
+
server.registerTool("get_watcher_status", {
|
|
60
|
+
description: "Status of the IMAP-to-Drive sync watcher: per-account/per-folder progress, last tick error, current sync state.",
|
|
61
|
+
inputSchema: getWatcherStatusInput.shape,
|
|
62
|
+
}, async () => ok(getWatcherStatus(deps.watcher)));
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@diskd-ai/email-client-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Drive-backed multi-account email MCP with reliable IMAP-to-mailboxes sync.",
|
|
5
|
+
"license": "LGPL-3.0-or-later",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"email-client-mcp": "./dist/server.js"
|
|
9
|
+
},
|
|
10
|
+
"main": "./dist/server.js",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=24.0.0"
|
|
16
|
+
},
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public",
|
|
19
|
+
"registry": "https://registry.npmjs.org/"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc -p tsconfig.json",
|
|
23
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
24
|
+
"lint": "biome check .",
|
|
25
|
+
"lint:fix": "biome check --write .",
|
|
26
|
+
"test": "vitest run",
|
|
27
|
+
"test:watch": "vitest",
|
|
28
|
+
"start": "node dist/server.js stdio",
|
|
29
|
+
"dev": "tsx src/server.ts stdio",
|
|
30
|
+
"prepublishOnly": "bun run build && bun run test"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@diskd/sdk": "5.1.2",
|
|
34
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
35
|
+
"imapflow": "^1.2.9",
|
|
36
|
+
"smol-toml": "^1.6.0",
|
|
37
|
+
"zod": "^3.23.8"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@biomejs/biome": "2.4.7",
|
|
41
|
+
"@types/node": "^22.10.0",
|
|
42
|
+
"tsx": "^4.19.2",
|
|
43
|
+
"typescript": "^5.6.3",
|
|
44
|
+
"vitest": "^2.1.5"
|
|
45
|
+
}
|
|
46
|
+
}
|