@ni-c/imap-mcp 0.2.0 → 0.4.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 (67) hide show
  1. package/README.md +142 -35
  2. package/dist/analyze.d.ts +54 -6
  3. package/dist/analyze.js +295 -27
  4. package/dist/analyze.js.map +1 -1
  5. package/dist/attachments.d.ts +36 -0
  6. package/dist/attachments.js +21 -3
  7. package/dist/attachments.js.map +1 -1
  8. package/dist/audit.d.ts +7 -0
  9. package/dist/audit.js +11 -3
  10. package/dist/audit.js.map +1 -1
  11. package/dist/config.d.ts +32 -0
  12. package/dist/config.js +65 -6
  13. package/dist/config.js.map +1 -1
  14. package/dist/errors.js.map +1 -1
  15. package/dist/extract/child.d.ts +1 -0
  16. package/dist/extract/child.js +83 -0
  17. package/dist/extract/child.js.map +1 -0
  18. package/dist/extract/index.d.ts +41 -0
  19. package/dist/extract/index.js +183 -0
  20. package/dist/extract/index.js.map +1 -0
  21. package/dist/extract/ooxml.d.ts +35 -0
  22. package/dist/extract/ooxml.js +627 -0
  23. package/dist/extract/ooxml.js.map +1 -0
  24. package/dist/extract/pdf.d.ts +62 -0
  25. package/dist/extract/pdf.js +539 -0
  26. package/dist/extract/pdf.js.map +1 -0
  27. package/dist/extract/types.d.ts +56 -0
  28. package/dist/extract/types.js +13 -0
  29. package/dist/extract/types.js.map +1 -0
  30. package/dist/imap.js.map +1 -1
  31. package/dist/index.js +32 -5
  32. package/dist/index.js.map +1 -1
  33. package/dist/output-schema.d.ts +63 -0
  34. package/dist/output-schema.js +87 -0
  35. package/dist/output-schema.js.map +1 -0
  36. package/dist/resources.d.ts +1 -1
  37. package/dist/resources.js +5 -2
  38. package/dist/resources.js.map +1 -1
  39. package/dist/result.d.ts +39 -6
  40. package/dist/result.js +142 -29
  41. package/dist/result.js.map +1 -1
  42. package/dist/schema.d.ts +13 -1
  43. package/dist/schema.js +20 -2
  44. package/dist/schema.js.map +1 -1
  45. package/dist/server.d.ts +1 -1
  46. package/dist/server.js +30 -5
  47. package/dist/server.js.map +1 -1
  48. package/dist/tools/annotations.d.ts +32 -0
  49. package/dist/tools/annotations.js +33 -0
  50. package/dist/tools/annotations.js.map +1 -0
  51. package/dist/tools/catalogue.d.ts +2 -2
  52. package/dist/tools/read.d.ts +1 -1
  53. package/dist/tools/read.js +743 -87
  54. package/dist/tools/read.js.map +1 -1
  55. package/dist/tools/write.d.ts +3 -3
  56. package/dist/tools/write.js +174 -39
  57. package/dist/tools/write.js.map +1 -1
  58. package/package.json +17 -11
  59. package/dist/approval.d.ts +0 -45
  60. package/dist/approval.js +0 -69
  61. package/dist/approval.js.map +0 -1
  62. package/dist/confirm.d.ts +0 -59
  63. package/dist/confirm.js +0 -92
  64. package/dist/confirm.js.map +0 -1
  65. package/dist/tool-filter.d.ts +0 -45
  66. package/dist/tool-filter.js +0 -171
  67. package/dist/tool-filter.js.map +0 -1
package/dist/config.js CHANGED
@@ -23,6 +23,18 @@ const DEFAULT_MAX_MESSAGES = 100;
23
23
  const DEFAULT_MAX_ATTACHMENT_BYTES = 1024 * 1024;
24
24
  /** Disk cap: this one protects the filesystem, which is a different concern. */
25
25
  const DEFAULT_MAX_DOWNLOAD_BYTES = 25 * 1024 * 1024;
26
+ /** Extraction cap: how much hostile input one parser is asked to chew on. */
27
+ const DEFAULT_MAX_EXTRACT_BYTES = 10 * 1024 * 1024;
28
+ /**
29
+ * Hard ceiling on `IMAP_MAX_EXTRACT_BYTES`.
30
+ *
31
+ * The other two size variables have no maximum because their cost is linear and
32
+ * paid somewhere visible — a big result, a big file. This one buys a buffer
33
+ * inside a parser working on bytes a stranger chose, so a typo of "104857600000"
34
+ * would not produce a big answer, it would produce an operator who believes
35
+ * there is a limit. 64 MiB is past any document that arrives by mail.
36
+ */
37
+ const MAX_MAX_EXTRACT_BYTES = 64 * 1024 * 1024;
26
38
  const DEFAULT_SEEN_KEYWORD = 'AiSeen';
27
39
  /** Shown when the configuration is incomplete — at startup and on every call. */
28
40
  export function missingConfigMessage(missing) {
@@ -60,6 +72,10 @@ export function loadConfig(env = process.env) {
60
72
  // to child processes and in /proc/<pid>/environ.
61
73
  delete env.IMAP_PASSWORD;
62
74
  const tls = parseTlsMode(env.IMAP_TLS);
75
+ // After the password delete, deliberately: this one can exit the process, and
76
+ // an exit above the delete would leave the password in the environment for
77
+ // whatever runs next.
78
+ const elicitation = parseElicitation(env.ELICITATION);
63
79
  if (host !== undefined)
64
80
  assertSafeHost(host, 'IMAP_HOST');
65
81
  const draftsMailbox = env.IMAP_DRAFTS_MAILBOX;
@@ -87,9 +103,11 @@ export function loadConfig(env = process.env) {
87
103
  allowedAttachmentTypes: parseTypes(env.IMAP_ATTACHMENT_TYPES),
88
104
  downloadDir: env.IMAP_DOWNLOAD_DIR,
89
105
  maxDownloadBytes: parseCount(env.IMAP_MAX_DOWNLOAD_BYTES, DEFAULT_MAX_DOWNLOAD_BYTES, 'IMAP_MAX_DOWNLOAD_BYTES'),
106
+ maxExtractBytes: parseCount(env.IMAP_MAX_EXTRACT_BYTES, DEFAULT_MAX_EXTRACT_BYTES, 'IMAP_MAX_EXTRACT_BYTES', MAX_MAX_EXTRACT_BYTES),
90
107
  },
91
108
  // Defaults to true, unlike the rest of the family — see the field comment.
92
109
  readOnly: env.IMAP_READ_ONLY !== 'false',
110
+ elicitation,
93
111
  allowTools: env.IMAP_ALLOW_TOOLS,
94
112
  denyTools: env.IMAP_DENY_TOOLS,
95
113
  };
@@ -122,6 +140,29 @@ function parseTlsMode(raw) {
122
140
  console.error('imap-mcp: IMAP_TLS must be one of implicit, starttls or none');
123
141
  process.exit(1);
124
142
  }
143
+ /**
144
+ * Reads `ELICITATION` — deliberately unprefixed, and deliberately fatal on
145
+ * anything it does not recognise.
146
+ *
147
+ * Unprefixed: environment variables are process-wide, so this is one switch for
148
+ * every server in the same environment. That is also its risk, which is why a
149
+ * server started with it off says so on its startup line.
150
+ *
151
+ * Fatal, like `parseTlsMode` above and unlike `IMAP_READ_ONLY`: this is the
152
+ * first variable of the family that defaults to *on*, so a typo that fell back
153
+ * to the default would leave the dialog running while the operator believes it
154
+ * is off — and an operator who believes that has no way to find out.
155
+ */
156
+ export function parseElicitation(raw) {
157
+ const value = raw?.trim().toLowerCase();
158
+ if (value === undefined || value === '' || value === 'true')
159
+ return true;
160
+ if (value === 'false')
161
+ return false;
162
+ console.error(`imap-mcp: ELICITATION must be "true" or "false" — got "${raw}". ` +
163
+ 'Refusing to start rather than guess.');
164
+ process.exit(1);
165
+ }
125
166
  function parsePort(raw, fallback, name) {
126
167
  if (raw === undefined || raw === '')
127
168
  return fallback;
@@ -133,7 +174,7 @@ function parsePort(raw, fallback, name) {
133
174
  }
134
175
  return value;
135
176
  }
136
- function parseCount(raw, fallback, name) {
177
+ function parseCount(raw, fallback, name, max) {
137
178
  if (raw === undefined || raw === '')
138
179
  return fallback;
139
180
  const value = Number(raw);
@@ -141,6 +182,13 @@ function parseCount(raw, fallback, name) {
141
182
  console.error(`imap-mcp: ${name} must be a positive integer`);
142
183
  process.exit(1);
143
184
  }
185
+ if (max !== undefined && value > max) {
186
+ // The limit is named rather than clamped to: an operator who asked for more
187
+ // than the server will do should learn that here, not from a refusal later
188
+ // that looks like the document was the problem.
189
+ console.error(`imap-mcp: ${name} must not exceed ${max}`);
190
+ process.exit(1);
191
+ }
144
192
  return value;
145
193
  }
146
194
  /**
@@ -191,12 +239,23 @@ function assertSingleLine(value, name) {
191
239
  }
192
240
  }
193
241
  function isLoopbackHost(hostname) {
242
+ // URL.hostname keeps the brackets around an IPv6 literal, may carry a %zone
243
+ // suffix, and 'localhost.' with its root label is the same name as
244
+ // 'localhost'. The comparison this replaced saw none of them — which is why
245
+ // its bare '::1' branch could never match a hostname taken from a URL.
194
246
  if (hostname === undefined)
195
247
  return false;
196
- return (hostname === 'localhost' ||
197
- hostname.endsWith('.localhost') ||
198
- hostname.startsWith('127.') ||
199
- hostname === '::1' ||
200
- hostname === '[::1]');
248
+ const host = hostname
249
+ .toLowerCase()
250
+ .replace(/^\[|]$/g, '')
251
+ .replace(/%.*$/, '')
252
+ .replace(/\.+$/, '');
253
+ return (host === 'localhost' ||
254
+ host.endsWith('.localhost') ||
255
+ host.startsWith('127.') ||
256
+ host === '::1' ||
257
+ // Every dual-stack client dials ::ffff:127.0.0.1 as plain 127.0.0.1, and
258
+ // URL normalises the mapped form to hex (::ffff:7f00:1).
259
+ /^::ffff:(?:7f[0-9a-f]{0,2}:|127\.)/.test(host));
201
260
  }
202
261
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,MAAM,OAAO,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,OAAO,SAAU,SAAQ,KAAK;IAGvB;IACA;IAHX,YACE,OAAe,EACN,OAA2B,SAAS,EACpC,eAAuB,EAAE;QAElC,KAAK,CAAC,OAAO,CAAC,CAAC;QAHN,SAAI,GAAJ,IAAI,CAAgC;QACpC,iBAAY,GAAZ,YAAY,CAAa;QAGlC,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,MAAM,OAAO,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,OAAO,SAAU,SAAQ,KAAK;IAGvB,IAAI;IACJ,YAAY;IAHvB,YACE,OAAe,EACN,IAAI,GAAuB,SAAS,EACpC,YAAY,GAAW,EAAE;QAElC,KAAK,CAAC,OAAO,CAAC,CAAC;oBAHN,IAAI;4BACJ,YAAY;QAGrB,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,83 @@
1
+ /**
2
+ * The extraction child: the only code in this server that parses a binary a
3
+ * stranger sent, and the reason it runs in a process of its own.
4
+ *
5
+ * A process rather than a worker thread, and that was a lesson rather than a
6
+ * preference. A worker's `resourceLimits` promise to turn a runaway parse into
7
+ * `ERR_WORKER_OUT_OF_MEMORY`, and for most allocation patterns they do; for
8
+ * the one a 3 kB spreadsheet produced they did not, and the whole server died
9
+ * with `FATAL ERROR: Reached heap limit`. A thread also cannot give back the
10
+ * memory a terminated parse left behind — a gigabyte stayed resident after
11
+ * `terminate()`. A process that is killed takes its memory with it, whatever
12
+ * it was doing, and a process that aborts aborts alone.
13
+ *
14
+ * Read the import rules before editing this file. It is started from its own
15
+ * source — `child.ts` under vitest, which Node runs with type stripping, and
16
+ * `child.js` from `dist/` in production — so Node loads it and everything it
17
+ * reaches, without vitest's resolver. Node strips types; it does not rewrite a
18
+ * `./x.js` specifier to the `./x.ts` sitting beside it. So:
19
+ *
20
+ * - static imports here may only be bare specifiers (`node:*`, a package) or
21
+ * `import type`, which is erased before it can fail to resolve;
22
+ * - anything relative is loaded through {@link sibling}, which picks the
23
+ * extension from this module's own;
24
+ * - no enums, no namespaces, no parameter properties — type stripping cannot
25
+ * erase syntax that emits code.
26
+ *
27
+ * Get this wrong in one direction and every test fails while the build stays
28
+ * green; get it wrong in the other and every test passes while the published
29
+ * package throws on first use. The second is why `npm run build` is followed by
30
+ * a real extraction against `dist/`.
31
+ */
32
+ const EXTENSION = import.meta.url.endsWith('.ts') ? 'ts' : 'js';
33
+ function sibling(path) {
34
+ return new URL(`${path}.${EXTENSION}`, import.meta.url).href;
35
+ }
36
+ async function run(request) {
37
+ if (request.kind === 'pdf') {
38
+ const { extractPdf } = (await import(sibling('./pdf')));
39
+ return extractPdf(request.bytes, request.maxChars);
40
+ }
41
+ const [{ extractZipDocument }, { htmlToText }] = await Promise.all([
42
+ import(sibling('./ooxml')),
43
+ import(sibling('../analyze')),
44
+ ]);
45
+ return extractZipDocument(request.kind, request.bytes, request.maxChars, htmlToText);
46
+ }
47
+ /** A code for the log, never a message: the message quotes the document. */
48
+ function codeOf(error) {
49
+ const value = error;
50
+ if (typeof value?.code === 'string')
51
+ return value.code;
52
+ if (typeof value?.name === 'string')
53
+ return value.name;
54
+ return 'unknown';
55
+ }
56
+ const send = process.send?.bind(process);
57
+ if (send !== undefined) {
58
+ // The parent is gone: nothing is waiting for an answer, and a parse that
59
+ // outlives the server it was started by is a parse nobody asked for.
60
+ process.on('disconnect', () => {
61
+ process.exit(0);
62
+ });
63
+ process.once('message', (request) => {
64
+ run(request).then((response) => {
65
+ send(response, () => {
66
+ process.exit(0);
67
+ });
68
+ }, (error) => {
69
+ // Never the caught error. pdf.js and fflate quote the document in
70
+ // their exception messages — byte offsets, object fragments, what they
71
+ // found where they expected something else. That is text a stranger
72
+ // wrote, and an error message is read as the server's own voice,
73
+ // outside the fence every other piece of message content passes
74
+ // through. A code crosses; the words are the host's.
75
+ console.error(`imap-mcp: extraction failed: ${codeOf(error)}`);
76
+ send({ ok: false, reason: 'internal' }, () => {
77
+ process.exit(0);
78
+ });
79
+ });
80
+ });
81
+ }
82
+ export {};
83
+ //# sourceMappingURL=child.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"child.js","sourceRoot":"","sources":["../../src/extract/child.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAEhE,SAAS,OAAO,CAAC,IAAY;IAC3B,OAAO,IAAI,GAAG,CAAC,GAAG,IAAI,IAAI,SAAS,EAAE,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;AAC/D,CAAC;AAED,KAAK,UAAU,GAAG,CAAC,OAAuB;IACxC,IAAI,OAAO,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QAC3B,MAAM,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,MAAM,CAClC,OAAO,CAAC,OAAO,CAAC,CACjB,CAA8B,CAAC;QAChC,OAAO,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrD,CAAC;IACD,MAAM,CAAC,EAAE,kBAAkB,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACjE,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAyC;QAClE,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAA4C;KACzE,CAAC,CAAC;IACH,OAAO,kBAAkB,CACvB,OAAO,CAAC,IAAI,EACZ,OAAO,CAAC,KAAK,EACb,OAAO,CAAC,QAAQ,EAChB,UAAU,CACX,CAAC;AACJ,CAAC;AAED,4EAA4E;AAC5E,SAAS,MAAM,CAAC,KAAc;IAC5B,MAAM,KAAK,GAAG,KAAkD,CAAC;IACjE,IAAI,OAAO,KAAK,EAAE,IAAI,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC;IACvD,IAAI,OAAO,KAAK,EAAE,IAAI,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC;IACvD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;AACzC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;IACvB,yEAAyE;IACzE,qEAAqE;IACrE,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,GAAG,EAAE;QAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,OAAuB,EAAE,EAAE;QAClD,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CACf,CAAC,QAAQ,EAAE,EAAE;YACX,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE;gBAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC,CAAC,CAAC;QACL,CAAC,EACD,CAAC,KAAc,EAAE,EAAE;YACjB,kEAAkE;YAClE,uEAAuE;YACvE,oEAAoE;YACpE,iEAAiE;YACjE,gEAAgE;YAChE,qDAAqD;YACrD,OAAO,CAAC,KAAK,CAAC,gCAAgC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC/D,IAAI,CACF,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAA4B,EAC3D,GAAG,EAAE;gBACH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC,CACF,CAAC;QACJ,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,41 @@
1
+ import type { ExtractKind, ExtractRequest, ExtractResponse } from './types.js';
2
+ export type { ExtractKind, ExtractReason, ExtractRequest, ExtractResponse, } from './types.js';
3
+ /**
4
+ * How long a document may be parsed before the process doing it is killed.
5
+ *
6
+ * Generous next to the five seconds a regular expression gets in the sibling
7
+ * servers, because a hundred-page PDF is honest work — and finite, because a
8
+ * document that has not finished by now is not going to.
9
+ */
10
+ export declare const EXTRACT_TIMEOUT_MS = 20000;
11
+ /**
12
+ * Characters the child may return, before any of the paging below.
13
+ *
14
+ * Not a context budget — that is `max_chars` at the tool, and it is much
15
+ * smaller. This is the ceiling on what is held in memory and paged through,
16
+ * and the child enforces it for every format: nothing larger is ever built
17
+ * there, let alone sent back.
18
+ */
19
+ export declare const MAX_EXTRACT_CHARS = 1000000;
20
+ /** The same set as content types, for `get_server_info`. */
21
+ export declare const EXTRACTABLE_TYPES: string[];
22
+ /** Prose for the refusals, so every one of them names the same set. */
23
+ export declare const EXTRACTABLE_TYPE_NAMES: string;
24
+ export declare function extractKindOf(contentType: string): ExtractKind | undefined;
25
+ export declare function isExtractable(contentType: string): boolean;
26
+ /** The magic-byte verdict an honest container of this kind produces. */
27
+ export declare function expectedSignature(kind: ExtractKind): string;
28
+ export declare function extractDocumentText(request: ExtractRequest, limits?: ChildLimits): Promise<ExtractResponse>;
29
+ /**
30
+ * Narrowed by the tests, never by the server.
31
+ *
32
+ * The timeout and the memory ceiling are the two guards whose whole purpose is
33
+ * what happens when they fire, and neither can be reached in a test at its real
34
+ * value without a document engineered to spend twenty seconds or a quarter of a
35
+ * gigabyte. Making them arguments is what lets the failure paths be exercised
36
+ * in milliseconds; nothing in `src/` passes them.
37
+ */
38
+ export interface ChildLimits {
39
+ timeoutMs?: number;
40
+ memoryMb?: number;
41
+ }
@@ -0,0 +1,183 @@
1
+ import { fork } from 'node:child_process';
2
+ import { once } from 'node:events';
3
+ /**
4
+ * How long a document may be parsed before the process doing it is killed.
5
+ *
6
+ * Generous next to the five seconds a regular expression gets in the sibling
7
+ * servers, because a hundred-page PDF is honest work — and finite, because a
8
+ * document that has not finished by now is not going to.
9
+ */
10
+ export const EXTRACT_TIMEOUT_MS = 20_000;
11
+ /**
12
+ * Characters the child may return, before any of the paging below.
13
+ *
14
+ * Not a context budget — that is `max_chars` at the tool, and it is much
15
+ * smaller. This is the ceiling on what is held in memory and paged through,
16
+ * and the child enforces it for every format: nothing larger is ever built
17
+ * there, let alone sent back.
18
+ */
19
+ export const MAX_EXTRACT_CHARS = 1_000_000;
20
+ /**
21
+ * V8 heap the parsing process may use.
22
+ *
23
+ * Best effort, and named as such. It bounds a pathological object graph, and
24
+ * when it fires the child aborts — on its own, which is the whole reason the
25
+ * parse is in a process. It does not bound typed arrays, which are external
26
+ * memory; the deflate pre-scan in `pdf.ts` and the entry caps in `ooxml.ts`
27
+ * are what cover those.
28
+ */
29
+ const CHILD_MEMORY_MB = 256;
30
+ /**
31
+ * Requests admitted at once, running and waiting together.
32
+ *
33
+ * Extractions run one at a time (see {@link queue}), so a request that arrives
34
+ * behind seven others would wait up to seven timeouts for its turn, holding
35
+ * its mailbox lock throughout. Past this many it is refused outright, which is
36
+ * an answer the caller can act on.
37
+ */
38
+ const MAX_IN_FLIGHT = 8;
39
+ /** Content types this server can read text out of, and what each one is. */
40
+ const EXTRACTABLE = new Map([
41
+ ['application/pdf', 'pdf'],
42
+ [
43
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
44
+ 'docx',
45
+ ],
46
+ ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xlsx'],
47
+ [
48
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
49
+ 'pptx',
50
+ ],
51
+ ['application/vnd.oasis.opendocument.text', 'odt'],
52
+ ['application/vnd.oasis.opendocument.spreadsheet', 'ods'],
53
+ ]);
54
+ /** The same set as content types, for `get_server_info`. */
55
+ export const EXTRACTABLE_TYPES = [...EXTRACTABLE.keys()];
56
+ /** Prose for the refusals, so every one of them names the same set. */
57
+ export const EXTRACTABLE_TYPE_NAMES = 'PDF, Word (.docx), Excel (.xlsx), PowerPoint (.pptx) and OpenDocument text ' +
58
+ 'and spreadsheets (.odt, .ods)';
59
+ export function extractKindOf(contentType) {
60
+ return EXTRACTABLE.get(contentType.toLowerCase());
61
+ }
62
+ export function isExtractable(contentType) {
63
+ return EXTRACTABLE.has(contentType.toLowerCase());
64
+ }
65
+ /** The magic-byte verdict an honest container of this kind produces. */
66
+ export function expectedSignature(kind) {
67
+ // Every OOXML and OpenDocument file is a zip, which is why `sniffContent`
68
+ // reports one for all five of them.
69
+ return kind === 'pdf' ? 'application/pdf' : 'application/zip';
70
+ }
71
+ /**
72
+ * Serialises extractions.
73
+ *
74
+ * One process per call and no limit would mean N concurrent tool calls holding
75
+ * N processes of {@link CHILD_MEMORY_MB} each, which is a memory limit that
76
+ * multiplies by a number the caller chooses. The queue is the whole mechanism:
77
+ * the next extraction starts when the previous process is gone.
78
+ */
79
+ let queue = Promise.resolve();
80
+ let inFlight = 0;
81
+ export async function extractDocumentText(request, limits = {}) {
82
+ if (inFlight >= MAX_IN_FLIGHT)
83
+ return { ok: false, reason: 'busy' };
84
+ inFlight += 1;
85
+ try {
86
+ const run = queue.then(() => runInChild(request, limits), () => runInChild(request, limits));
87
+ queue = run.catch(() => undefined);
88
+ return await run;
89
+ }
90
+ finally {
91
+ inFlight -= 1;
92
+ }
93
+ }
94
+ /** A code for the log, never a message. */
95
+ function codeOf(error) {
96
+ const value = error;
97
+ if (typeof value?.code === 'string')
98
+ return value.code;
99
+ if (typeof value?.name === 'string')
100
+ return value.name;
101
+ return 'unknown';
102
+ }
103
+ async function runInChild(request, limits = {}) {
104
+ const timeoutMs = limits.timeoutMs ?? EXTRACT_TIMEOUT_MS;
105
+ const memoryMb = limits.memoryMb ?? CHILD_MEMORY_MB;
106
+ const child = fork(new URL(import.meta.url.endsWith('.ts') ? './child.ts' : './child.js', import.meta.url), [], {
107
+ // Stated rather than inherited. The parent's own flags may be ones a
108
+ // child cannot take — `--input-type` is one — and an inherited flag that
109
+ // fails to parse would turn every extraction into a silent `internal`.
110
+ execArgv: [`--max-old-space-size=${memoryMb}`],
111
+ // Not tidiness — correctness. The parent's stdout is this server's
112
+ // JSON-RPC transport, and pdf.js logs. One line from inside the parser
113
+ // would corrupt the framing and hang the session. Discarded; stderr is
114
+ // shared, because that is where every other diagnostic in this server
115
+ // already goes.
116
+ stdio: ['ignore', 'ignore', 'inherit', 'ipc'],
117
+ // Structured clone rather than JSON: the request carries the document as
118
+ // a typed array, and JSON would turn it into an array of numbers ten
119
+ // times its size.
120
+ serialization: 'advanced',
121
+ });
122
+ let timer;
123
+ try {
124
+ return await new Promise((resolve) => {
125
+ // The first answer wins. Everything after it — the exit of a child that
126
+ // was killed because it had already answered, most of all — is silence,
127
+ // not a second verdict.
128
+ let settled = false;
129
+ const settle = (value) => {
130
+ if (settled)
131
+ return;
132
+ settled = true;
133
+ resolve(value);
134
+ };
135
+ timer = setTimeout(() => {
136
+ settle({ ok: false, reason: 'timeout' });
137
+ }, timeoutMs);
138
+ child.once('message', (value) => {
139
+ settle(value);
140
+ });
141
+ child.once('error', (error) => {
142
+ if (settled)
143
+ return;
144
+ console.error(`imap-mcp: extraction process failed: ${codeOf(error)}`);
145
+ settle({ ok: false, reason: 'internal' });
146
+ });
147
+ child.once('exit', (code, signal) => {
148
+ // Only reached when the child left without answering. An abort is what
149
+ // V8 does when the heap limit is hit — and what the process does
150
+ // *instead of* taking the server with it, which is the property being
151
+ // bought here.
152
+ if (settled)
153
+ return;
154
+ if (signal === 'SIGABRT' || code === 134) {
155
+ settle({ ok: false, reason: 'out-of-memory' });
156
+ return;
157
+ }
158
+ console.error(`imap-mcp: extraction process exited early: ${signal ?? `code ${code}`}`);
159
+ settle({ ok: false, reason: 'internal' });
160
+ });
161
+ try {
162
+ child.send(request);
163
+ }
164
+ catch (error) {
165
+ console.error(`imap-mcp: extraction request failed: ${codeOf(error)}`);
166
+ settle({ ok: false, reason: 'internal' });
167
+ }
168
+ });
169
+ }
170
+ finally {
171
+ if (timer)
172
+ clearTimeout(timer);
173
+ // Unconditional: on the timeout path the process is still inside the parse
174
+ // and will never exit on its own. SIGKILL, because a parser stuck in native
175
+ // code does not check for anything gentler — and because a process, unlike
176
+ // a thread, can be killed from outside whatever it is doing.
177
+ if (child.exitCode === null && child.signalCode === null) {
178
+ child.kill('SIGKILL');
179
+ await once(child, 'exit');
180
+ }
181
+ }
182
+ }
183
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/extract/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { ExtractKind, ExtractResponse } from './types.js';
2
+ /**
3
+ * Turns markup into readable text. Injected rather than imported.
4
+ *
5
+ * `htmlToText` lives in `../analyze.ts`, and this module is reached from the
6
+ * extraction child, which Node loads directly — where a `../analyze.js`
7
+ * specifier does not resolve to the `.ts` beside it. Passing the function in
8
+ * keeps this file free of relative value imports, which is the property that
9
+ * lets it run in the child at all. It also makes the seam explicit: the tests
10
+ * hand it the same `htmlToText` the child does.
11
+ */
12
+ export type MarkupToText = (markup: string, maxChars: number) => string;
13
+ /**
14
+ * Reads the text of an OOXML or OpenDocument container.
15
+ *
16
+ * The whole defence lives in the `filter` callback below, and it is worth
17
+ * saying why that specific place. `unzipSync` inflates an entry into a buffer
18
+ * sized by the *declared* uncompressed size out of the central directory — a
19
+ * number the sender chose, checked against nothing. The filter is the last
20
+ * point before that allocation, and returning `false` there means the entry is
21
+ * never inflated and never sized.
22
+ *
23
+ * Measured on fflate 0.8.3: a declared size far past the real one does not blow
24
+ * up resident memory on Linux, because the allocation is virtual and untouched
25
+ * pages cost nothing; and a declared size *below* the real one truncates the
26
+ * output to what was declared, because fflate does not grow a caller-sized
27
+ * buffer. The guard stays regardless — it is free, it is the only thing
28
+ * standing between an *honest* high-ratio entry and its real expansion, and a
29
+ * host that does not overcommit would pay the full price.
30
+ *
31
+ * This never recurses. An entry that is itself an archive is not in the name
32
+ * allowlist, so a nested bomb is not descended into; that is a property to keep
33
+ * rather than an omission to fix.
34
+ */
35
+ export declare function extractZipDocument(kind: Exclude<ExtractKind, 'pdf'>, bytes: Uint8Array, maxChars: number, toText: MarkupToText): Promise<ExtractResponse>;