fluxmail 0.0.1 → 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.
- package/README.md +37 -10
- package/dist/accounts/googleAuth.d.ts +31 -0
- package/dist/accounts/googleAuth.d.ts.map +1 -0
- package/dist/accounts/googleAuth.js +147 -0
- package/dist/accounts/googleAuth.js.map +1 -0
- package/dist/accounts/registry.d.ts +37 -0
- package/dist/accounts/registry.d.ts.map +1 -0
- package/dist/accounts/registry.js +278 -0
- package/dist/accounts/registry.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +629 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +40 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +216 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +15 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +15 -0
- package/dist/context.js.map +1 -0
- package/dist/http/app.d.ts +16 -0
- package/dist/http/app.d.ts.map +1 -0
- package/dist/http/app.js +118 -0
- package/dist/http/app.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/licensing/activation.d.ts +5 -0
- package/dist/licensing/activation.d.ts.map +1 -0
- package/dist/licensing/activation.js +11 -0
- package/dist/licensing/activation.js.map +1 -0
- package/dist/licensing/client.d.ts +52 -0
- package/dist/licensing/client.d.ts.map +1 -0
- package/dist/licensing/client.js +75 -0
- package/dist/licensing/client.js.map +1 -0
- package/dist/licensing/entitlements.d.ts +55 -0
- package/dist/licensing/entitlements.d.ts.map +1 -0
- package/dist/licensing/entitlements.js +116 -0
- package/dist/licensing/entitlements.js.map +1 -0
- package/dist/licensing/lease.d.ts +47 -0
- package/dist/licensing/lease.d.ts.map +1 -0
- package/dist/licensing/lease.js +103 -0
- package/dist/licensing/lease.js.map +1 -0
- package/dist/licensing/refresher.d.ts +46 -0
- package/dist/licensing/refresher.d.ts.map +1 -0
- package/dist/licensing/refresher.js +150 -0
- package/dist/licensing/refresher.js.map +1 -0
- package/dist/mcp/buildServer.d.ts +28 -0
- package/dist/mcp/buildServer.d.ts.map +1 -0
- package/dist/mcp/buildServer.js +414 -0
- package/dist/mcp/buildServer.js.map +1 -0
- package/dist/scheduler/sendScheduler.d.ts +38 -0
- package/dist/scheduler/sendScheduler.d.ts.map +1 -0
- package/dist/scheduler/sendScheduler.js +128 -0
- package/dist/scheduler/sendScheduler.js.map +1 -0
- package/dist/service/emailService.d.ts +139 -0
- package/dist/service/emailService.d.ts.map +1 -0
- package/dist/service/emailService.js +380 -0
- package/dist/service/emailService.js.map +1 -0
- package/dist/storage/apiKeys.d.ts +27 -0
- package/dist/storage/apiKeys.d.ts.map +1 -0
- package/dist/storage/apiKeys.js +49 -0
- package/dist/storage/apiKeys.js.map +1 -0
- package/dist/storage/crypto.d.ts +4 -0
- package/dist/storage/crypto.d.ts.map +1 -0
- package/dist/storage/crypto.js +21 -0
- package/dist/storage/crypto.js.map +1 -0
- package/dist/storage/db.d.ts +1041 -0
- package/dist/storage/db.d.ts.map +1 -0
- package/dist/storage/db.js +211 -0
- package/dist/storage/db.js.map +1 -0
- package/dist/storage/imapState.d.ts +15 -0
- package/dist/storage/imapState.d.ts.map +1 -0
- package/dist/storage/imapState.js +89 -0
- package/dist/storage/imapState.js.map +1 -0
- package/dist/storage/members.d.ts +29 -0
- package/dist/storage/members.d.ts.map +1 -0
- package/dist/storage/members.js +67 -0
- package/dist/storage/members.js.map +1 -0
- package/dist/storage/scheduledSends.d.ts +60 -0
- package/dist/storage/scheduledSends.d.ts.map +1 -0
- package/dist/storage/scheduledSends.js +169 -0
- package/dist/storage/scheduledSends.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +7 -0
- package/dist/version.js.map +1 -0
- package/package.json +49 -15
- package/bin/fluxmail.js +0 -4
- package/src/cli.js +0 -36
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { validateLicense } from './client.js';
|
|
5
|
+
import { licensePublicKeys, verifyLease } from './lease.js';
|
|
6
|
+
import { getEntitlements, readLeaseRow, saveLeaseToken } from './entitlements.js';
|
|
7
|
+
/** Instances revalidate roughly daily; the lease itself is valid for ~7 days. */
|
|
8
|
+
export const VALIDATE_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
9
|
+
/** After an outage, retry sooner than the daily cadence. */
|
|
10
|
+
const OUTAGE_RETRY_MS = 60 * 60 * 1000;
|
|
11
|
+
/**
|
|
12
|
+
* Stable random id per install, persisted next to the database. Not a secret;
|
|
13
|
+
* it lets the license server spot one key shared across many instances.
|
|
14
|
+
*/
|
|
15
|
+
export function loadInstanceId(dataDir) {
|
|
16
|
+
const file = path.join(dataDir, 'instance.id');
|
|
17
|
+
if (existsSync(file)) {
|
|
18
|
+
const id = readFileSync(file, 'utf8').trim();
|
|
19
|
+
if (id)
|
|
20
|
+
return id;
|
|
21
|
+
}
|
|
22
|
+
const id = randomBytes(16).toString('hex');
|
|
23
|
+
writeFileSync(file, id + '\n');
|
|
24
|
+
return id;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Validate the license with the server and cache the returned lease. Every
|
|
28
|
+
* failure keeps the existing cached lease, per the contract: an outage or a
|
|
29
|
+
* lapsed subscription degrades to free-tier limits only once the cached lease
|
|
30
|
+
* expires, and never interrupts a running server.
|
|
31
|
+
*/
|
|
32
|
+
export async function refreshLicense(db, opts) {
|
|
33
|
+
const result = await validateLicense({
|
|
34
|
+
serverUrl: opts.serverUrl,
|
|
35
|
+
licenseKey: opts.licenseKey,
|
|
36
|
+
instanceId: loadInstanceId(opts.dataDir),
|
|
37
|
+
...(opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}),
|
|
38
|
+
});
|
|
39
|
+
const cachedLeaseActive = () => getEntitlements(db).licensed;
|
|
40
|
+
switch (result.kind) {
|
|
41
|
+
case 'valid': {
|
|
42
|
+
let lease;
|
|
43
|
+
try {
|
|
44
|
+
lease = verifyLease(result.lease, licensePublicKeys());
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
return {
|
|
48
|
+
outcome: 'bad_lease',
|
|
49
|
+
message: `The license server returned a lease this build cannot verify ` +
|
|
50
|
+
`(${err instanceof Error ? err.message : String(err)}). ` +
|
|
51
|
+
'Update Fluxmail if a signing-key rotation was announced.',
|
|
52
|
+
cachedLeaseActive: cachedLeaseActive(),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
saveLeaseToken(db, result.lease);
|
|
56
|
+
return { outcome: 'refreshed', lease };
|
|
57
|
+
}
|
|
58
|
+
case 'invalid_request':
|
|
59
|
+
return {
|
|
60
|
+
outcome: 'invalid_key',
|
|
61
|
+
message: 'The license server rejected the key as malformed; check FLUXMAIL_LICENSE_KEY.',
|
|
62
|
+
cachedLeaseActive: cachedLeaseActive(),
|
|
63
|
+
};
|
|
64
|
+
case 'license_not_found':
|
|
65
|
+
return {
|
|
66
|
+
outcome: 'not_found',
|
|
67
|
+
message: 'The license key is invalid; check it for typos.',
|
|
68
|
+
cachedLeaseActive: cachedLeaseActive(),
|
|
69
|
+
};
|
|
70
|
+
case 'license_inactive':
|
|
71
|
+
return {
|
|
72
|
+
outcome: 'inactive',
|
|
73
|
+
message: `The license is no longer active (${result.status}).`,
|
|
74
|
+
cachedLeaseActive: cachedLeaseActive(),
|
|
75
|
+
};
|
|
76
|
+
case 'license_in_use':
|
|
77
|
+
return {
|
|
78
|
+
outcome: 'in_use',
|
|
79
|
+
message: 'This license is already active on another Fluxmail instance. ' +
|
|
80
|
+
'Run "fluxmail license deactivate" there first, or manage instances from your Fluxmail account.',
|
|
81
|
+
cachedLeaseActive: cachedLeaseActive(),
|
|
82
|
+
};
|
|
83
|
+
case 'outage':
|
|
84
|
+
return {
|
|
85
|
+
outcome: 'outage',
|
|
86
|
+
message: `Could not reach the license server (${result.detail}); will retry.`,
|
|
87
|
+
cachedLeaseActive: cachedLeaseActive(),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Background revalidation for long-running server modes: refresh immediately
|
|
93
|
+
* if the last validation is over a day old, then keep a daily cadence. Timers
|
|
94
|
+
* are unref'd and every failure path is caught, so licensing can never keep
|
|
95
|
+
* the process alive or take it down. Returns a stop function.
|
|
96
|
+
*/
|
|
97
|
+
export function startLicenseRefresher(deps) {
|
|
98
|
+
const { db, config } = deps;
|
|
99
|
+
const log = deps.log ?? (() => { });
|
|
100
|
+
const licenseKey = config.licenseKey;
|
|
101
|
+
if (!licenseKey)
|
|
102
|
+
return () => { };
|
|
103
|
+
let timer;
|
|
104
|
+
let stopped = false;
|
|
105
|
+
const schedule = (delayMs) => {
|
|
106
|
+
if (stopped)
|
|
107
|
+
return;
|
|
108
|
+
timer = setTimeout(() => void run(), delayMs);
|
|
109
|
+
timer.unref();
|
|
110
|
+
};
|
|
111
|
+
const run = async () => {
|
|
112
|
+
let result;
|
|
113
|
+
try {
|
|
114
|
+
result = await refreshLicense(db, {
|
|
115
|
+
licenseKey,
|
|
116
|
+
serverUrl: config.licenseServerUrl,
|
|
117
|
+
dataDir: config.dataDir,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
log(`License refresh failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
122
|
+
schedule(OUTAGE_RETRY_MS);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (result.outcome === 'refreshed') {
|
|
126
|
+
log(`License validated; lease renewed until ${result.lease.expiresAt}`);
|
|
127
|
+
deps.onRefreshed?.();
|
|
128
|
+
schedule(VALIDATE_INTERVAL_MS);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
log(`License validation: ${result.message}` +
|
|
132
|
+
(result.cachedLeaseActive
|
|
133
|
+
? ' The cached lease keeps paid limits for now.'
|
|
134
|
+
: ' Running with Personal-plan limits.'));
|
|
135
|
+
schedule(result.outcome === 'outage' ? OUTAGE_RETRY_MS : VALIDATE_INTERVAL_MS);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
const row = readLeaseRow(db);
|
|
139
|
+
const sinceLastValidation = row ? Date.now() - row.updatedAt : Number.POSITIVE_INFINITY;
|
|
140
|
+
if (sinceLastValidation >= VALIDATE_INTERVAL_MS)
|
|
141
|
+
void run();
|
|
142
|
+
else
|
|
143
|
+
schedule(VALIDATE_INTERVAL_MS - sinceLastValidation);
|
|
144
|
+
return () => {
|
|
145
|
+
stopped = true;
|
|
146
|
+
if (timer)
|
|
147
|
+
clearTimeout(timer);
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=refresher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresher.js","sourceRoot":"","sources":["../../src/licensing/refresher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { EmailService, SendInput } from '../service/emailService.js';
|
|
3
|
+
type DraftArgs = {
|
|
4
|
+
accountId?: string;
|
|
5
|
+
to?: string[];
|
|
6
|
+
cc?: string[];
|
|
7
|
+
bcc?: string[];
|
|
8
|
+
subject?: string;
|
|
9
|
+
bodyText?: string;
|
|
10
|
+
bodyHtml?: string;
|
|
11
|
+
replyToMessageId?: string;
|
|
12
|
+
replyAll?: boolean;
|
|
13
|
+
attachments?: Array<{
|
|
14
|
+
filename: string;
|
|
15
|
+
mimeType: string;
|
|
16
|
+
content: string;
|
|
17
|
+
}>;
|
|
18
|
+
};
|
|
19
|
+
export declare function toSendRequest(args: DraftArgs & {
|
|
20
|
+
draftId?: string;
|
|
21
|
+
}): SendInput | {
|
|
22
|
+
draftId: string;
|
|
23
|
+
};
|
|
24
|
+
export declare function resolveAttachmentSavePath(savePath: string, filename: string): string;
|
|
25
|
+
export declare function saveAttachment(savePath: string, filename: string, content: Buffer): string;
|
|
26
|
+
export declare function buildMcpServer(service: EmailService): McpServer;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=buildServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildServer.d.ts","sourceRoot":"","sources":["../../src/mcp/buildServer.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAYpE,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAuE1E,KAAK,SAAS,GAAG;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9E,CAAC;AAyBF,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAsBrG;AAqDD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAcpF;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAY1F;AAqBD,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,SAAS,CAoU/D"}
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
import { existsSync, statSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { VERSION } from '../version.js';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
6
|
+
import { EmailError, isEmailError, parseSingleAddress, } from '@fluxmail/core';
|
|
7
|
+
const MAX_BODY_CHARS = 50_000;
|
|
8
|
+
const MAX_INLINE_ATTACHMENT_BYTES = 2 * 1024 * 1024;
|
|
9
|
+
const accountIdParam = z
|
|
10
|
+
.string()
|
|
11
|
+
.min(1)
|
|
12
|
+
.optional()
|
|
13
|
+
.describe('Account to operate on. Optional when exactly one account is connected.');
|
|
14
|
+
const idParam = z.string().min(1);
|
|
15
|
+
const addressList = z.array(z.string().min(1)).describe('Recipients, each "Name <a@x.com>" or "a@x.com"');
|
|
16
|
+
const queryShape = {
|
|
17
|
+
folder: z
|
|
18
|
+
.string()
|
|
19
|
+
.min(1)
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Folder role (inbox, sent, drafts, trash, spam, starred, archive, all) or a label/folder name'),
|
|
22
|
+
text: z.string().optional().describe('Full-text search terms'),
|
|
23
|
+
from: z.string().optional(),
|
|
24
|
+
to: z.string().optional(),
|
|
25
|
+
subject: z.string().optional(),
|
|
26
|
+
unreadOnly: z.boolean().optional(),
|
|
27
|
+
starredOnly: z.boolean().optional(),
|
|
28
|
+
hasAttachment: z.boolean().optional(),
|
|
29
|
+
after: z.string().min(1).optional().describe('ISO date, inclusive'),
|
|
30
|
+
before: z.string().min(1).optional().describe('ISO date, exclusive'),
|
|
31
|
+
rawProviderQuery: z
|
|
32
|
+
.string()
|
|
33
|
+
.optional()
|
|
34
|
+
.describe('Escape hatch passed verbatim to the provider (e.g. Gmail q= syntax)'),
|
|
35
|
+
pageSize: z.number().int().min(1).max(100).optional().describe('Defaults to 25'),
|
|
36
|
+
pageToken: z.string().min(1).optional().describe('nextPageToken from a previous call'),
|
|
37
|
+
};
|
|
38
|
+
const draftShape = {
|
|
39
|
+
accountId: accountIdParam,
|
|
40
|
+
to: addressList.optional(),
|
|
41
|
+
cc: addressList.optional(),
|
|
42
|
+
bcc: addressList.optional(),
|
|
43
|
+
subject: z.string().optional().describe('Defaults to "Re: ..." when replying'),
|
|
44
|
+
bodyText: z.string().optional().describe('Plain-text body'),
|
|
45
|
+
bodyHtml: z.string().optional().describe('HTML body'),
|
|
46
|
+
replyToMessageId: idParam
|
|
47
|
+
.optional()
|
|
48
|
+
.describe('Message being replied to; threads correctly and computes recipients if "to" is omitted'),
|
|
49
|
+
replyAll: z.boolean().optional().describe('With replyToMessageId: reply to all original recipients'),
|
|
50
|
+
attachments: z
|
|
51
|
+
.array(z.object({
|
|
52
|
+
filename: z.string().min(1),
|
|
53
|
+
mimeType: z.string().min(1),
|
|
54
|
+
content: z.string().describe('base64'),
|
|
55
|
+
}))
|
|
56
|
+
.optional(),
|
|
57
|
+
};
|
|
58
|
+
function parseAddresses(raw) {
|
|
59
|
+
if (!raw)
|
|
60
|
+
return undefined;
|
|
61
|
+
const parsed = raw.map((r) => {
|
|
62
|
+
const addr = parseSingleAddress(r);
|
|
63
|
+
if (!addr)
|
|
64
|
+
throw new EmailError('invalid_request', `Could not parse email address: "${r}"`);
|
|
65
|
+
return addr;
|
|
66
|
+
});
|
|
67
|
+
return parsed;
|
|
68
|
+
}
|
|
69
|
+
function toSendInput(args) {
|
|
70
|
+
if (args.replyAll && !args.replyToMessageId) {
|
|
71
|
+
throw new EmailError('invalid_request', 'replyAll requires replyToMessageId');
|
|
72
|
+
}
|
|
73
|
+
const input = {
|
|
74
|
+
body: {
|
|
75
|
+
...(args.bodyText !== undefined ? { text: args.bodyText } : {}),
|
|
76
|
+
...(args.bodyHtml !== undefined ? { html: args.bodyHtml } : {}),
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
const to = parseAddresses(args.to);
|
|
80
|
+
if (to?.length)
|
|
81
|
+
input.to = to;
|
|
82
|
+
const cc = parseAddresses(args.cc);
|
|
83
|
+
if (cc?.length)
|
|
84
|
+
input.cc = cc;
|
|
85
|
+
const bcc = parseAddresses(args.bcc);
|
|
86
|
+
if (bcc?.length)
|
|
87
|
+
input.bcc = bcc;
|
|
88
|
+
if (args.subject !== undefined)
|
|
89
|
+
input.subject = args.subject;
|
|
90
|
+
if (args.replyToMessageId)
|
|
91
|
+
input.replyToMessageId = args.replyToMessageId;
|
|
92
|
+
if (args.replyAll !== undefined)
|
|
93
|
+
input.replyAll = args.replyAll;
|
|
94
|
+
if (args.attachments?.length)
|
|
95
|
+
input.attachments = args.attachments;
|
|
96
|
+
return input;
|
|
97
|
+
}
|
|
98
|
+
export function toSendRequest(args) {
|
|
99
|
+
if (args.draftId !== undefined) {
|
|
100
|
+
const contentKeys = [
|
|
101
|
+
'to',
|
|
102
|
+
'cc',
|
|
103
|
+
'bcc',
|
|
104
|
+
'subject',
|
|
105
|
+
'bodyText',
|
|
106
|
+
'bodyHtml',
|
|
107
|
+
'replyToMessageId',
|
|
108
|
+
'replyAll',
|
|
109
|
+
'attachments',
|
|
110
|
+
];
|
|
111
|
+
if (contentKeys.some((key) => args[key] !== undefined)) {
|
|
112
|
+
throw new EmailError('invalid_request', 'draftId cannot be combined with message content; update the draft before sending it');
|
|
113
|
+
}
|
|
114
|
+
return { draftId: args.draftId };
|
|
115
|
+
}
|
|
116
|
+
return toSendInput(args);
|
|
117
|
+
}
|
|
118
|
+
function truncateBody(message) {
|
|
119
|
+
if (!message.body)
|
|
120
|
+
return message;
|
|
121
|
+
const body = { ...message.body };
|
|
122
|
+
for (const key of ['text', 'html']) {
|
|
123
|
+
const value = body[key];
|
|
124
|
+
if (value && value.length > MAX_BODY_CHARS) {
|
|
125
|
+
body[key] = value.slice(0, MAX_BODY_CHARS) + `\n… [truncated ${value.length - MAX_BODY_CHARS} characters]`;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return { ...message, body };
|
|
129
|
+
}
|
|
130
|
+
function ok(data, warning) {
|
|
131
|
+
return {
|
|
132
|
+
content: [
|
|
133
|
+
{ type: 'text', text: JSON.stringify(data, null, 2) },
|
|
134
|
+
...(warning ? [{ type: 'text', text: `Note: ${warning}` }] : []),
|
|
135
|
+
],
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function toolError(err) {
|
|
139
|
+
const payload = isEmailError(err)
|
|
140
|
+
? { error: err.code, message: err.message, ...(err.data ? { data: err.data } : {}) }
|
|
141
|
+
: { error: 'internal', message: err instanceof Error ? err.message : String(err) };
|
|
142
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }] };
|
|
143
|
+
}
|
|
144
|
+
function handle(fn, gate) {
|
|
145
|
+
return async (...args) => {
|
|
146
|
+
try {
|
|
147
|
+
// The gate throws when a lapsed license leaves the instance over quota,
|
|
148
|
+
// and yields a renewal warning to attach while the license is in grace.
|
|
149
|
+
const warning = gate?.();
|
|
150
|
+
return ok(await fn(...args), warning);
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
return toolError(err);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
function pageOpts(args) {
|
|
158
|
+
return {
|
|
159
|
+
...(args.pageSize !== undefined ? { pageSize: args.pageSize } : {}),
|
|
160
|
+
...(args.pageToken !== undefined ? { pageToken: args.pageToken } : {}),
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
export function resolveAttachmentSavePath(savePath, filename) {
|
|
164
|
+
const isDir = savePath.endsWith(path.sep) || (existsSync(savePath) && statSync(savePath).isDirectory());
|
|
165
|
+
if (!isDir)
|
|
166
|
+
return savePath;
|
|
167
|
+
const safeFilename = path.posix.basename(filename.replace(/\\/g, '/'));
|
|
168
|
+
if (!safeFilename || safeFilename === '.' || safeFilename === '..') {
|
|
169
|
+
throw new Error('Attachment filename is not safe to use');
|
|
170
|
+
}
|
|
171
|
+
const directory = path.resolve(savePath);
|
|
172
|
+
const target = path.resolve(directory, safeFilename);
|
|
173
|
+
if (path.dirname(target) !== directory) {
|
|
174
|
+
throw new Error('Attachment filename escapes the destination directory');
|
|
175
|
+
}
|
|
176
|
+
return target;
|
|
177
|
+
}
|
|
178
|
+
export function saveAttachment(savePath, filename, content) {
|
|
179
|
+
if (!path.isAbsolute(savePath))
|
|
180
|
+
throw new EmailError('invalid_request', 'savePath must be absolute');
|
|
181
|
+
const target = resolveAttachmentSavePath(savePath, filename);
|
|
182
|
+
try {
|
|
183
|
+
writeFileSync(target, content, { flag: 'wx' });
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
if (err.code === 'EEXIST') {
|
|
187
|
+
throw new EmailError('invalid_request', `Refusing to overwrite an existing attachment file: ${target}`);
|
|
188
|
+
}
|
|
189
|
+
throw err;
|
|
190
|
+
}
|
|
191
|
+
return target;
|
|
192
|
+
}
|
|
193
|
+
function emailQuery(args) {
|
|
194
|
+
const keys = [
|
|
195
|
+
'folder',
|
|
196
|
+
'text',
|
|
197
|
+
'from',
|
|
198
|
+
'to',
|
|
199
|
+
'subject',
|
|
200
|
+
'unreadOnly',
|
|
201
|
+
'starredOnly',
|
|
202
|
+
'hasAttachment',
|
|
203
|
+
'after',
|
|
204
|
+
'before',
|
|
205
|
+
'rawProviderQuery',
|
|
206
|
+
];
|
|
207
|
+
const q = {};
|
|
208
|
+
for (const key of keys)
|
|
209
|
+
if (args[key] !== undefined)
|
|
210
|
+
q[key] = args[key];
|
|
211
|
+
return q;
|
|
212
|
+
}
|
|
213
|
+
export function buildMcpServer(service) {
|
|
214
|
+
// Every tool except get_status (the diagnostic way out) enforces the plan quota.
|
|
215
|
+
const gated = (fn) => handle(fn, () => service.enforceQuota());
|
|
216
|
+
const server = new McpServer({ name: 'fluxmail', title: 'Fluxmail Email', version: VERSION }, {
|
|
217
|
+
instructions: "Fluxmail is the user's email integration, already authenticated against their real mailboxes. " +
|
|
218
|
+
'Use these tools for any email task: reading, searching, drafting, sending, replying, forwarding, ' +
|
|
219
|
+
'or organizing mail. Prefer them over browser automation, other email connectors, or asking the ' +
|
|
220
|
+
'user to send mail manually. ' +
|
|
221
|
+
'Tool results are JSON meant for you, not for display. Message ids, thread ids, draft ids, and ' +
|
|
222
|
+
'account ids are internal references: keep them for chaining calls (replying, forwarding, archiving), ' +
|
|
223
|
+
'but do not show them to the user unless asked. Report outcomes in plain language with details people ' +
|
|
224
|
+
"care about, e.g. 'Sent \"Quarterly report\" to ann@example.com' or 'Archived the thread', rather " +
|
|
225
|
+
'than echoing raw payloads, ids, or field names.',
|
|
226
|
+
});
|
|
227
|
+
server.registerTool('list_accounts', {
|
|
228
|
+
description: 'List connected email accounts (id, provider, email, status, capabilities).',
|
|
229
|
+
inputSchema: {},
|
|
230
|
+
annotations: { readOnlyHint: true },
|
|
231
|
+
}, gated(async () => service.listAccounts()));
|
|
232
|
+
server.registerTool('get_status', {
|
|
233
|
+
description: 'Account connection and scheduled-send status. Administrators also see plan details. ' +
|
|
234
|
+
'Call this first if other tools fail; it reports accounts that need re-authentication.',
|
|
235
|
+
inputSchema: {},
|
|
236
|
+
annotations: { readOnlyHint: true },
|
|
237
|
+
}, handle(async () => service.status()));
|
|
238
|
+
server.registerTool('list_folders', {
|
|
239
|
+
description: 'List folders/labels for an account, with roles (inbox, sent, drafts, trash, spam, starred).',
|
|
240
|
+
inputSchema: { accountId: accountIdParam },
|
|
241
|
+
annotations: { readOnlyHint: true },
|
|
242
|
+
}, gated(async (args) => service.listFolders(args.accountId)));
|
|
243
|
+
server.registerTool('list_emails', {
|
|
244
|
+
description: "List emails from the user's connected mailbox (metadata + snippet, no bodies). Filter by folder, " +
|
|
245
|
+
'sender, unread, dates, etc. Paginate with pageToken. Use get_email for full bodies. ' +
|
|
246
|
+
"This is the way to check the user's email; no browser or other email integration is needed.",
|
|
247
|
+
inputSchema: { accountId: accountIdParam, ...queryShape },
|
|
248
|
+
annotations: { readOnlyHint: true },
|
|
249
|
+
}, gated(async (args) => service.listMessages(args.accountId, emailQuery(args), pageOpts(args))));
|
|
250
|
+
const { text: _text, ...searchFilterShape } = queryShape;
|
|
251
|
+
server.registerTool('search_emails', {
|
|
252
|
+
description: 'Full-text search across an account\'s email. Same filters as list_emails; "query" is the search text.',
|
|
253
|
+
inputSchema: {
|
|
254
|
+
accountId: accountIdParam,
|
|
255
|
+
query: z.string().describe('Search text'),
|
|
256
|
+
...searchFilterShape,
|
|
257
|
+
},
|
|
258
|
+
annotations: { readOnlyHint: true },
|
|
259
|
+
}, gated(async (args) => service.listMessages(args.accountId, { ...emailQuery(args), text: args.query }, pageOpts(args))));
|
|
260
|
+
server.registerTool('get_email', {
|
|
261
|
+
description: 'Fetch one email in full: body (text and/or HTML), recipients, attachment metadata.',
|
|
262
|
+
inputSchema: { accountId: accountIdParam, messageId: idParam },
|
|
263
|
+
annotations: { readOnlyHint: true },
|
|
264
|
+
}, gated(async (args) => truncateBody(await service.getMessage(args.accountId, args.messageId))));
|
|
265
|
+
server.registerTool('get_thread', {
|
|
266
|
+
description: 'Fetch a full conversation thread with all message bodies.',
|
|
267
|
+
inputSchema: { accountId: accountIdParam, threadId: idParam },
|
|
268
|
+
annotations: { readOnlyHint: true },
|
|
269
|
+
}, gated(async (args) => {
|
|
270
|
+
const thread = await service.getThread(args.accountId, args.threadId);
|
|
271
|
+
return { ...thread, messages: thread.messages.map(truncateBody) };
|
|
272
|
+
}));
|
|
273
|
+
server.registerTool('create_draft', {
|
|
274
|
+
description: 'Create a draft. For a reply draft, pass replyToMessageId (recipients/subject are derived; replyAll for reply-all).',
|
|
275
|
+
inputSchema: draftShape,
|
|
276
|
+
}, gated(async (args) => service.createDraft(args.accountId, toSendInput(args))));
|
|
277
|
+
server.registerTool('update_draft', {
|
|
278
|
+
description: 'Replace the content of an existing draft (full replacement, not a patch).',
|
|
279
|
+
inputSchema: { draftId: idParam, ...draftShape },
|
|
280
|
+
}, gated(async (args) => service.updateDraft(args.accountId, args.draftId, toSendInput(args))));
|
|
281
|
+
server.registerTool('delete_draft', {
|
|
282
|
+
description: 'Delete a draft.',
|
|
283
|
+
inputSchema: { accountId: accountIdParam, draftId: idParam },
|
|
284
|
+
annotations: { destructiveHint: true },
|
|
285
|
+
}, gated(async (args) => {
|
|
286
|
+
await service.deleteDraft(args.accountId, args.draftId);
|
|
287
|
+
return { deleted: args.draftId };
|
|
288
|
+
}));
|
|
289
|
+
server.registerTool('send_email', {
|
|
290
|
+
description: "Send an email from the user's connected account; this actually delivers mail, so prefer it over " +
|
|
291
|
+
'browser automation or leaving a draft when the user asked to send. Three modes: direct (to + subject ' +
|
|
292
|
+
'+ body), sending an existing draft (draftId), or replying (replyToMessageId, optionally replyAll) ' +
|
|
293
|
+
'where recipients, subject, and threading are derived from the original. Confirm with the user when ' +
|
|
294
|
+
'intent is ambiguous. Add sendAt to any mode to schedule instead of sending now.',
|
|
295
|
+
inputSchema: {
|
|
296
|
+
draftId: idParam.optional().describe('Send this existing draft'),
|
|
297
|
+
...draftShape,
|
|
298
|
+
sendAt: z
|
|
299
|
+
.string()
|
|
300
|
+
.datetime({ offset: true })
|
|
301
|
+
.optional()
|
|
302
|
+
.describe('Schedule delivery instead of sending now: ISO 8601 with timezone offset or Z ' +
|
|
303
|
+
'(e.g. 2026-07-11T09:00:00-07:00). Fluxmail saves the message as a real draft in the mailbox ' +
|
|
304
|
+
'and sends it at this time; the server must be running then (anything missed while it was ' +
|
|
305
|
+
'down goes out at the next startup). Returns a scheduleId for list/cancel.'),
|
|
306
|
+
},
|
|
307
|
+
annotations: { destructiveHint: true },
|
|
308
|
+
}, gated(async (args) => {
|
|
309
|
+
const { sendAt, ...sendArgs } = args;
|
|
310
|
+
return sendAt !== undefined
|
|
311
|
+
? service.scheduleSend(args.accountId, toSendRequest(sendArgs), sendAt)
|
|
312
|
+
: service.send(args.accountId, toSendRequest(sendArgs));
|
|
313
|
+
}));
|
|
314
|
+
server.registerTool('list_scheduled_emails', {
|
|
315
|
+
description: 'List scheduled sends: pending ones first (with sendAt), then past ones (sent, failed, canceled). ' +
|
|
316
|
+
'For failed entries, lastError says what went wrong. Pending sends only fire while the ' +
|
|
317
|
+
'Fluxmail server is running.',
|
|
318
|
+
inputSchema: { accountId: accountIdParam },
|
|
319
|
+
annotations: { readOnlyHint: true },
|
|
320
|
+
}, gated(async (args) => service.listScheduled(args.accountId)));
|
|
321
|
+
server.registerTool('cancel_scheduled_email', {
|
|
322
|
+
description: 'Cancel a pending scheduled send by scheduleId (from send_email with sendAt, or list_scheduled_emails). ' +
|
|
323
|
+
'The draft stays in the Drafts folder, so the content is not lost.',
|
|
324
|
+
inputSchema: { scheduleId: idParam },
|
|
325
|
+
}, gated(async (args) => service.cancelScheduled(args.scheduleId)));
|
|
326
|
+
server.registerTool('forward_email', {
|
|
327
|
+
description: 'Forward an email to new recipients: quoted original body, "Fwd:" subject, original attachments included ' +
|
|
328
|
+
'unless includeAttachments=false. Optional comment appears above the forwarded content.',
|
|
329
|
+
inputSchema: {
|
|
330
|
+
accountId: accountIdParam,
|
|
331
|
+
messageId: idParam,
|
|
332
|
+
to: addressList.min(1),
|
|
333
|
+
cc: addressList.optional(),
|
|
334
|
+
comment: z.string().optional(),
|
|
335
|
+
includeAttachments: z.boolean().optional().describe('Default true'),
|
|
336
|
+
},
|
|
337
|
+
annotations: { destructiveHint: true },
|
|
338
|
+
}, gated(async (args) => {
|
|
339
|
+
const to = parseAddresses(args.to) ?? [];
|
|
340
|
+
const cc = parseAddresses(args.cc);
|
|
341
|
+
return service.forward(args.accountId, {
|
|
342
|
+
messageId: args.messageId,
|
|
343
|
+
to,
|
|
344
|
+
...(cc?.length ? { cc } : {}),
|
|
345
|
+
...(args.comment !== undefined ? { comment: args.comment } : {}),
|
|
346
|
+
...(args.includeAttachments !== undefined ? { includeAttachments: args.includeAttachments } : {}),
|
|
347
|
+
});
|
|
348
|
+
}));
|
|
349
|
+
server.registerTool('modify_emails', {
|
|
350
|
+
description: 'Batch-modify emails: markRead, markUnread, star, unstar, archive, trash, untrash, delete (permanent!), ' +
|
|
351
|
+
'move (requires folder), addLabels/removeLabels (requires labels; Gmail only).',
|
|
352
|
+
inputSchema: {
|
|
353
|
+
accountId: accountIdParam,
|
|
354
|
+
messageIds: z.array(idParam).min(1),
|
|
355
|
+
action: z.enum([
|
|
356
|
+
'markRead',
|
|
357
|
+
'markUnread',
|
|
358
|
+
'star',
|
|
359
|
+
'unstar',
|
|
360
|
+
'archive',
|
|
361
|
+
'trash',
|
|
362
|
+
'untrash',
|
|
363
|
+
'delete',
|
|
364
|
+
'move',
|
|
365
|
+
'addLabels',
|
|
366
|
+
'removeLabels',
|
|
367
|
+
]),
|
|
368
|
+
folder: z.string().min(1).optional().describe('Target folder for action=move'),
|
|
369
|
+
labels: z.array(z.string().min(1)).max(100).optional().describe('Labels for addLabels/removeLabels'),
|
|
370
|
+
},
|
|
371
|
+
annotations: { destructiveHint: true },
|
|
372
|
+
}, gated(async (args) => {
|
|
373
|
+
let action;
|
|
374
|
+
if (args.action === 'move') {
|
|
375
|
+
if (!args.folder)
|
|
376
|
+
throw new EmailError('invalid_request', 'action=move requires "folder"');
|
|
377
|
+
action = { move: args.folder };
|
|
378
|
+
}
|
|
379
|
+
else if (args.action === 'addLabels' || args.action === 'removeLabels') {
|
|
380
|
+
if (!args.labels?.length) {
|
|
381
|
+
throw new EmailError('invalid_request', `action=${args.action} requires "labels"`);
|
|
382
|
+
}
|
|
383
|
+
action = args.action === 'addLabels' ? { addLabels: args.labels } : { removeLabels: args.labels };
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
action = args.action;
|
|
387
|
+
}
|
|
388
|
+
await service.modify(args.accountId, args.messageIds, action);
|
|
389
|
+
return { modified: args.messageIds.length, action: args.action };
|
|
390
|
+
}));
|
|
391
|
+
server.registerTool('download_attachment', {
|
|
392
|
+
description: 'Download an email attachment. With savePath, writes the file to disk and returns the path; ' +
|
|
393
|
+
'otherwise returns base64 content (up to 2 MB).',
|
|
394
|
+
inputSchema: {
|
|
395
|
+
accountId: accountIdParam,
|
|
396
|
+
messageId: idParam,
|
|
397
|
+
attachmentId: idParam,
|
|
398
|
+
savePath: z.string().min(1).optional().describe('Absolute file path or directory to write the attachment to'),
|
|
399
|
+
},
|
|
400
|
+
annotations: { readOnlyHint: false, destructiveHint: true },
|
|
401
|
+
}, gated(async (args) => {
|
|
402
|
+
const { meta, content } = await service.getAttachment(args.accountId, args.messageId, args.attachmentId);
|
|
403
|
+
if (args.savePath) {
|
|
404
|
+
const target = saveAttachment(args.savePath, meta.filename, content);
|
|
405
|
+
return { saved: target, ...meta };
|
|
406
|
+
}
|
|
407
|
+
if (content.length > MAX_INLINE_ATTACHMENT_BYTES) {
|
|
408
|
+
throw new EmailError('invalid_request', `Attachment is ${content.length} bytes (limit ${MAX_INLINE_ATTACHMENT_BYTES} inline). Pass savePath to write it to disk.`);
|
|
409
|
+
}
|
|
410
|
+
return { ...meta, contentBase64: content.toString('base64') };
|
|
411
|
+
}));
|
|
412
|
+
return server;
|
|
413
|
+
}
|
|
414
|
+
//# sourceMappingURL=buildServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildServer.js","sourceRoot":"","sources":["../../src/mcp/buildServer.ts"],"names":[],"mappings":"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"}
|