@juvantlabs/m365-graph-mcp-server 0.4.3 → 0.5.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/ARCHITECTURE.md CHANGED
@@ -208,7 +208,7 @@ Each row is also reflected in [`README.md`](README.md) § Tools.
208
208
  | `m365-graph:list_drives` | `GET /me/drive`, `GET /me/drives` | _(none)_ | `{ primary, accessible: [] }` | `Files.Read` | First-ship; validates the auth + Graph plumbing end-to-end. |
209
209
  | `m365-graph:list_items` | `GET /me/drive/root/children` or `GET /drives/{id}/items/{item}/children` | `drive_id?`, `item_id?`, `limit?` (1–100, default 50) | `{ count, items: [] }` | `Files.Read` | Item type derived from presence of `folder` facet. `child_count` populated only for folders. |
210
210
  | `m365-graph:search_files` | `GET /drives/{id}/root/search(q='…')` (defaults to `/me/drive`) | `query`, `drive_id?`, `limit?` (1–50, default 20) | `{ count, results: [] }` with virtual `path` joining `parentReference.path` + `name` | `Files.Read` | OData function call; query single quotes are escaped (`'` → `''`). |
211
- | `m365-graph:download_file` | `GET /me/drive/items/{id}` for metadata, then `GET @microsoft.graph.downloadUrl` (Graph CDN) for the bytes | `item_id`, `drive_id?` | `{ local_path, size_bytes, name, content_type }` | `Files.Read` | **Sandboxed**: writes only under `<sandbox>/<tenant>/<sha256(item_id)[:16]>-<sanitized name>`. Streamed via fetch + Node `pipeline`; no whole-file buffering. 200 MB cap, refused pre-fetch via metadata size. Folders rejected. |
211
+ | `m365-graph:download_file` | `GET /me/drive/items/{id}` for metadata, then `GET @microsoft.graph.downloadUrl` (Graph CDN) for the bytes. With `format`: `GET {drive}/items/{id}/content?format=pdf` → 302 → `GET <Location>` | `item_id`, `drive_id?`, `format?` (`pdf`) | `{ local_path, size_bytes, name, content_type, format }` (`format` is `"pdf"` when converted, `null` for a plain download; + `source_size_bytes`, `source_content_type` when converting) | `Files.Read` | **Sandboxed**: writes only under `<sandbox>/<tenant>/<sha256(item_id)[:16]>-<sanitized name>`. Streamed via fetch + Node `pipeline`; no whole-file buffering. 200 MB cap, refused pre-fetch via metadata size. Folders rejected. **Server-side conversion** (see § Download sandboxing): strict `format` enum, pre-flight source-type allowlist, redirect followed by the tool without the bearer token, 200 MB cap re-enforced on the converted stream. |
212
212
  | `m365-graph:list_calendars` | `GET /me/calendars` | `limit?` (1–100, default 50) | `{ count, calendars: [] }` | `Calendars.Read` | Owner extracted from `owner.{name,address}`; falls back to null. |
213
213
  | `m365-graph:list_events` | `GET /me/calendarView` (or `/me/calendars/{id}/calendarView`) with `startDateTime` + `endDateTime` query params | `start`, `end` (ISO 8601), `calendar_id?`, `limit?` (1–200, default 100) | `{ window, count, events: [] }` | `Calendars.Read` | **Recurrences expanded** (calendarView vs /events). Ordered by `start/dateTime` ascending. ISO 8601 input lightly validated client-side (regex), Graph does the strict parse. |
214
214
  | `m365-graph:search_events` | `GET /me/events?$filter=contains(subject, '…')` | `query`, `limit?` (1–50, default 20) | `{ count, results: [] }` | `Calendars.Read` | Subject-only substring match. `$search` is not supported on the Events resource by Graph; body search would require POST `/search/query` (separate API, deferred). Single-quote escaping (`'` → `''`) on the query. **Series masters**, not expanded occurrences. |
@@ -270,6 +270,51 @@ sandbox root before writing.
270
270
  Mode: dirs `0o700`, files `0o600` so other users on a shared host
271
271
  can't read downloaded content.
272
272
 
273
+ The same item always maps to the same local path; a repeat download
274
+ overwrites the previous copy.
275
+
276
+ #### Server-side format conversion
277
+
278
+ `download_file` accepts an optional `format` (strict enum; today only
279
+ `pdf`). Conversion happens entirely in Microsoft Graph — the server runs
280
+ no converter and never executes anything on the file:
281
+
282
+ 1. **Validation.** `format` must be exactly one of the enum values; the
283
+ query string is built from the server-side constant, never from the
284
+ raw caller string. The source name's extension is checked against the
285
+ types Graph documents as PDF-convertible (`doc`, `docx`, `dot`,
286
+ `dotx`, `dotm`, `dsn`, `dwg`, `eml`, `epub`, `fluidframework`, `htm`,
287
+ `html`, `loop`, `markdown`, `md`, `msg`, `odp`, `ods`, `odt`, `pps`,
288
+ `ppsx`, `ppt`, `pptx`, `rtf`, `tif`, `tiff`, `xls`, `xlsm`, `xlsx`).
289
+ Anything else — including a file that is already a PDF — fails
290
+ before the conversion request with an error naming the supported
291
+ types.
292
+ 2. **Request.** `GET {drive}/items/{id}/content?format=pdf` with the
293
+ SDK's automatic redirect-following disabled.
294
+ 3. **Redirect.** Graph answers `302` with a pre-authenticated `Location`.
295
+ The tool requires an absolute `https` URL and fetches it **without**
296
+ the bearer token — the same trust model as
297
+ `@microsoft.graph.downloadUrl`. A direct `200` with the body is also
298
+ accepted. Graph `406`/`415`/`notSupported` responses, including a
299
+ `400` with the `notSupported` code, are reported as a conversion
300
+ failure naming the source extension (the file may be encrypted,
301
+ corrupt, or not convertible). Any other `400` also names the extension
302
+ but does not claim the source type is the cause, because the status
303
+ alone cannot establish that. Other statuses surface with their Graph
304
+ error code. A refused conversion never falls back to the original
305
+ bytes.
306
+ 4. **Write.** The 200 MB source cap applies pre-flight as usual; since
307
+ the converted size is unknown in advance, the cap is re-enforced on
308
+ the stream (`Content-Length` when present, plus a byte counter). A
309
+ capped or failed transfer leaves no partial file.
310
+ 5. **Naming.** `<sha256(item_id)[:16]>-<stem>.pdf` — the original
311
+ extension is replaced, so the converted copy never collides with a
312
+ plain download of the same item, and the stem is trimmed so the
313
+ 200-character filename cap cannot cut the `.pdf` extension.
314
+
315
+ No additional Graph scope is required: conversion is a read on the same
316
+ item (`Files.Read` / `Sites.Read.All` or broader for SharePoint drives).
317
+
273
318
  ## Input validation
274
319
 
275
320
  Every tool validates its inputs via helpers in
package/CHANGELOG.md CHANGED
@@ -11,6 +11,59 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [0.5.0] - unreleased — server-side PDF conversion in `download_file`
15
+
16
+ ### Added — Files
17
+
18
+ - **`m365-graph:download_file` — optional `format` parameter
19
+ (`"pdf"`).** When set, the tool asks Microsoft Graph to convert the
20
+ file server-side via `GET {drive}/items/{id}/content?format=pdf` and
21
+ saves the resulting PDF to the sandbox instead of the original bytes.
22
+ This lets agents read Word / Excel / PowerPoint / OpenDocument / RTF /
23
+ HTML / Markdown / email / TIFF documents through a plain PDF reader
24
+ with no local converter (no subprocess, no new executable surface).
25
+ - `format` is a strict enum; the query value is a server-side
26
+ constant, never the raw caller string.
27
+ - Source type is checked pre-flight against the extensions Graph
28
+ documents as PDF-convertible. Unsupported types (and files that are
29
+ already PDFs) fail fast with an error listing the supported types.
30
+ Graph-side conversion failures (`406` / `415` / `notSupported`,
31
+ including a `400` with that code) are reported as such and name the
32
+ source extension. Any other `400` also names the extension but does
33
+ not claim the source type is the cause. Other Graph errors surface
34
+ with status and code. A refused conversion never falls back to the
35
+ original bytes.
36
+ - Graph's `302` to the converted content is handled explicitly: the
37
+ SDK's redirect-following is disabled for this call, the `Location`
38
+ must be an absolute `https` URL, and it is fetched without the
39
+ bearer token (same trust model as `@microsoft.graph.downloadUrl`).
40
+ - Same sandbox (`0700` dir / `0600` file, per-tenant root), same
41
+ naming and overwrite policy: `<sha256(item_id)[:16]>-<stem>.pdf`.
42
+ The 200 MB cap applies to the source pre-flight and is re-enforced
43
+ on the converted stream; a capped or failed transfer leaves no
44
+ partial file.
45
+ - The output always includes `format`: `"pdf"` when converted, `null`
46
+ for a plain download. Additive output fields when converting:
47
+ `source_size_bytes`, `source_content_type`; `content_type` is
48
+ `application/pdf` and `size_bytes` is the size of the PDF on disk.
49
+ - No new Graph scope.
50
+ - **Validators**: `validateOptionalStrictEnum` (optional enum with no
51
+ default) and `validateHttpsUrl` in `src/types/validators.ts`.
52
+
53
+ ### Fixed — Calendar
54
+
55
+ - **`m365-graph:list_events`: positive UTC offsets no longer fail.**
56
+ `start` / `end` such as `2026-11-04T00:00:00+01:00` were rejected by
57
+ Graph (`The value '2026-11-04T00:00:00 01:00' of parameter
58
+ 'StartDateTime' is invalid`). The Graph SDK does not URL-encode query
59
+ values, so the `+` was sent literally and decoded as a space. Values
60
+ are now percent-encoded; `window` in the result still echoes the
61
+ caller's input ([#18](https://github.com/juvantlabs/m365-graph-mcp-server/issues/18)).
62
+ - **`m365-graph:search_events`: search terms containing `+`, `&` or `#`
63
+ are now matched as written.** Same cause: `+` searched for a space,
64
+ `&` split `$filter` into a stray query parameter, and `#` cut off the
65
+ rest of the query string ([#18](https://github.com/juvantlabs/m365-graph-mcp-server/issues/18)).
66
+
14
67
  ## [0.4.3] - unreleased — publish-workflow fix; first npm release of the 0.4.2 content
15
68
 
16
69
  Ships everything listed under `[0.4.2]` below (that version was tagged
@@ -576,7 +629,8 @@ the Juvant OS instance level — see juvant-os-pm FEAT-018 / 019 /
576
629
 
577
630
  ---
578
631
 
579
- [Unreleased]: https://github.com/juvantlabs/m365-graph-mcp-server/compare/v0.4.3...HEAD
632
+ [Unreleased]: https://github.com/juvantlabs/m365-graph-mcp-server/compare/v0.5.0...HEAD
633
+ [0.5.0]: https://github.com/juvantlabs/m365-graph-mcp-server/compare/v0.4.3...v0.5.0
580
634
  [0.4.3]: https://github.com/juvantlabs/m365-graph-mcp-server/compare/v0.4.2...v0.4.3
581
635
  [0.4.2]: https://github.com/juvantlabs/m365-graph-mcp-server/compare/v0.4.1...v0.4.2
582
636
  [0.4.1]: https://github.com/juvantlabs/m365-graph-mcp-server/compare/v0.4.0...v0.4.1
package/README.md CHANGED
@@ -119,7 +119,7 @@ Step 8.5 cross-check semantics.
119
119
  | `m365-graph:list_drives` | Lists the drives the user has access to (primary OneDrive + shared document libraries). | _(none)_ | `{ primary, accessible: [] }` with id / driveType / name / webUrl / owner. | `Files.Read` |
120
120
  | `m365-graph:list_items` | Lists immediate children (files + folders) of a folder. Defaults to the drive root. | `drive_id?`, `item_id?`, `limit?` (1–100, default 50) | `{ count, items: [] }` with id / name / type / size / child_count / lastModified / webUrl. | `Files.Read` |
121
121
  | `m365-graph:search_files` | Searches files by name and content within a drive. | `query` (required), `drive_id?`, `limit?` (1–50, default 20) | `{ count, results: [] }` with id / name / path / size / is_folder / lastModified / webUrl. | `Files.Read` |
122
- | `m365-graph:download_file` | Downloads a file to a per-tenant local sandbox. Returns the local path; agent reads via a filesystem-aware tool. Streams, capped at 200 MB. | `item_id` (required), `drive_id?` | `{ local_path, size_bytes, name, content_type }` | `Files.Read` |
122
+ | `m365-graph:download_file` | Downloads a file to a per-tenant local sandbox. Returns the local path; agent reads via a filesystem-aware tool. Streams, capped at 200 MB. With `format: "pdf"`, Microsoft Graph converts the file to PDF server-side (no local converter) and the PDF is saved as `<name>.pdf` in the same sandbox; unsupported source types are rejected with an error listing the supported ones. | `item_id` (required), `drive_id?`, `format?` (`pdf`) | `{ local_path, size_bytes, name, content_type, format }`, where `format` is `"pdf"` when converted (`content_type` is then `application/pdf`) and `null` for a plain download; when converted also `source_size_bytes`, `source_content_type` | `Files.Read` |
123
123
  | `m365-graph:list_calendars` | Lists the user's calendars (primary + group / shared). | `limit?` (1–100, default 50) | `{ count, calendars: [] }` with id / name / color / owner_name / owner_email / is_default / can_edit / can_share. | `Calendars.Read` |
124
124
  | `m365-graph:list_events` | Lists events in a date window. Recurrences are expanded — each occurrence is its own event. | `start` + `end` (ISO 8601, required), `calendar_id?`, `limit?` (1–200, default 100) | `{ calendar_id, window, count, events: [] }` with id / subject / body_preview / start / end / is_all_day / is_online_meeting / location / organizer_name / organizer_email / attendees / webLink. | `Calendars.Read` |
125
125
  | `m365-graph:search_events` | Searches events by subject substring (Graph $search isn't supported on Events; subject-only via `contains()`). Returns recurrence series masters, not occurrences. | `query` (required), `limit?` (1–50, default 20) | `{ count, results: [] }` (same event shape). | `Calendars.Read` |
@@ -23,6 +23,8 @@
23
23
  * - 0o700 dir mode + 0o600 file mode (defense-in-depth on shared hosts).
24
24
  * - Resolved path is verified to start with the sandbox root before
25
25
  * writing — an extra check on top of the structurally-safe naming.
26
+ * - Same item → same local path; a repeat download overwrites the
27
+ * previous copy (deterministic, no accumulation).
26
28
  *
27
29
  * Size cap: 200 MB (handbook spec § Performance characteristics). Item
28
30
  * size is fetched via `/items/{id}` metadata BEFORE downloading; the
@@ -33,11 +35,74 @@
33
35
  * auth needed for the bytes themselves). Streamed via fetch + Node
34
36
  * streams pipeline (no whole-file buffering — handbook anti-pattern #11).
35
37
  *
36
- * Required Graph scope: `Files.Read` (delegated). Read-only on the
37
- * cloud side; writes only to the sandbox locally.
38
+ * Server-side format conversion (`format`, optional):
39
+ * - `format: "pdf"` asks Graph to convert the file server-side via
40
+ * `GET {drive}/items/{id}/content?format=pdf`. No local converter
41
+ * runs — the server never executes anything on the file.
42
+ * - `format` is a strict enum (`DOWNLOAD_FORMATS`); the query value
43
+ * is always the server-side constant, never the raw caller string.
44
+ * - Source type is checked pre-flight against the extensions Graph
45
+ * documents as PDF-convertible; unsupported types fail fast with a
46
+ * clear error and no network call beyond the metadata GET.
47
+ * - Graph answers with a 302 to a pre-authenticated URL for the
48
+ * converted bytes. The SDK's automatic redirect-following is
49
+ * disabled for this request: we read `Location` ourselves, require
50
+ * https, and fetch it WITHOUT the bearer token (same trust model as
51
+ * `@microsoft.graph.downloadUrl`).
52
+ * - A Graph refusal never falls back to the original bytes. 406, 415
53
+ * and a `notSupported` code name the source extension as a conversion
54
+ * failure. Any other 400 also names it, but does not claim the source
55
+ * type is the cause, because the status alone cannot establish that.
56
+ * - The converted size is not known in advance, so the 200 MB cap is
57
+ * also enforced on the stream (Content-Length when present, plus a
58
+ * byte counter). A capped or failed conversion leaves no partial
59
+ * file behind.
60
+ * - Local filename: `<sha256(item_id)[:16]>-<stem>.pdf` — same
61
+ * sandbox, same naming and overwrite policy as plain downloads.
62
+ *
63
+ * Required Graph scope: `Files.Read` (delegated; `Sites.Read(Write).All`
64
+ * for SharePoint drives). Read-only on the cloud side; writes only to
65
+ * the sandbox locally. Conversion needs no additional scope.
38
66
  */
67
+ import { Transform } from "node:stream";
39
68
  import type { Tool } from "../types/tool.js";
69
+ /** Server-side conversion targets accepted by the `format` parameter. */
70
+ export declare const DOWNLOAD_FORMATS: readonly ["pdf"];
71
+ export type DownloadFormat = (typeof DOWNLOAD_FORMATS)[number];
72
+ /**
73
+ * Source extensions Microsoft Graph documents as convertible with
74
+ * `?format=pdf` ("Download a file in another format").
75
+ */
76
+ export declare const PDF_CONVERTIBLE_EXTENSIONS: ReadonlySet<string>;
40
77
  export declare function getSandboxRoot(tenantId: string): string;
41
78
  export declare function deriveSafeLocalPath(sandboxRoot: string, itemId: string, originalName: string): string;
79
+ /**
80
+ * Lower-cased extension without the dot, or null when the name has
81
+ * none. A leading dot alone (".profile") is not an extension.
82
+ */
83
+ export declare function fileExtension(name: string): string | null;
84
+ /**
85
+ * Throw a caller-actionable error when Graph cannot convert this source
86
+ * type to the requested format. Returns the validated source extension.
87
+ */
88
+ export declare function checkConvertible(name: string, format: DownloadFormat): string;
89
+ /**
90
+ * Graph path for the converted content of an item. The `format` value
91
+ * comes from the enum constant, never from raw caller input.
92
+ */
93
+ export declare function buildConvertedContentPath(driveRoot: string, itemId: string, format: DownloadFormat): string;
94
+ /**
95
+ * Local name for a converted file: original stem + `.<format>`. The stem
96
+ * is trimmed so the sanitizer's length cap can never cut the extension.
97
+ */
98
+ export declare function convertedFilename(originalName: string, format: DownloadFormat): string;
99
+ /**
100
+ * Byte-counting pass-through that errors once `limit` is exceeded.
101
+ * `bytes()` reports how many bytes have passed through.
102
+ */
103
+ export declare function cappedCounter(limit: number): {
104
+ stream: Transform;
105
+ bytes: () => number;
106
+ };
42
107
  export declare const downloadFileTool: Tool;
43
108
  //# sourceMappingURL=download_file.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"download_file.d.ts","sourceRoot":"","sources":["../../src/tools/download_file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAiBH,OAAO,KAAK,EAAE,IAAI,EAA6C,MAAM,kBAAkB,CAAC;AA2BxF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQvD;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAWrG;AAgED,eAAO,MAAM,gBAAgB,EAAE,IAAgD,CAAC"}
1
+ {"version":3,"file":"download_file.d.ts","sourceRoot":"","sources":["../../src/tools/download_file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AAOH,OAAO,EAAY,SAAS,EAA0B,MAAM,aAAa,CAAC;AAgB1E,OAAO,KAAK,EAAE,IAAI,EAA6C,MAAM,kBAAkB,CAAC;AAUxF,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,kBAAmB,CAAC;AACjD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D;;;GAGG;AACH,eAAO,MAAM,0BAA0B,EAAE,WAAW,CAAC,MAAM,CA8BzD,CAAC;AAuCH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQvD;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAWrG;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIzD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,MAAM,CAe7E;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,cAAc,GACrB,MAAM,CAER;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,MAAM,CAMtF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,MAAM,CAAA;CAAE,CAavF;AAoND,eAAO,MAAM,gBAAgB,EAAE,IAAgD,CAAC"}
@@ -23,6 +23,8 @@
23
23
  * - 0o700 dir mode + 0o600 file mode (defense-in-depth on shared hosts).
24
24
  * - Resolved path is verified to start with the sandbox root before
25
25
  * writing — an extra check on top of the structurally-safe naming.
26
+ * - Same item → same local path; a repeat download overwrites the
27
+ * previous copy (deterministic, no accumulation).
26
28
  *
27
29
  * Size cap: 200 MB (handbook spec § Performance characteristics). Item
28
30
  * size is fetched via `/items/{id}` metadata BEFORE downloading; the
@@ -33,23 +35,98 @@
33
35
  * auth needed for the bytes themselves). Streamed via fetch + Node
34
36
  * streams pipeline (no whole-file buffering — handbook anti-pattern #11).
35
37
  *
36
- * Required Graph scope: `Files.Read` (delegated). Read-only on the
37
- * cloud side; writes only to the sandbox locally.
38
+ * Server-side format conversion (`format`, optional):
39
+ * - `format: "pdf"` asks Graph to convert the file server-side via
40
+ * `GET {drive}/items/{id}/content?format=pdf`. No local converter
41
+ * runs — the server never executes anything on the file.
42
+ * - `format` is a strict enum (`DOWNLOAD_FORMATS`); the query value
43
+ * is always the server-side constant, never the raw caller string.
44
+ * - Source type is checked pre-flight against the extensions Graph
45
+ * documents as PDF-convertible; unsupported types fail fast with a
46
+ * clear error and no network call beyond the metadata GET.
47
+ * - Graph answers with a 302 to a pre-authenticated URL for the
48
+ * converted bytes. The SDK's automatic redirect-following is
49
+ * disabled for this request: we read `Location` ourselves, require
50
+ * https, and fetch it WITHOUT the bearer token (same trust model as
51
+ * `@microsoft.graph.downloadUrl`).
52
+ * - A Graph refusal never falls back to the original bytes. 406, 415
53
+ * and a `notSupported` code name the source extension as a conversion
54
+ * failure. Any other 400 also names it, but does not claim the source
55
+ * type is the cause, because the status alone cannot establish that.
56
+ * - The converted size is not known in advance, so the 200 MB cap is
57
+ * also enforced on the stream (Content-Length when present, plus a
58
+ * byte counter). A capped or failed conversion leaves no partial
59
+ * file behind.
60
+ * - Local filename: `<sha256(item_id)[:16]>-<stem>.pdf` — same
61
+ * sandbox, same naming and overwrite policy as plain downloads.
62
+ *
63
+ * Required Graph scope: `Files.Read` (delegated; `Sites.Read(Write).All`
64
+ * for SharePoint drives). Read-only on the cloud side; writes only to
65
+ * the sandbox locally. Conversion needs no additional scope.
38
66
  */
39
67
  import { createWriteStream } from "node:fs";
40
- import { mkdir } from "node:fs/promises";
68
+ import { mkdir, rm } from "node:fs/promises";
41
69
  import os from "node:os";
42
70
  import path from "node:path";
43
71
  import crypto from "node:crypto";
44
- import { Readable } from "node:stream";
72
+ import { Readable, Transform } from "node:stream";
45
73
  import { pipeline } from "node:stream/promises";
46
- import { sanitizeFilename, validateOptionalString, validateRequiredString, } from "../types/validators.js";
74
+ import { RedirectHandlerOptions, ResponseType, } from "@microsoft/microsoft-graph-client";
75
+ import { sanitizeFilename, validateHttpsUrl, validateOptionalStrictEnum, validateOptionalString, validateRequiredString, } from "../types/validators.js";
47
76
  const MAX_FILE_SIZE_BYTES = 200 * 1024 * 1024; // 200 MB per handbook spec
48
77
  const SANDBOX_DIR_MODE = 0o700;
49
78
  const SANDBOX_FILE_MODE = 0o600;
79
+ /** Mirrors sanitizeFilename's length cap so a converted name keeps its extension. */
80
+ const MAX_LOCAL_NAME_CHARS = 200;
81
+ /** Upper bound on how much of a Graph error body we read to build a message. */
82
+ const MAX_ERROR_BODY_CHARS = 4096;
83
+ /** Server-side conversion targets accepted by the `format` parameter. */
84
+ export const DOWNLOAD_FORMATS = ["pdf"];
85
+ /**
86
+ * Source extensions Microsoft Graph documents as convertible with
87
+ * `?format=pdf` ("Download a file in another format").
88
+ */
89
+ export const PDF_CONVERTIBLE_EXTENSIONS = new Set([
90
+ "doc",
91
+ "docx",
92
+ "dot",
93
+ "dotx",
94
+ "dotm",
95
+ "dsn",
96
+ "dwg",
97
+ "eml",
98
+ "epub",
99
+ "fluidframework",
100
+ "htm",
101
+ "html",
102
+ "loop",
103
+ "markdown",
104
+ "md",
105
+ "msg",
106
+ "odp",
107
+ "ods",
108
+ "odt",
109
+ "pps",
110
+ "ppsx",
111
+ "ppt",
112
+ "pptx",
113
+ "rtf",
114
+ "tif",
115
+ "tiff",
116
+ "xls",
117
+ "xlsm",
118
+ "xlsx",
119
+ ]);
120
+ const CONVERTIBLE_EXTENSIONS = {
121
+ pdf: PDF_CONVERTIBLE_EXTENSIONS,
122
+ };
123
+ const FORMAT_CONTENT_TYPES = {
124
+ pdf: "application/pdf",
125
+ };
126
+ const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
50
127
  const definition = {
51
128
  name: "m365-graph:download_file",
52
- description: "Download a file from a drive to a local sandbox directory. Returns the local path, not the file content — agents read the file via a filesystem-aware tool. Size is capped at 200 MB. Read-only on the cloud side.",
129
+ description: "Download a file from a drive to a local sandbox directory. Returns the local path, not the file content — agents read the file via a filesystem-aware tool. Size is capped at 200 MB. Optional `format: \"pdf\"` has Microsoft Graph convert the file to PDF server-side (Word, Excel, PowerPoint, OpenDocument, RTF, HTML, Markdown, email, TIFF, …) and saves the PDF instead of the original. Read-only on the cloud side.",
53
130
  inputSchema: {
54
131
  type: "object",
55
132
  properties: {
@@ -61,6 +138,11 @@ const definition = {
61
138
  type: "string",
62
139
  description: "Optional drive ID. Defaults to the user's primary OneDrive.",
63
140
  },
141
+ format: {
142
+ type: "string",
143
+ enum: [...DOWNLOAD_FORMATS],
144
+ description: "Optional server-side conversion. 'pdf' converts the file to PDF in Microsoft Graph and saves it as '<name>.pdf' in the sandbox. Omit to download the original bytes. Unsupported source types (e.g. images other than TIFF, archives, existing PDFs) are rejected with an error.",
145
+ },
64
146
  },
65
147
  required: ["item_id"],
66
148
  },
@@ -85,9 +167,158 @@ export function deriveSafeLocalPath(sandboxRoot, itemId, originalName) {
85
167
  }
86
168
  return resolved;
87
169
  }
170
+ /**
171
+ * Lower-cased extension without the dot, or null when the name has
172
+ * none. A leading dot alone (".profile") is not an extension.
173
+ */
174
+ export function fileExtension(name) {
175
+ const dot = name.lastIndexOf(".");
176
+ if (dot <= 0 || dot === name.length - 1)
177
+ return null;
178
+ return name.slice(dot + 1).toLowerCase();
179
+ }
180
+ /**
181
+ * Throw a caller-actionable error when Graph cannot convert this source
182
+ * type to the requested format. Returns the validated source extension.
183
+ */
184
+ export function checkConvertible(name, format) {
185
+ const ext = fileExtension(name);
186
+ const supported = CONVERTIBLE_EXTENSIONS[format];
187
+ if (ext !== null && supported.has(ext))
188
+ return ext;
189
+ const list = [...supported].join(", ");
190
+ if (ext === format) {
191
+ throw new Error(`'${name}' is already a ${format.toUpperCase()} — call download_file without 'format' to fetch it as-is.`);
192
+ }
193
+ const what = ext === null ? "has no file extension" : `has extension '.${ext}'`;
194
+ throw new Error(`Cannot convert '${name}' to ${format.toUpperCase()}: the file ${what}, which Microsoft Graph does not convert to ${format}. Supported source types: ${list}.`);
195
+ }
196
+ /**
197
+ * Graph path for the converted content of an item. The `format` value
198
+ * comes from the enum constant, never from raw caller input.
199
+ */
200
+ export function buildConvertedContentPath(driveRoot, itemId, format) {
201
+ return `${driveRoot}/items/${encodeURIComponent(itemId)}/content?format=${encodeURIComponent(format)}`;
202
+ }
203
+ /**
204
+ * Local name for a converted file: original stem + `.<format>`. The stem
205
+ * is trimmed so the sanitizer's length cap can never cut the extension.
206
+ */
207
+ export function convertedFilename(originalName, format) {
208
+ const ext = fileExtension(originalName);
209
+ const stem = ext === null ? originalName : originalName.slice(0, -(ext.length + 1));
210
+ const suffix = `.${format}`;
211
+ const trimmed = stem.slice(0, MAX_LOCAL_NAME_CHARS - suffix.length);
212
+ return `${trimmed.length > 0 ? trimmed : "file"}${suffix}`;
213
+ }
214
+ /**
215
+ * Byte-counting pass-through that errors once `limit` is exceeded.
216
+ * `bytes()` reports how many bytes have passed through.
217
+ */
218
+ export function cappedCounter(limit) {
219
+ let seen = 0;
220
+ const stream = new Transform({
221
+ transform(chunk, _enc, cb) {
222
+ seen += chunk.length;
223
+ if (seen > limit) {
224
+ cb(new Error("Converted file exceeds the 200 MB cap. Download aborted."));
225
+ return;
226
+ }
227
+ cb(null, chunk);
228
+ },
229
+ });
230
+ return { stream, bytes: () => seen };
231
+ }
232
+ async function readErrorSummary(raw) {
233
+ let text = "";
234
+ try {
235
+ text = (await raw.text()).slice(0, MAX_ERROR_BODY_CHARS);
236
+ }
237
+ catch {
238
+ return { code: "", detail: "" };
239
+ }
240
+ try {
241
+ const parsed = JSON.parse(text);
242
+ const code = typeof parsed.error?.code === "string" ? parsed.error.code : "";
243
+ const message = typeof parsed.error?.message === "string" ? parsed.error.message : "";
244
+ return { code, detail: [code, message].filter(Boolean).join(": ") };
245
+ }
246
+ catch {
247
+ return { code: "", detail: text.trim().slice(0, 300) };
248
+ }
249
+ }
250
+ /**
251
+ * Whether a failed conversion response is Graph refusing the conversion
252
+ * itself. A 400 counts only on Graph's structured `notSupported` code:
253
+ * the status alone covers any malformed request, and free text such as
254
+ * "Unsupported query option" says nothing about the source file.
255
+ */
256
+ function isConversionRefusal(status, code, detail) {
257
+ if (status === 406 || status === 415)
258
+ return true;
259
+ if (status === 400)
260
+ return code.toLowerCase() === "notsupported";
261
+ return /notSupported|unsupported/i.test(detail);
262
+ }
263
+ /**
264
+ * Request the converted content from Graph and return a response whose
265
+ * body is the converted bytes. Handles Graph's 302-to-pre-authenticated
266
+ * URL contract explicitly; tolerates a direct 200 with the body.
267
+ */
268
+ async function fetchConverted(graph, contentPath, name, sourceExtension, format) {
269
+ const raw = (await graph
270
+ .api(contentPath)
271
+ // Do not let the SDK follow the redirect: we validate the target and
272
+ // fetch it ourselves without the bearer token.
273
+ .middlewareOptions([new RedirectHandlerOptions(0, () => false)])
274
+ .responseType(ResponseType.RAW)
275
+ .get());
276
+ if (REDIRECT_STATUSES.has(raw.status)) {
277
+ const target = validateHttpsUrl(raw.headers.get("location"), "PDF conversion: Graph redirect Location");
278
+ await raw.body?.cancel().catch(() => undefined);
279
+ const converted = await fetch(target);
280
+ if (!converted.ok) {
281
+ throw new Error(`PDF conversion download HTTP ${converted.status}: ${converted.statusText}`);
282
+ }
283
+ return converted;
284
+ }
285
+ if (raw.status === 200)
286
+ return raw;
287
+ const { code, detail } = await readErrorSummary(raw);
288
+ const suffix = detail ? ` (${detail})` : "";
289
+ if (isConversionRefusal(raw.status, code, detail)) {
290
+ throw new Error(`Microsoft Graph could not convert '${name}' to ${format.toUpperCase()}: HTTP ${raw.status}${suffix}. Source extension: '.${sourceExtension}'. The file may be encrypted, corrupt, or of a type Graph cannot convert.`);
291
+ }
292
+ if (raw.status === 400) {
293
+ throw new Error(`PDF conversion HTTP 400${suffix} for '${name}' (source extension '.${sourceExtension}'). This response does not establish that the source type is the cause.`);
294
+ }
295
+ throw new Error(`PDF conversion HTTP ${raw.status}${suffix}`);
296
+ }
297
+ async function writeCapped(response, localPath) {
298
+ const declared = Number(response.headers.get("content-length") ?? NaN);
299
+ if (Number.isFinite(declared) && declared > MAX_FILE_SIZE_BYTES) {
300
+ await response.body?.cancel().catch(() => undefined);
301
+ throw new Error(`Converted file size (${declared} bytes) exceeds the 200 MB cap. Refusing to download.`);
302
+ }
303
+ if (!response.body) {
304
+ throw new Error("Download response has no body stream.");
305
+ }
306
+ const counter = cappedCounter(MAX_FILE_SIZE_BYTES);
307
+ const out = createWriteStream(localPath, { mode: SANDBOX_FILE_MODE });
308
+ try {
309
+ await pipeline(Readable.fromWeb(response.body), counter.stream, out);
310
+ }
311
+ catch (err) {
312
+ // No partial artifact left in the sandbox.
313
+ await rm(localPath, { force: true }).catch(() => undefined);
314
+ throw err;
315
+ }
316
+ return counter.bytes();
317
+ }
88
318
  const handler = async (graph, args) => {
89
319
  const itemId = validateRequiredString(args.item_id, "item_id");
90
320
  const driveId = validateOptionalString(args.drive_id, "drive_id");
321
+ const format = validateOptionalStrictEnum(args.format, "format", DOWNLOAD_FORMATS);
91
322
  const driveRoot = driveId ? `/drives/${encodeURIComponent(driveId)}` : "/me/drive";
92
323
  const item = await graph.api(`${driveRoot}/items/${encodeURIComponent(itemId)}`).get();
93
324
  if (item.folder !== undefined) {
@@ -97,6 +328,31 @@ const handler = async (graph, args) => {
97
328
  if (size > MAX_FILE_SIZE_BYTES) {
98
329
  throw new Error(`File size (${size} bytes) exceeds the 200 MB cap. Refusing to download.`);
99
330
  }
331
+ const itemName = String(item.name ?? "");
332
+ const sourceContentType = item.file?.mimeType ?? null;
333
+ if (format !== undefined) {
334
+ const sourceExtension = checkConvertible(itemName, format);
335
+ const tenantId = process.env.M365_TENANT_ID ?? "unknown";
336
+ const sandboxRoot = getSandboxRoot(tenantId);
337
+ await mkdir(sandboxRoot, { recursive: true, mode: SANDBOX_DIR_MODE });
338
+ const localPath = deriveSafeLocalPath(sandboxRoot, itemId, convertedFilename(itemName, format));
339
+ const response = await fetchConverted(graph, buildConvertedContentPath(driveRoot, itemId, format), itemName, sourceExtension, format);
340
+ const written = await writeCapped(response, localPath);
341
+ const result = {
342
+ item_id: itemId,
343
+ drive_id: driveId ?? null,
344
+ local_path: localPath,
345
+ size_bytes: written,
346
+ name: itemName,
347
+ content_type: FORMAT_CONTENT_TYPES[format],
348
+ format,
349
+ source_size_bytes: size,
350
+ source_content_type: sourceContentType,
351
+ };
352
+ return {
353
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
354
+ };
355
+ }
100
356
  const downloadUrl = item["@microsoft.graph.downloadUrl"];
101
357
  if (!downloadUrl) {
102
358
  throw new Error("No @microsoft.graph.downloadUrl in item metadata — Graph returned an unexpected shape.");
@@ -122,8 +378,9 @@ const handler = async (graph, args) => {
122
378
  drive_id: driveId ?? null,
123
379
  local_path: localPath,
124
380
  size_bytes: size,
125
- name: String(item.name ?? ""),
126
- content_type: item.file?.mimeType ?? null,
381
+ name: itemName,
382
+ content_type: sourceContentType,
383
+ format: null,
127
384
  };
128
385
  return {
129
386
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
@@ -1 +1 @@
1
- {"version":3,"file":"download_file.js","sourceRoot":"","sources":["../../src/tools/download_file.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"download_file.js","sourceRoot":"","sources":["../../src/tools/download_file.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"list_events.d.ts","sourceRoot":"","sources":["../../src/tools/list_events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AASH,OAAO,KAAK,EAAE,IAAI,EAA6C,MAAM,kBAAkB,CAAC;AAkCxF,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,GAAG,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,UAAU,EAAE,OAAO,CAAC;IACpB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;CACjB;AAaD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,CA2B3E;AA0CD,eAAO,MAAM,cAAc,EAAE,IAAgD,CAAC"}
1
+ {"version":3,"file":"list_events.d.ts","sourceRoot":"","sources":["../../src/tools/list_events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AASH,OAAO,KAAK,EAAE,IAAI,EAA6C,MAAM,kBAAkB,CAAC;AAkCxF,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,GAAG,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,UAAU,EAAE,OAAO,CAAC;IACpB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;CACjB;AAaD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,CA2B3E;AA+CD,eAAO,MAAM,cAAc,EAAE,IAAgD,CAAC"}
@@ -98,9 +98,14 @@ const handler = async (graph, args) => {
98
98
  const apiBase = calendarId
99
99
  ? `/me/calendars/${encodeURIComponent(calendarId)}/calendarView`
100
100
  : "/me/calendarView";
101
+ // The SDK joins query values raw. Encode them here, or the '+' of a
102
+ // positive UTC offset reaches Graph as a space.
101
103
  const response = await graph
102
104
  .api(apiBase)
103
- .query({ startDateTime: start, endDateTime: end })
105
+ .query({
106
+ startDateTime: encodeURIComponent(start),
107
+ endDateTime: encodeURIComponent(end),
108
+ })
104
109
  .select("id,subject,bodyPreview,start,end,isAllDay,isOnlineMeeting,location,organizer,attendees,webLink")
105
110
  .top(limit)
106
111
  .orderby("start/dateTime")
@@ -1 +1 @@
1
- {"version":3,"file":"list_events.js","sourceRoot":"","sources":["../../src/tools/list_events.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"list_events.js","sourceRoot":"","sources":["../../src/tools/list_events.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"search_events.d.ts","sourceRoot":"","sources":["../../src/tools/search_events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AASH,OAAO,KAAK,EAAE,IAAI,EAA6C,MAAM,kBAAkB,CAAC;AA0DxF,eAAO,MAAM,gBAAgB,EAAE,IAAgD,CAAC"}
1
+ {"version":3,"file":"search_events.d.ts","sourceRoot":"","sources":["../../src/tools/search_events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AASH,OAAO,KAAK,EAAE,IAAI,EAA6C,MAAM,kBAAkB,CAAC;AA4DxF,eAAO,MAAM,gBAAgB,EAAE,IAAgD,CAAC"}
@@ -51,9 +51,11 @@ const handler = async (graph, args) => {
51
51
  });
52
52
  // OData literal-string escape: ' → ''
53
53
  const escapedQuery = query.replace(/'/g, "''");
54
+ // The SDK stores $filter raw. Encode the literal here, or '+', '&' and
55
+ // '#' in the search term corrupt or split the query string.
54
56
  const response = await graph
55
57
  .api("/me/events")
56
- .filter(`contains(subject, '${escapedQuery}')`)
58
+ .filter(`contains(subject, '${encodeURIComponent(escapedQuery)}')`)
57
59
  .top(limit)
58
60
  .get();
59
61
  const items = Array.isArray(response?.value) ? response.value : [];
@@ -1 +1 @@
1
- {"version":3,"file":"search_events.js","sourceRoot":"","sources":["../../src/tools/search_events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EACL,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAGhC,MAAM,UAAU,GAAmB;IACjC,IAAI,EAAE,0BAA0B;IAChC,WAAW,EACT,oPAAoP;IACtP,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,mFAAmF;aACjG;YACD,KAAK,EAAE;gBACL,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,EAAE;gBACX,WAAW,EAAE,mDAAmD;aACjE;SACF;QACD,QAAQ,EAAE,CAAC,OAAO,CAAC;KACpB;CACF,CAAC;AAEF,MAAM,OAAO,GAAgB,KAAK,EAChC,KAAa,EACb,IAA6B,EACN,EAAE;IACzB,MAAM,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,uBAAuB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE;QACzD,GAAG,EAAE,CAAC;QACN,GAAG,EAAE,EAAE;QACP,OAAO,EAAE,EAAE;KACZ,CAAC,CAAC;IAEH,sCAAsC;IACtC,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAE/C,MAAM,QAAQ,GAAG,MAAM,KAAK;SACzB,GAAG,CAAC,YAAY,CAAC;SACjB,MAAM,CAAC,sBAAsB,YAAY,IAAI,CAAC;SAC9C,GAAG,CAAC,KAAK,CAAC;SACV,GAAG,EAAE,CAAC;IAET,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAA0B,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;IAE5E,MAAM,MAAM,GAAG;QACb,KAAK;QACL,KAAK,EAAE,MAAM,CAAC,MAAM;QACpB,OAAO,EAAE,MAAM;KAChB,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KACnE,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"search_events.js","sourceRoot":"","sources":["../../src/tools/search_events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EACL,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAGhC,MAAM,UAAU,GAAmB;IACjC,IAAI,EAAE,0BAA0B;IAChC,WAAW,EACT,oPAAoP;IACtP,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,mFAAmF;aACjG;YACD,KAAK,EAAE;gBACL,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,EAAE;gBACX,WAAW,EAAE,mDAAmD;aACjE;SACF;QACD,QAAQ,EAAE,CAAC,OAAO,CAAC;KACpB;CACF,CAAC;AAEF,MAAM,OAAO,GAAgB,KAAK,EAChC,KAAa,EACb,IAA6B,EACN,EAAE;IACzB,MAAM,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,uBAAuB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE;QACzD,GAAG,EAAE,CAAC;QACN,GAAG,EAAE,EAAE;QACP,OAAO,EAAE,EAAE;KACZ,CAAC,CAAC;IAEH,sCAAsC;IACtC,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAE/C,uEAAuE;IACvE,4DAA4D;IAC5D,MAAM,QAAQ,GAAG,MAAM,KAAK;SACzB,GAAG,CAAC,YAAY,CAAC;SACjB,MAAM,CAAC,sBAAsB,kBAAkB,CAAC,YAAY,CAAC,IAAI,CAAC;SAClE,GAAG,CAAC,KAAK,CAAC;SACV,GAAG,EAAE,CAAC;IAET,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAA0B,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;IAE5E,MAAM,MAAM,GAAG;QACb,KAAK;QACL,KAAK,EAAE,MAAM,CAAC,MAAM;QACpB,OAAO,EAAE,MAAM;KAChB,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KACnE,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC"}
@@ -19,6 +19,18 @@ export declare function validateOptionalInteger(value: unknown, fieldName: strin
19
19
  default: number;
20
20
  }): number;
21
21
  export declare function validateOptionalEnum<T extends string>(value: unknown, fieldName: string, allowed: ReadonlyArray<T>, defaultValue: T): T;
22
+ /**
23
+ * Optional strict enum with no default: absent/null → undefined;
24
+ * anything else must be one of `allowed` exactly (case-sensitive).
25
+ * Used where "unset" has its own meaning (e.g. download_file `format`
26
+ * absent = original bytes), so a default value would be wrong.
27
+ */
28
+ export declare function validateOptionalStrictEnum<T extends string>(value: unknown, fieldName: string, allowed: ReadonlyArray<T>): T | undefined;
29
+ /**
30
+ * Require an absolute https URL (e.g. a server-issued redirect target
31
+ * that will be fetched). Returns the normalized URL string.
32
+ */
33
+ export declare function validateHttpsUrl(value: unknown, label: string): string;
22
34
  /**
23
35
  * Lightweight ISO 8601 date/datetime check. Accepts:
24
36
  * - YYYY-MM-DD
@@ -1 +1 @@
1
- {"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../src/types/validators.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAKhF;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CAGpB;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACrD,MAAM,CAaR;AAID,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,MAAM,EACnD,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,EACzB,YAAY,EAAE,CAAC,GACd,CAAC,CAQH;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQjF;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKrD"}
1
+ {"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../src/types/validators.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAKhF;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CAGpB;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACrD,MAAM,CAaR;AAID,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,MAAM,EACnD,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,EACzB,YAAY,EAAE,CAAC,GACd,CAAC,CAQH;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,SAAS,MAAM,EACzD,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GACxB,CAAC,GAAG,SAAS,CAQf;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CActE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQjF;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKrD"}
@@ -42,6 +42,40 @@ export function validateOptionalEnum(value, fieldName, allowed, defaultValue) {
42
42
  }
43
43
  return value;
44
44
  }
45
+ /**
46
+ * Optional strict enum with no default: absent/null → undefined;
47
+ * anything else must be one of `allowed` exactly (case-sensitive).
48
+ * Used where "unset" has its own meaning (e.g. download_file `format`
49
+ * absent = original bytes), so a default value would be wrong.
50
+ */
51
+ export function validateOptionalStrictEnum(value, fieldName, allowed) {
52
+ if (value === undefined || value === null)
53
+ return undefined;
54
+ if (typeof value !== "string" || !allowed.includes(value)) {
55
+ throw new Error(`'${fieldName}' must be one of ${JSON.stringify(allowed)}; got ${JSON.stringify(value)}`);
56
+ }
57
+ return value;
58
+ }
59
+ /**
60
+ * Require an absolute https URL (e.g. a server-issued redirect target
61
+ * that will be fetched). Returns the normalized URL string.
62
+ */
63
+ export function validateHttpsUrl(value, label) {
64
+ if (typeof value !== "string" || value.length === 0) {
65
+ throw new Error(`${label} is missing`);
66
+ }
67
+ let url;
68
+ try {
69
+ url = new URL(value);
70
+ }
71
+ catch {
72
+ throw new Error(`${label} is not an absolute URL`);
73
+ }
74
+ if (url.protocol !== "https:") {
75
+ throw new Error(`${label} must be https; refusing non-https target (${url.protocol})`);
76
+ }
77
+ return url.toString();
78
+ }
45
79
  /**
46
80
  * Lightweight ISO 8601 date/datetime check. Accepts:
47
81
  * - YYYY-MM-DD
@@ -1 +1 @@
1
- {"version":3,"file":"validators.js","sourceRoot":"","sources":["../../src/types/validators.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,UAAU,sBAAsB,CAAC,KAAc,EAAE,SAAiB;IACtE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,IAAI,SAAS,8BAA8B,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,KAAc,EACd,SAAiB;IAEjB,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5D,OAAO,sBAAsB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,KAAc,EACd,SAAiB,EACjB,OAAsD;IAEtD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC;IAClE,IACE,OAAO,KAAK,KAAK,QAAQ;QACzB,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC;QACxB,KAAK,GAAG,OAAO,CAAC,GAAG;QACnB,KAAK,GAAG,OAAO,CAAC,GAAG,EACnB,CAAC;QACD,MAAM,IAAI,KAAK,CACb,IAAI,SAAS,gCAAgC,OAAO,CAAC,GAAG,QAAQ,OAAO,CAAC,GAAG,EAAE,CAC9E,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,mBAAmB,GAAG,0EAA0E,CAAC;AAEvG,MAAM,UAAU,oBAAoB,CAClC,KAAc,EACd,SAAiB,EACjB,OAAyB,EACzB,YAAe;IAEf,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,YAAY,CAAC;IAC/D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAE,OAAiC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACrF,MAAM,IAAI,KAAK,CACb,IAAI,SAAS,oBAAoB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CACzF,CAAC;IACJ,CAAC;IACD,OAAO,KAAU,CAAC;AACpB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAc,EAAE,SAAiB;IACvE,MAAM,CAAC,GAAG,sBAAsB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACnD,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,IAAI,SAAS,6FAA6F,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAC9H,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,IAAI;SACR,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;SACxB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,kBAAkB;SACvC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACnB,CAAC"}
1
+ {"version":3,"file":"validators.js","sourceRoot":"","sources":["../../src/types/validators.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juvantlabs/m365-graph-mcp-server",
3
- "version": "0.4.3",
3
+ "version": "0.5.0",
4
4
  "description": "Microsoft Graph MCP server — OneDrive, SharePoint, and Calendar read+write for Juvant OS agents.",
5
5
  "license": "MIT",
6
6
  "author": "Juvant Srls",