read-email-mcp 1.0.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 +21 -0
- package/README.md +203 -0
- package/dist/config.d.ts +30 -0
- package/dist/config.js +99 -0
- package/dist/config.js.map +1 -0
- package/dist/imap.d.ts +60 -0
- package/dist/imap.js +255 -0
- package/dist/imap.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/parser.d.ts +11 -0
- package/dist/parser.js +105 -0
- package/dist/parser.js.map +1 -0
- package/dist/server.d.ts +17 -0
- package/dist/server.js +39 -0
- package/dist/server.js.map +1 -0
- package/dist/store.d.ts +38 -0
- package/dist/store.js +597 -0
- package/dist/store.js.map +1 -0
- package/dist/tools.d.ts +246 -0
- package/dist/tools.js +204 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +108 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/docs/production-readiness.md +70 -0
- package/package.json +58 -0
- package/scripts/smoke-mcp.mjs +80 -0
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import type { EmailSyncService } from "./imap.js";
|
|
4
|
+
import type { EmailStore } from "./store.js";
|
|
5
|
+
export interface ToolResult extends CallToolResult {
|
|
6
|
+
content: Array<{
|
|
7
|
+
type: "text";
|
|
8
|
+
text: string;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
export interface EmailToolContext {
|
|
12
|
+
accountEmail: string;
|
|
13
|
+
storagePath: string;
|
|
14
|
+
store: EmailStore;
|
|
15
|
+
sync: Pick<EmailSyncService, "sync">;
|
|
16
|
+
}
|
|
17
|
+
export declare const toolSchemas: {
|
|
18
|
+
sync_email: z.ZodObject<{
|
|
19
|
+
mailbox: z.ZodOptional<z.ZodString>;
|
|
20
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
21
|
+
since: z.ZodOptional<z.ZodString>;
|
|
22
|
+
}, "strip", z.ZodTypeAny, {
|
|
23
|
+
mailbox?: string | undefined;
|
|
24
|
+
limit?: number | undefined;
|
|
25
|
+
since?: string | undefined;
|
|
26
|
+
}, {
|
|
27
|
+
mailbox?: string | undefined;
|
|
28
|
+
limit?: number | undefined;
|
|
29
|
+
since?: string | undefined;
|
|
30
|
+
}>;
|
|
31
|
+
get_sync_status: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
32
|
+
list_mailboxes: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
33
|
+
get_recent_emails: z.ZodObject<{
|
|
34
|
+
mailbox: z.ZodOptional<z.ZodString>;
|
|
35
|
+
unreadOnly: z.ZodOptional<z.ZodBoolean>;
|
|
36
|
+
flaggedOnly: z.ZodOptional<z.ZodBoolean>;
|
|
37
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
38
|
+
}, "strip", z.ZodTypeAny, {
|
|
39
|
+
mailbox?: string | undefined;
|
|
40
|
+
limit?: number | undefined;
|
|
41
|
+
unreadOnly?: boolean | undefined;
|
|
42
|
+
flaggedOnly?: boolean | undefined;
|
|
43
|
+
}, {
|
|
44
|
+
mailbox?: string | undefined;
|
|
45
|
+
limit?: number | undefined;
|
|
46
|
+
unreadOnly?: boolean | undefined;
|
|
47
|
+
flaggedOnly?: boolean | undefined;
|
|
48
|
+
}>;
|
|
49
|
+
browse_email_dates: z.ZodObject<{
|
|
50
|
+
granularity: z.ZodDefault<z.ZodEnum<["day", "week", "month"]>>;
|
|
51
|
+
mailbox: z.ZodOptional<z.ZodString>;
|
|
52
|
+
startDate: z.ZodOptional<z.ZodString>;
|
|
53
|
+
endDate: z.ZodOptional<z.ZodString>;
|
|
54
|
+
}, "strip", z.ZodTypeAny, {
|
|
55
|
+
granularity: "day" | "week" | "month";
|
|
56
|
+
mailbox?: string | undefined;
|
|
57
|
+
startDate?: string | undefined;
|
|
58
|
+
endDate?: string | undefined;
|
|
59
|
+
}, {
|
|
60
|
+
mailbox?: string | undefined;
|
|
61
|
+
startDate?: string | undefined;
|
|
62
|
+
endDate?: string | undefined;
|
|
63
|
+
granularity?: "day" | "week" | "month" | undefined;
|
|
64
|
+
}>;
|
|
65
|
+
search_emails: z.ZodObject<{
|
|
66
|
+
mailbox: z.ZodOptional<z.ZodString>;
|
|
67
|
+
from: z.ZodOptional<z.ZodString>;
|
|
68
|
+
to: z.ZodOptional<z.ZodString>;
|
|
69
|
+
cc: z.ZodOptional<z.ZodString>;
|
|
70
|
+
subject: z.ZodOptional<z.ZodString>;
|
|
71
|
+
startDate: z.ZodOptional<z.ZodString>;
|
|
72
|
+
endDate: z.ZodOptional<z.ZodString>;
|
|
73
|
+
hasAttachments: z.ZodOptional<z.ZodBoolean>;
|
|
74
|
+
isUnread: z.ZodOptional<z.ZodBoolean>;
|
|
75
|
+
isFlagged: z.ZodOptional<z.ZodBoolean>;
|
|
76
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
77
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
78
|
+
sort: z.ZodOptional<z.ZodEnum<["date_asc", "date_desc"]>>;
|
|
79
|
+
} & {
|
|
80
|
+
query: z.ZodOptional<z.ZodString>;
|
|
81
|
+
}, "strip", z.ZodTypeAny, {
|
|
82
|
+
mailbox?: string | undefined;
|
|
83
|
+
subject?: string | undefined;
|
|
84
|
+
from?: string | undefined;
|
|
85
|
+
to?: string | undefined;
|
|
86
|
+
cc?: string | undefined;
|
|
87
|
+
hasAttachments?: boolean | undefined;
|
|
88
|
+
sort?: "date_asc" | "date_desc" | undefined;
|
|
89
|
+
startDate?: string | undefined;
|
|
90
|
+
endDate?: string | undefined;
|
|
91
|
+
isUnread?: boolean | undefined;
|
|
92
|
+
isFlagged?: boolean | undefined;
|
|
93
|
+
limit?: number | undefined;
|
|
94
|
+
query?: string | undefined;
|
|
95
|
+
cursor?: string | undefined;
|
|
96
|
+
}, {
|
|
97
|
+
mailbox?: string | undefined;
|
|
98
|
+
subject?: string | undefined;
|
|
99
|
+
from?: string | undefined;
|
|
100
|
+
to?: string | undefined;
|
|
101
|
+
cc?: string | undefined;
|
|
102
|
+
hasAttachments?: boolean | undefined;
|
|
103
|
+
sort?: "date_asc" | "date_desc" | undefined;
|
|
104
|
+
startDate?: string | undefined;
|
|
105
|
+
endDate?: string | undefined;
|
|
106
|
+
isUnread?: boolean | undefined;
|
|
107
|
+
isFlagged?: boolean | undefined;
|
|
108
|
+
limit?: number | undefined;
|
|
109
|
+
query?: string | undefined;
|
|
110
|
+
cursor?: string | undefined;
|
|
111
|
+
}>;
|
|
112
|
+
list_emails: z.ZodObject<{
|
|
113
|
+
mailbox: z.ZodOptional<z.ZodString>;
|
|
114
|
+
from: z.ZodOptional<z.ZodString>;
|
|
115
|
+
to: z.ZodOptional<z.ZodString>;
|
|
116
|
+
cc: z.ZodOptional<z.ZodString>;
|
|
117
|
+
subject: z.ZodOptional<z.ZodString>;
|
|
118
|
+
startDate: z.ZodOptional<z.ZodString>;
|
|
119
|
+
endDate: z.ZodOptional<z.ZodString>;
|
|
120
|
+
hasAttachments: z.ZodOptional<z.ZodBoolean>;
|
|
121
|
+
isUnread: z.ZodOptional<z.ZodBoolean>;
|
|
122
|
+
isFlagged: z.ZodOptional<z.ZodBoolean>;
|
|
123
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
124
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
125
|
+
sort: z.ZodOptional<z.ZodEnum<["date_asc", "date_desc"]>>;
|
|
126
|
+
}, "strip", z.ZodTypeAny, {
|
|
127
|
+
mailbox?: string | undefined;
|
|
128
|
+
subject?: string | undefined;
|
|
129
|
+
from?: string | undefined;
|
|
130
|
+
to?: string | undefined;
|
|
131
|
+
cc?: string | undefined;
|
|
132
|
+
hasAttachments?: boolean | undefined;
|
|
133
|
+
sort?: "date_asc" | "date_desc" | undefined;
|
|
134
|
+
startDate?: string | undefined;
|
|
135
|
+
endDate?: string | undefined;
|
|
136
|
+
isUnread?: boolean | undefined;
|
|
137
|
+
isFlagged?: boolean | undefined;
|
|
138
|
+
limit?: number | undefined;
|
|
139
|
+
cursor?: string | undefined;
|
|
140
|
+
}, {
|
|
141
|
+
mailbox?: string | undefined;
|
|
142
|
+
subject?: string | undefined;
|
|
143
|
+
from?: string | undefined;
|
|
144
|
+
to?: string | undefined;
|
|
145
|
+
cc?: string | undefined;
|
|
146
|
+
hasAttachments?: boolean | undefined;
|
|
147
|
+
sort?: "date_asc" | "date_desc" | undefined;
|
|
148
|
+
startDate?: string | undefined;
|
|
149
|
+
endDate?: string | undefined;
|
|
150
|
+
isUnread?: boolean | undefined;
|
|
151
|
+
isFlagged?: boolean | undefined;
|
|
152
|
+
limit?: number | undefined;
|
|
153
|
+
cursor?: string | undefined;
|
|
154
|
+
}>;
|
|
155
|
+
get_email: z.ZodEffects<z.ZodObject<{
|
|
156
|
+
id: z.ZodOptional<z.ZodNumber>;
|
|
157
|
+
mailbox: z.ZodOptional<z.ZodString>;
|
|
158
|
+
uid: z.ZodOptional<z.ZodNumber>;
|
|
159
|
+
messageId: z.ZodOptional<z.ZodString>;
|
|
160
|
+
}, "strip", z.ZodTypeAny, {
|
|
161
|
+
mailbox?: string | undefined;
|
|
162
|
+
uid?: number | undefined;
|
|
163
|
+
messageId?: string | undefined;
|
|
164
|
+
id?: number | undefined;
|
|
165
|
+
}, {
|
|
166
|
+
mailbox?: string | undefined;
|
|
167
|
+
uid?: number | undefined;
|
|
168
|
+
messageId?: string | undefined;
|
|
169
|
+
id?: number | undefined;
|
|
170
|
+
}>, {
|
|
171
|
+
mailbox?: string | undefined;
|
|
172
|
+
uid?: number | undefined;
|
|
173
|
+
messageId?: string | undefined;
|
|
174
|
+
id?: number | undefined;
|
|
175
|
+
}, {
|
|
176
|
+
mailbox?: string | undefined;
|
|
177
|
+
uid?: number | undefined;
|
|
178
|
+
messageId?: string | undefined;
|
|
179
|
+
id?: number | undefined;
|
|
180
|
+
}>;
|
|
181
|
+
get_thread: z.ZodEffects<z.ZodObject<{
|
|
182
|
+
id: z.ZodOptional<z.ZodNumber>;
|
|
183
|
+
messageId: z.ZodOptional<z.ZodString>;
|
|
184
|
+
}, "strip", z.ZodTypeAny, {
|
|
185
|
+
messageId?: string | undefined;
|
|
186
|
+
id?: number | undefined;
|
|
187
|
+
}, {
|
|
188
|
+
messageId?: string | undefined;
|
|
189
|
+
id?: number | undefined;
|
|
190
|
+
}>, {
|
|
191
|
+
messageId?: string | undefined;
|
|
192
|
+
id?: number | undefined;
|
|
193
|
+
}, {
|
|
194
|
+
messageId?: string | undefined;
|
|
195
|
+
id?: number | undefined;
|
|
196
|
+
}>;
|
|
197
|
+
get_raw_email: z.ZodEffects<z.ZodObject<{
|
|
198
|
+
id: z.ZodOptional<z.ZodNumber>;
|
|
199
|
+
mailbox: z.ZodOptional<z.ZodString>;
|
|
200
|
+
uid: z.ZodOptional<z.ZodNumber>;
|
|
201
|
+
messageId: z.ZodOptional<z.ZodString>;
|
|
202
|
+
} & {
|
|
203
|
+
maxBytes: z.ZodDefault<z.ZodNumber>;
|
|
204
|
+
}, "strip", z.ZodTypeAny, {
|
|
205
|
+
maxBytes: number;
|
|
206
|
+
mailbox?: string | undefined;
|
|
207
|
+
uid?: number | undefined;
|
|
208
|
+
messageId?: string | undefined;
|
|
209
|
+
id?: number | undefined;
|
|
210
|
+
}, {
|
|
211
|
+
mailbox?: string | undefined;
|
|
212
|
+
uid?: number | undefined;
|
|
213
|
+
messageId?: string | undefined;
|
|
214
|
+
id?: number | undefined;
|
|
215
|
+
maxBytes?: number | undefined;
|
|
216
|
+
}>, {
|
|
217
|
+
maxBytes: number;
|
|
218
|
+
mailbox?: string | undefined;
|
|
219
|
+
uid?: number | undefined;
|
|
220
|
+
messageId?: string | undefined;
|
|
221
|
+
id?: number | undefined;
|
|
222
|
+
}, {
|
|
223
|
+
mailbox?: string | undefined;
|
|
224
|
+
uid?: number | undefined;
|
|
225
|
+
messageId?: string | undefined;
|
|
226
|
+
id?: number | undefined;
|
|
227
|
+
maxBytes?: number | undefined;
|
|
228
|
+
}>;
|
|
229
|
+
get_storage_stats: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
230
|
+
optimize_email_store: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
231
|
+
};
|
|
232
|
+
export declare const toolDescriptions: Record<keyof typeof toolSchemas, string>;
|
|
233
|
+
export declare function createToolHandlers(context: EmailToolContext): {
|
|
234
|
+
sync_email: (input: unknown) => Promise<ToolResult>;
|
|
235
|
+
get_sync_status: (input: unknown) => Promise<ToolResult>;
|
|
236
|
+
list_mailboxes: (input: unknown) => Promise<ToolResult>;
|
|
237
|
+
get_recent_emails: (input: unknown) => Promise<ToolResult>;
|
|
238
|
+
browse_email_dates: (input: unknown) => Promise<ToolResult>;
|
|
239
|
+
search_emails: (input: unknown) => Promise<ToolResult>;
|
|
240
|
+
list_emails: (input: unknown) => Promise<ToolResult>;
|
|
241
|
+
get_email: (input: unknown) => Promise<ToolResult>;
|
|
242
|
+
get_thread: (input: unknown) => Promise<ToolResult>;
|
|
243
|
+
get_raw_email: (input: unknown) => Promise<ToolResult>;
|
|
244
|
+
get_storage_stats: (input: unknown) => Promise<ToolResult>;
|
|
245
|
+
optimize_email_store: (input: unknown) => Promise<ToolResult>;
|
|
246
|
+
};
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
export const toolSchemas = {
|
|
4
|
+
sync_email: z.object({
|
|
5
|
+
mailbox: z.string().min(1).optional(),
|
|
6
|
+
limit: z.number().int().positive().max(1000).optional(),
|
|
7
|
+
since: z.string().datetime().optional()
|
|
8
|
+
}),
|
|
9
|
+
get_sync_status: z.object({}),
|
|
10
|
+
list_mailboxes: z.object({}),
|
|
11
|
+
get_recent_emails: z.object({
|
|
12
|
+
mailbox: z.string().min(1).optional(),
|
|
13
|
+
unreadOnly: z.boolean().optional(),
|
|
14
|
+
flaggedOnly: z.boolean().optional(),
|
|
15
|
+
limit: z.number().int().positive().max(100).optional()
|
|
16
|
+
}),
|
|
17
|
+
browse_email_dates: z.object({
|
|
18
|
+
granularity: z.enum(["day", "week", "month"]).default("day"),
|
|
19
|
+
mailbox: z.string().min(1).optional(),
|
|
20
|
+
startDate: z.string().datetime().optional(),
|
|
21
|
+
endDate: z.string().datetime().optional()
|
|
22
|
+
}),
|
|
23
|
+
search_emails: messageFilterSchema().extend({
|
|
24
|
+
query: z.string().min(1).optional()
|
|
25
|
+
}),
|
|
26
|
+
list_emails: messageFilterSchema(),
|
|
27
|
+
get_email: z
|
|
28
|
+
.object({
|
|
29
|
+
id: z.number().int().positive().optional(),
|
|
30
|
+
mailbox: z.string().min(1).optional(),
|
|
31
|
+
uid: z.number().int().positive().optional(),
|
|
32
|
+
messageId: z.string().min(1).optional()
|
|
33
|
+
})
|
|
34
|
+
.refine((value) => value.id || value.messageId || (value.mailbox && value.uid), {
|
|
35
|
+
message: "Provide id, messageId, or mailbox plus uid"
|
|
36
|
+
}),
|
|
37
|
+
get_thread: z
|
|
38
|
+
.object({
|
|
39
|
+
id: z.number().int().positive().optional(),
|
|
40
|
+
messageId: z.string().min(1).optional()
|
|
41
|
+
})
|
|
42
|
+
.refine((value) => value.id || value.messageId, {
|
|
43
|
+
message: "Provide id or messageId"
|
|
44
|
+
}),
|
|
45
|
+
get_raw_email: emailLocatorBaseSchema()
|
|
46
|
+
.extend({
|
|
47
|
+
maxBytes: z.number().int().positive().max(1_000_000).default(65_536)
|
|
48
|
+
})
|
|
49
|
+
.refine((value) => value.id || value.messageId || (value.mailbox && value.uid), {
|
|
50
|
+
message: "Provide id, messageId, or mailbox plus uid"
|
|
51
|
+
}),
|
|
52
|
+
get_storage_stats: z.object({}),
|
|
53
|
+
optimize_email_store: z.object({})
|
|
54
|
+
};
|
|
55
|
+
export const toolDescriptions = {
|
|
56
|
+
sync_email: "Pull new messages from the IMAP server into the local mirror. Call this first (or after a gap) before browsing/searching, since every other tool reads the local copy. Tip: start with a small limit on one mailbox (e.g. { mailbox: 'INBOX', limit: 10 }) to verify credentials, then sync more. Without a mailbox, syncs all selectable mailboxes. Uses read-only IMAP access and never mutates the server mailbox.",
|
|
57
|
+
get_sync_status: "Check how fresh the local mirror is: total messages, latest message date, per-mailbox counts, and the last sync result. Good first call to see whether a sync is needed and whether the previous sync succeeded.",
|
|
58
|
+
list_mailboxes: "List the mailboxes known locally (e.g. INBOX, Sent, Drafts) with message counts and last-sync time. Use this to discover mailbox names to pass to sync_email, get_recent_emails, or list_emails.",
|
|
59
|
+
get_recent_emails: "Show the latest emails, newest first. This is the everyday 'what's new in my inbox' tool. Set unreadOnly: true to see only unread messages, or flaggedOnly: true for starred messages. Returns summaries (subject, from, date, preview, attachments, read/flagged state); pass the returned id to get_email for the full body, or get_thread to see the whole conversation.",
|
|
60
|
+
browse_email_dates: "Summarize message volume over time as counts per day, week, or month. Useful for 'how much email did I get this month' or finding a busy period before drilling in with list_emails/search_emails over that date range.",
|
|
61
|
+
search_emails: "Full-text search across subject, sender/recipient addresses, preview, and body text, with the same filters as list_emails (mailbox, from, to, cc, subject, date range, attachments, unread, flagged). Use this when looking for specific content or a topic. Returns paginated summaries; use get_email on a hit for the full message.",
|
|
62
|
+
list_emails: "List email summaries in chronological order with filters (mailbox, from, to, cc, subject, date range, attachments, unread, flagged) and keyset pagination, but without full-text search. Prefer this over search_emails when browsing by sender, date, or mailbox rather than searching body text. Defaults to newest first with a page size of 25.",
|
|
63
|
+
get_email: "Return the full metadata and body (text and HTML) for a single message. Resolve it by the id returned from get_recent_emails/list_emails/search_emails, by Message-ID, or by mailbox plus UID. Use this after finding a summary you want to read in full.",
|
|
64
|
+
get_thread: "Return all locally known messages in one conversation, matched via Message-ID, In-Reply-To, and References headers. Give the id or messageId of any message in the thread. Use this to follow a discussion after get_email or when a search hit looks like part of a longer thread.",
|
|
65
|
+
get_raw_email: "Return the raw RFC822/MIME source for one message, byte-limited (default 64 KiB). Use this only when you need original headers or MIME structure not exposed by get_email, for example to inspect a specific header or attachment encoding.",
|
|
66
|
+
get_storage_stats: "Report SQLite database, WAL, and shared-memory file sizes plus page counts for the local mirror. Use this to understand disk usage after large syncs.",
|
|
67
|
+
optimize_email_store: "Run lightweight SQLite and FTS maintenance (ANALYZE/optimize) to keep queries fast. Safe to call occasionally after large syncs or before packaging a local archive."
|
|
68
|
+
};
|
|
69
|
+
export function createToolHandlers(context) {
|
|
70
|
+
return {
|
|
71
|
+
sync_email: async (input) => {
|
|
72
|
+
const args = toolSchemas.sync_email.parse(input);
|
|
73
|
+
const result = await context.sync.sync(args);
|
|
74
|
+
return json(result);
|
|
75
|
+
},
|
|
76
|
+
get_sync_status: async (input) => {
|
|
77
|
+
toolSchemas.get_sync_status.parse(input);
|
|
78
|
+
return json({
|
|
79
|
+
account: context.accountEmail,
|
|
80
|
+
storagePath: context.storagePath,
|
|
81
|
+
...context.store.getSyncStatus()
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
list_mailboxes: async (input) => {
|
|
85
|
+
toolSchemas.list_mailboxes.parse(input);
|
|
86
|
+
return json({ mailboxes: context.store.listMailboxes() });
|
|
87
|
+
},
|
|
88
|
+
get_recent_emails: async (input) => {
|
|
89
|
+
const args = toolSchemas.get_recent_emails.parse(input);
|
|
90
|
+
return json(context.store.listMessages({
|
|
91
|
+
mailbox: args.mailbox,
|
|
92
|
+
isUnread: args.unreadOnly,
|
|
93
|
+
isFlagged: args.flaggedOnly,
|
|
94
|
+
limit: args.limit,
|
|
95
|
+
sort: "date_desc"
|
|
96
|
+
}));
|
|
97
|
+
},
|
|
98
|
+
browse_email_dates: async (input) => {
|
|
99
|
+
const args = toolSchemas.browse_email_dates.parse(input);
|
|
100
|
+
return json({ buckets: context.store.getDateBuckets(args) });
|
|
101
|
+
},
|
|
102
|
+
search_emails: async (input) => {
|
|
103
|
+
const args = toolSchemas.search_emails.parse(input);
|
|
104
|
+
return json(context.store.searchMessages(args));
|
|
105
|
+
},
|
|
106
|
+
list_emails: async (input) => {
|
|
107
|
+
const args = toolSchemas.list_emails.parse(input);
|
|
108
|
+
return json(context.store.listMessages(args));
|
|
109
|
+
},
|
|
110
|
+
get_email: async (input) => {
|
|
111
|
+
const args = toolSchemas.get_email.parse(input);
|
|
112
|
+
const message = findMessage(context.store, args);
|
|
113
|
+
if (!message) {
|
|
114
|
+
throw new Error("Email message not found");
|
|
115
|
+
}
|
|
116
|
+
return json({ message });
|
|
117
|
+
},
|
|
118
|
+
get_thread: async (input) => {
|
|
119
|
+
const args = toolSchemas.get_thread.parse(input);
|
|
120
|
+
return json({ items: context.store.getThread(args.id ?? args.messageId) });
|
|
121
|
+
},
|
|
122
|
+
get_raw_email: async (input) => {
|
|
123
|
+
const args = toolSchemas.get_raw_email.parse(input);
|
|
124
|
+
const message = findMessage(context.store, args);
|
|
125
|
+
if (!message) {
|
|
126
|
+
throw new Error("Email message not found");
|
|
127
|
+
}
|
|
128
|
+
const stats = await fs.stat(message.rawPath);
|
|
129
|
+
const handle = await fs.open(message.rawPath, "r");
|
|
130
|
+
try {
|
|
131
|
+
const bytesToRead = Math.min(args.maxBytes, stats.size);
|
|
132
|
+
const buffer = Buffer.alloc(bytesToRead);
|
|
133
|
+
const { bytesRead } = await handle.read(buffer, 0, bytesToRead, 0);
|
|
134
|
+
return json({
|
|
135
|
+
id: message.id,
|
|
136
|
+
rawPath: message.rawPath,
|
|
137
|
+
sizeBytes: stats.size,
|
|
138
|
+
returnedBytes: bytesRead,
|
|
139
|
+
truncated: bytesRead < stats.size,
|
|
140
|
+
content: buffer.subarray(0, bytesRead).toString("utf8")
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
await handle.close();
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
get_storage_stats: async (input) => {
|
|
148
|
+
toolSchemas.get_storage_stats.parse(input);
|
|
149
|
+
return json(context.store.getStorageStats());
|
|
150
|
+
},
|
|
151
|
+
optimize_email_store: async (input) => {
|
|
152
|
+
toolSchemas.optimize_email_store.parse(input);
|
|
153
|
+
return json(context.store.optimize());
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
function emailLocatorSchema() {
|
|
158
|
+
return emailLocatorBaseSchema().refine((value) => value.id || value.messageId || (value.mailbox && value.uid), {
|
|
159
|
+
message: "Provide id, messageId, or mailbox plus uid"
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
function emailLocatorBaseSchema() {
|
|
163
|
+
return z.object({
|
|
164
|
+
id: z.number().int().positive().optional(),
|
|
165
|
+
mailbox: z.string().min(1).optional(),
|
|
166
|
+
uid: z.number().int().positive().optional(),
|
|
167
|
+
messageId: z.string().min(1).optional()
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
function messageFilterSchema() {
|
|
171
|
+
return z.object({
|
|
172
|
+
mailbox: z.string().min(1).optional(),
|
|
173
|
+
from: z.string().min(1).optional(),
|
|
174
|
+
to: z.string().min(1).optional(),
|
|
175
|
+
cc: z.string().min(1).optional(),
|
|
176
|
+
subject: z.string().min(1).optional(),
|
|
177
|
+
startDate: z.string().datetime().optional(),
|
|
178
|
+
endDate: z.string().datetime().optional(),
|
|
179
|
+
hasAttachments: z.boolean().optional(),
|
|
180
|
+
isUnread: z.boolean().optional(),
|
|
181
|
+
isFlagged: z.boolean().optional(),
|
|
182
|
+
limit: z.number().int().positive().max(100).optional(),
|
|
183
|
+
cursor: z.string().min(1).optional(),
|
|
184
|
+
sort: z.enum(["date_asc", "date_desc"]).optional()
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
function findMessage(store, locator) {
|
|
188
|
+
return locator.id
|
|
189
|
+
? store.getMessageById(locator.id)
|
|
190
|
+
: locator.messageId
|
|
191
|
+
? store.getMessageByMessageId(locator.messageId)
|
|
192
|
+
: store.getMessageByMailboxUid(locator.mailbox, locator.uid);
|
|
193
|
+
}
|
|
194
|
+
function json(value) {
|
|
195
|
+
return {
|
|
196
|
+
content: [
|
|
197
|
+
{
|
|
198
|
+
type: "text",
|
|
199
|
+
text: JSON.stringify(value, null, 2)
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
export interface EmailAddress {
|
|
2
|
+
name?: string;
|
|
3
|
+
address: string;
|
|
4
|
+
}
|
|
5
|
+
export interface AttachmentSummary {
|
|
6
|
+
filename?: string;
|
|
7
|
+
contentType?: string;
|
|
8
|
+
size?: number;
|
|
9
|
+
contentId?: string;
|
|
10
|
+
disposition?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface MailboxRecord {
|
|
13
|
+
path: string;
|
|
14
|
+
delimiter: string;
|
|
15
|
+
uidValidity: string | null;
|
|
16
|
+
highestUid: number;
|
|
17
|
+
selectable: boolean;
|
|
18
|
+
lastSyncedAt?: string | null;
|
|
19
|
+
messageCount?: number;
|
|
20
|
+
}
|
|
21
|
+
export interface MessageInput {
|
|
22
|
+
mailbox: string;
|
|
23
|
+
uid: number;
|
|
24
|
+
uidValidity: string;
|
|
25
|
+
messageId: string | null;
|
|
26
|
+
inReplyTo: string | null;
|
|
27
|
+
references: string[];
|
|
28
|
+
subject: string | null;
|
|
29
|
+
date: string;
|
|
30
|
+
internalDate: string | null;
|
|
31
|
+
from: EmailAddress[];
|
|
32
|
+
to: EmailAddress[];
|
|
33
|
+
cc: EmailAddress[];
|
|
34
|
+
bcc: EmailAddress[];
|
|
35
|
+
flags: string[];
|
|
36
|
+
size: number | null;
|
|
37
|
+
hasAttachments: boolean;
|
|
38
|
+
attachmentCount: number;
|
|
39
|
+
preview: string | null;
|
|
40
|
+
text: string | null;
|
|
41
|
+
html: string | null;
|
|
42
|
+
headers: Record<string, string | string[]>;
|
|
43
|
+
attachments: AttachmentSummary[];
|
|
44
|
+
rawPath: string;
|
|
45
|
+
parseError: string | null;
|
|
46
|
+
}
|
|
47
|
+
export interface StoredMessage extends MessageInput {
|
|
48
|
+
id: number;
|
|
49
|
+
}
|
|
50
|
+
export interface MessageSummary {
|
|
51
|
+
id: number;
|
|
52
|
+
mailbox: string;
|
|
53
|
+
uid: number;
|
|
54
|
+
messageId: string | null;
|
|
55
|
+
date: string;
|
|
56
|
+
from: EmailAddress[];
|
|
57
|
+
to: EmailAddress[];
|
|
58
|
+
cc: EmailAddress[];
|
|
59
|
+
subject: string | null;
|
|
60
|
+
preview: string | null;
|
|
61
|
+
flags: string[];
|
|
62
|
+
hasAttachments: boolean;
|
|
63
|
+
attachmentCount: number;
|
|
64
|
+
}
|
|
65
|
+
export interface MessageFilters {
|
|
66
|
+
query?: string;
|
|
67
|
+
mailbox?: string;
|
|
68
|
+
from?: string;
|
|
69
|
+
to?: string;
|
|
70
|
+
cc?: string;
|
|
71
|
+
subject?: string;
|
|
72
|
+
startDate?: string;
|
|
73
|
+
endDate?: string;
|
|
74
|
+
hasAttachments?: boolean;
|
|
75
|
+
isUnread?: boolean;
|
|
76
|
+
isFlagged?: boolean;
|
|
77
|
+
limit?: number;
|
|
78
|
+
cursor?: string;
|
|
79
|
+
sort?: "date_asc" | "date_desc";
|
|
80
|
+
}
|
|
81
|
+
export interface PaginatedMessages {
|
|
82
|
+
items: MessageSummary[];
|
|
83
|
+
nextCursor?: string;
|
|
84
|
+
}
|
|
85
|
+
export interface DateBucketOptions {
|
|
86
|
+
granularity: "day" | "week" | "month";
|
|
87
|
+
mailbox?: string;
|
|
88
|
+
startDate?: string;
|
|
89
|
+
endDate?: string;
|
|
90
|
+
}
|
|
91
|
+
export interface DateBucket {
|
|
92
|
+
bucket: string;
|
|
93
|
+
count: number;
|
|
94
|
+
}
|
|
95
|
+
export interface SyncResultRecord {
|
|
96
|
+
ok: boolean;
|
|
97
|
+
mailbox: string | null;
|
|
98
|
+
startedAt: string;
|
|
99
|
+
finishedAt: string;
|
|
100
|
+
message: string;
|
|
101
|
+
syncedMessages: number;
|
|
102
|
+
}
|
|
103
|
+
export interface SyncStatus {
|
|
104
|
+
totalMessages: number;
|
|
105
|
+
latestMessageDate: string | null;
|
|
106
|
+
mailboxes: MailboxRecord[];
|
|
107
|
+
lastSync: SyncResultRecord | null;
|
|
108
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Production Readiness
|
|
2
|
+
|
|
3
|
+
Use this page as the handoff checklist for running the Read Email MCP server with a real mailbox.
|
|
4
|
+
|
|
5
|
+
## Current Status
|
|
6
|
+
|
|
7
|
+
- The server uses the official MCP TypeScript SDK over stdio.
|
|
8
|
+
- IMAP settings are provider-configurable via `IMAP_HOST` (required), `IMAP_PORT` (default 993), `IMAP_SECURE` (default true), and `IMAP_USER` (defaults to the email address), or the matching `--imap-*` CLI args.
|
|
9
|
+
- Setup requires `EMAIL`, `PASSWORD`, and `IMAP_HOST`.
|
|
10
|
+
- Browse and search tools read from a local SQLite mirror, not directly from IMAP.
|
|
11
|
+
- Sync is read-only and uses read-only mailbox locks.
|
|
12
|
+
- SQLite runs with WAL mode, a busy timeout, keyset pagination, and lightweight optimization.
|
|
13
|
+
- Raw RFC822 messages are stored locally for reparse and inspection.
|
|
14
|
+
|
|
15
|
+
## Local Verification
|
|
16
|
+
|
|
17
|
+
Run:
|
|
18
|
+
|
|
19
|
+
```powershell
|
|
20
|
+
npm run verify
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
That command runs:
|
|
24
|
+
|
|
25
|
+
- `npm test`
|
|
26
|
+
- `npm run typecheck`
|
|
27
|
+
- `npm run build`
|
|
28
|
+
- `npm run smoke:mcp`
|
|
29
|
+
|
|
30
|
+
The smoke check starts the built MCP server over stdio with dummy credentials and verifies the registered tools. It proves the server starts and speaks MCP, but it does not prove live authentication.
|
|
31
|
+
|
|
32
|
+
## Live Mailbox Check
|
|
33
|
+
|
|
34
|
+
After adding real credentials to the MCP host, run a small sync first:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"mailbox": "INBOX",
|
|
39
|
+
"limit": 10
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Then inspect:
|
|
44
|
+
|
|
45
|
+
- `get_sync_status`
|
|
46
|
+
- `list_mailboxes`
|
|
47
|
+
- `get_recent_emails`
|
|
48
|
+
- `browse_email_dates`
|
|
49
|
+
- `search_emails`
|
|
50
|
+
- `get_email`
|
|
51
|
+
|
|
52
|
+
Once those look correct, run a larger sync or sync all mailboxes.
|
|
53
|
+
|
|
54
|
+
## Operational Notes
|
|
55
|
+
|
|
56
|
+
- The local mirror is stored under `~/.read-email-mcp/<account-hash>/`.
|
|
57
|
+
- Passwords are read from the process environment and are not stored by this server.
|
|
58
|
+
- Raw `.eml` files contain full email content. Keep the storage directory private and backed up according to your own retention rules.
|
|
59
|
+
- The server does not schedule background syncs. Sync runs when the MCP client calls `sync_email`.
|
|
60
|
+
- Use `get_storage_stats` to inspect database size and WAL state.
|
|
61
|
+
- Use `optimize_email_store` after large syncs or before packaging a local archive.
|
|
62
|
+
|
|
63
|
+
## Not Included
|
|
64
|
+
|
|
65
|
+
- Sending email
|
|
66
|
+
- Deleting, moving, archiving, flagging, or marking messages read
|
|
67
|
+
- OAuth
|
|
68
|
+
- Background daemon scheduling
|
|
69
|
+
- Attachment byte extraction
|
|
70
|
+
- Web UI
|