@juvantlabs/m365-graph-mcp-server 0.2.1 → 0.3.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
@@ -39,7 +39,12 @@ the auth path consolidated.
39
39
  **Meeting transcripts** (v0.2.0+)
40
40
 
41
41
  - List available transcripts for a Teams meeting (from a calendar event ID).
42
- - Fetch transcript content (VTT parsed to clean text, capped at 30 000 chars).
42
+ - Fetch transcript content (VTT parsed to clean text). Long transcripts page
43
+ client-side via `offset` + `next_offset` — the Graph content endpoint
44
+ returns the whole VTT in one blob, so paging is implemented in this server
45
+ by slicing the parsed text. Per-call cap (`M365_TRANSCRIPT_MAX_CHARS`,
46
+ default 200 000) and upstream byte cap (`M365_TRANSCRIPT_MAX_BYTES`,
47
+ default 10 MB) are configurable.
43
48
  - Post-meeting only: live transcription during active calls requires a media bot
44
49
  (separate threat model; explicitly out of scope — see below).
45
50
 
@@ -163,7 +168,7 @@ that informs the [handbook MCP server spec](https://github.com/juvantlabs/handbo
163
168
  | README env-var lies (audit S2) | CI README env-var accuracy check. |
164
169
  | OData / URL injection (audit S3) | All Graph queries built via the SDK or with explicit `encodeURIComponent`. |
165
170
  | Token storage (audit S5) | `@napi-rs/keyring`, never `keytar`. |
166
- | Whole-file buffering (audit S7) | Downloads stream; max file size capped at 200 MB (configurable). |
171
+ | Whole-file buffering (audit S7) | Downloads stream; max file size capped at 200 MB (configurable). Transcript reads cap raw VTT at `M365_TRANSCRIPT_MAX_BYTES` (default 10 MB) and parsed-text per response at `M365_TRANSCRIPT_MAX_CHARS` (default 200 000 chars). |
167
172
  | No async-op polling (audit S8) | `copy` / `move` poll the monitor URL until completion; never return "initiated successfully" as the final result. |
168
173
 
169
174
  ### Universal Boundaries (per `SYSTEM_INVARIANTS.md` §4)
@@ -217,6 +222,8 @@ Each row is also reflected in [`README.md`](README.md) § Tools.
217
222
  | `m365-graph:cancel_event` | Phase 1: `GET /events/{id}` → preview. Phase 2: `POST /events/{id}/cancel { Comment }` after token consume. | `event_id` (required), `comment?`, `confirmation_token?` | preview or `{ cancelled }` | `Calendars.ReadWrite` | Same two-phase pattern as delete_file. The `comment` is part of the spec — changing it between preview and execute fails `spec_mismatch`. |
218
223
  | `m365-graph:decline_event` | Phase 1: `GET /events/{id}` → preview. Phase 2: `POST /events/{id}/decline { sendResponse, comment? }` after token consume. | `event_id`, `comment?`, `send_response?`, `confirmation_token?` | preview or `{ declined }` | `Calendars.ReadWrite` | For events the user is invited to (attendee). Cancel_event vs decline_event reflect the Graph distinction (organizer vs attendee). `send_response` is part of the spec hash so changing it between preview/execute fails `spec_mismatch`. Default true = organizer notified; false = silent decline. |
219
224
  | `m365-graph:search_events_content` | `POST /search/query` with `entityTypes: ["event"]` + queryString | `query`, `limit?`, `from?` | `{ count, total, results: [<event summary>] }` | `Calendars.Read` | Subject + body search via the Microsoft Search API (separate from `$filter` on /me/events used by `search_events`). Search API hit shape `{ hitId, summary, resource }` mapped back to summarizeEvent's shape via `resource`. Returns recurrence series masters. |
225
+ | `m365-graph:list_meeting_transcripts` | 3-step: `GET /me/events/{id}` (resolve `onlineMeeting.joinUrl`) → `GET /me/onlineMeetings?$filter=JoinWebUrl eq '…'` (resolve onlineMeeting id) → `GET /me/onlineMeetings/{meeting-id}/transcripts` | `event_id` | `{ event_id, meeting_id, count, transcripts: [{ id, meeting_id, created_at, end_at }] }` | `Calendars.Read`, `OnlineMeetings.Read`, `OnlineMeetingTranscript.Read.All` (latter two delegated, **admin consent required**) | Non-online-meeting events return `{ error: "not_an_online_meeting" }`; missing join URL or unresolved onlineMeeting returns `{ error: "meeting_id_unavailable" }` (both as text content, not thrown). joinUrl is single-quote-escaped before OData filter interpolation. Empty `transcripts` list (not an error) when recording was disabled or transcript is still processing. |
226
+ | `m365-graph:get_transcript` | `GET /me/onlineMeetings/{meeting-id}/transcripts/{transcript-id}/content?$format=text/vtt` (returns raw WebVTT) | `meeting_id`, `transcript_id`, `offset?` (0..2_000_000_000, default 0), `max_chars?` (1..`M365_TRANSCRIPT_MAX_CHARS`, default = cap) | `{ meeting_id, transcript_id, offset, char_count, next_offset, total_char_count, truncated, vtt_truncated, transcript }` | `OnlineMeetingTranscript.Read.All` (delegated, **admin consent required**) | **VTT timing-marker stripping**: `WEBVTT` header, `NOTE` blocks, `HH:MM:SS.mmm --> …` timestamp lines, numeric cue-sequence lines, and blank lines are stripped; cue text (speaker names + spoken content) is kept and joined with `\n`. **Two caps** (defense-in-depth, audit-S7 whole-file-buffering bound): raw VTT bytes read from Graph capped at `M365_TRANSCRIPT_MAX_BYTES` (default 10 MB ≈ 8h+ of speech) — surplus is dropped and `vtt_truncated: true` is flagged on the response; parsed-text characters returned per call capped at `M365_TRANSCRIPT_MAX_CHARS` (default 200 000 ≈ 2h of speech). **Client-side paging**: long transcripts are paged by slicing the parsed text — caller passes the previous response's `next_offset` (or `null` if done) back as `offset` on the next call. `truncated` is `true` iff `next_offset !== null` (i.e. the returned slice does not reach the end of the parsed text); distinct from `vtt_truncated`, which signals upstream byte-cap loss. |
220
227
 
221
228
  ## Spec/approval confirmation-token pattern
222
229
 
package/CHANGELOG.md CHANGED
@@ -9,6 +9,75 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
9
9
 
10
10
  ---
11
11
 
12
+ ## [Unreleased]
13
+
14
+ ---
15
+
16
+ ## [0.3.0] - 2026-06-22 — Long Teams transcript paging + cap fix
17
+
18
+ ### Fixed
19
+
20
+ - **`m365-graph:get_transcript`** silently truncated long Teams meeting
21
+ transcripts at 30 000 chars (parsed text) and 500 KB (raw VTT). Defaults
22
+ are now 200 000 chars / 10 MB — generous enough for multi-hour meetings —
23
+ and the byte cap loss is now flagged on the response (`vtt_truncated`).
24
+ Issue [#2](https://github.com/juvantlabs/m365-graph-mcp-server/issues/2).
25
+ - **Server version reporting** — the MCP `Server` constructor previously
26
+ advertised a hardcoded `version: "0.1.4"` to every MCP client while
27
+ `package.json` had moved on. The version is now read from `package.json`
28
+ at runtime via `createRequire(import.meta.url)`, so it always matches the
29
+ shipped package (and is also surfaced in the stdio startup log line). A
30
+ unit test asserts `PACKAGE_VERSION === package.json#version` to prevent
31
+ silent drift from recurring.
32
+
33
+ ### Added
34
+
35
+ - **`m365-graph:get_transcript`** — paging support. New optional inputs
36
+ `offset` (0..2_000_000_000) and `max_chars`. New response fields `offset`,
37
+ `next_offset`, `total_char_count`, and `vtt_truncated`. Existing fields
38
+ (`meeting_id`, `transcript_id`, `char_count`, `truncated`, `transcript`)
39
+ remain. Backward-compatible: prior callers passing only `meeting_id` +
40
+ `transcript_id` keep working; `truncated` now means "this slice does not
41
+ reach the end of the parsed text" (previously meant "30k cap hit", which
42
+ was always at offset 0 so the semantics align).
43
+ - **`M365_TRANSCRIPT_MAX_BYTES`** env var — overrides the upstream VTT
44
+ byte cap (default 10 000 000).
45
+ - **`M365_TRANSCRIPT_MAX_CHARS`** env var — overrides the per-call parsed-
46
+ text cap (default 200 000).
47
+
48
+ ### Security
49
+
50
+ - `npm audit fix` to clear moderate+ advisories that were blocking CI. No
51
+ direct-dependency major bumps; transitive lockfile updates only.
52
+
53
+ ### Documentation
54
+
55
+ - Accuracy pass across `ARCHITECTURE.md`, `README.md`, and `## Status` ahead
56
+ of the v0.3.0 tag. `ARCHITECTURE.md § Tool catalog` gains rows for
57
+ `list_meeting_transcripts` and `get_transcript` (Graph call chain, inputs,
58
+ outputs, scopes, VTT-stripping + paging + cap notes). README Tools-table
59
+ rows for `list_calendars`, `list_events`, and `get_event` reconciled with
60
+ the actual handler shapes (owner_name/owner_email split, body_preview /
61
+ is_all_day / is_online_meeting / organizer_name / organizer_email / webLink,
62
+ online_meeting_join_url). `## What's new` is now evergreen (no version
63
+ suffix); the `get_transcript` bullet drops the stale "30 000 chars" cap
64
+ reference — cap and paging detail live in the Tools table and the
65
+ `## Environment variables` table only. `## Status` reads v0.3.0; the
66
+ `mcp_server` pin in the binding example is bumped to `0.3.0`. No code
67
+ changes.
68
+
69
+ ---
70
+
71
+ ## [0.2.1] - 2026-06-15
72
+
73
+ ### Documentation
74
+
75
+ - README `## What's new in v0.2.0` section added retroactively for the v0.2.0
76
+ ship (transcript tools + new delegated scopes + `npm run setup` reminder).
77
+ No behavior change; package metadata-only release.
78
+
79
+ ---
80
+
12
81
  ## [0.2.0] - 2026-05-15
13
82
 
14
83
  ### Added
@@ -299,4 +368,12 @@ the Juvant OS instance level — see juvant-os-pm FEAT-018 / 019 /
299
368
 
300
369
  ---
301
370
 
302
- [Unreleased]: https://github.com/juvantlabs/m365-graph-mcp-server/compare/HEAD
371
+ [Unreleased]: https://github.com/juvantlabs/m365-graph-mcp-server/compare/v0.3.0...HEAD
372
+ [0.3.0]: https://github.com/juvantlabs/m365-graph-mcp-server/compare/v0.2.1...v0.3.0
373
+ [0.2.1]: https://github.com/juvantlabs/m365-graph-mcp-server/compare/v0.2.0...v0.2.1
374
+ [0.2.0]: https://github.com/juvantlabs/m365-graph-mcp-server/compare/v0.1.4...v0.2.0
375
+ [0.1.4]: https://github.com/juvantlabs/m365-graph-mcp-server/compare/v0.1.3...v0.1.4
376
+ [0.1.3]: https://github.com/juvantlabs/m365-graph-mcp-server/compare/v0.1.2...v0.1.3
377
+ [0.1.2]: https://github.com/juvantlabs/m365-graph-mcp-server/compare/v0.1.1...v0.1.2
378
+ [0.1.1]: https://github.com/juvantlabs/m365-graph-mcp-server/compare/v0.1.0...v0.1.1
379
+ [0.1.0]: https://github.com/juvantlabs/m365-graph-mcp-server/releases/tag/v0.1.0
package/README.md CHANGED
@@ -17,12 +17,12 @@ real Juvant OS need surfaces; outbound Teams notifications go through
17
17
  webhooks (Adaptive Cards), not MCP. Per-company instance config binds
18
18
  this server in `.juvant/config.json`.
19
19
 
20
- ## What's new in v0.2.0
20
+ ## What's new
21
21
 
22
22
  **Teams meeting transcript support.** Two new read-only tools:
23
23
 
24
24
  - **`m365-graph:list_meeting_transcripts`** — given a calendar event ID, lists available post-meeting transcripts. Returns transcript IDs to pass to `get_transcript`.
25
- - **`m365-graph:get_transcript`** — fetches the transcript content, strips VTT timing markers, and returns clean readable text (capped at 30 000 chars).
25
+ - **`m365-graph:get_transcript`** — fetches the transcript content, strips VTT timing markers, and returns clean readable text.
26
26
 
27
27
  Two new delegated scopes required (admin consent — see § Tools):
28
28
  `OnlineMeetings.Read` and `OnlineMeetingTranscript.Read.All`.
@@ -32,7 +32,7 @@ See [CHANGELOG.md](CHANGELOG.md) for the full change list.
32
32
 
33
33
  ## Status
34
34
 
35
- **Published.** v0.2.0 on npm
35
+ **Published.** v0.3.0 on npm
36
36
  ([`@juvantlabs/m365-graph-mcp-server`](https://www.npmjs.com/package/@juvantlabs/m365-graph-mcp-server)).
37
37
  19 tools across files (OneDrive + SharePoint), Outlook Calendar, and
38
38
  Teams meeting transcripts. Published via npm **Trusted Publishing**
@@ -76,6 +76,8 @@ Optional:
76
76
  |---|---|
77
77
  | `MCP_SERVER_LOG_LEVEL` | Log level for diagnostics on stderr (default `info`). |
78
78
  | `M365_DOWNLOAD_DIR` | Override the per-tenant sandbox directory used by `download_file`. Default: `$XDG_CACHE_HOME/m365-graph-mcp-server/<tenant-id>` or `~/.cache/m365-graph-mcp-server/<tenant-id>`. |
79
+ | `M365_TRANSCRIPT_MAX_BYTES` | Max raw VTT bytes read from Graph per `get_transcript` call. Defense-in-depth bound against the audit-S7 whole-file-buffering pattern. Default `10000000` (10 MB ≈ 8 h+ of speech). |
80
+ | `M365_TRANSCRIPT_MAX_CHARS` | Max parsed-text characters returned in a single `get_transcript` response. Long transcripts page via the tool's `offset` + `next_offset` fields. Default `200000` (~2 h of speech). |
79
81
 
80
82
  > CI enforces that every variable documented in this section is actually
81
83
  > read from `process.env.<NAME>` somewhere in `src/` — placeholder names
@@ -94,7 +96,7 @@ The Juvant OS adopter binds this server in `.juvant/config.json`:
94
96
  {
95
97
  "m365-graph": {
96
98
  "provider": "microsoft",
97
- "mcp_server": "npx @juvantlabs/m365-graph-mcp-server@0.1.3",
99
+ "mcp_server": "npx @juvantlabs/m365-graph-mcp-server@0.3.0",
98
100
  "scope": "rw"
99
101
  }
100
102
  }
@@ -115,10 +117,10 @@ Step 8.5 cross-check semantics.
115
117
  | `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` |
116
118
  | `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` |
117
119
  | `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` |
118
- | `m365-graph:list_calendars` | Lists the user's calendars (primary + group / shared). | `limit?` (1–100, default 50) | `{ count, calendars: [] }` with id / name / color / owner / is_default / can_edit / can_share. | `Calendars.Read` |
119
- | `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) | `{ window, count, events: [] }` with id / subject / start / end / location / organizer / attendees / web_url. | `Calendars.Read` |
120
+ | `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` |
121
+ | `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` |
120
122
  | `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` |
121
- | `m365-graph:get_event` | Fetches full details for a single event — body (capped at 8000 chars), attendees with response statuses, location, recurrence rule. | `event_id` (required) | event summary + `body` / `body_content_type` / `body_truncated` / `recurrence`. | `Calendars.Read` |
123
+ | `m365-graph:get_event` | Fetches full details for a single event — body (capped at 8000 chars), attendees with response statuses, location, recurrence rule, online-meeting join URL when applicable. | `event_id` (required) | event summary + `body` / `body_content_type` / `body_truncated` / `recurrence` / `online_meeting_join_url`. | `Calendars.Read` |
122
124
  | `m365-graph:upload_file` | Uploads a local file to a drive. Auto-routes between single PUT (≤ 4 MB) and resumable upload session (> 4 MB, 10 MB chunks). 200 MB hard cap. | `local_path` (required), `drive_id?`, `parent_item_id?`, `name?`, `conflict_behavior?` (`fail`/`replace`/`rename`, default `fail`) | `{ uploaded: { id, name, size, webUrl, upload_path } }` | `Files.ReadWrite` |
123
125
  | `m365-graph:create_event` | Creates a new event on the user's primary calendar (or a specified calendar). Sends invitations to attendees by Graph default. | `subject` + `start` + `end` (required), `timezone?` (default UTC), `body?`, `body_content_type?` (`text`/`html`), `location?`, `attendees?`, `is_all_day?`, `calendar_id?` | `{ created: <event summary> }` | `Calendars.ReadWrite` |
124
126
  | `m365-graph:update_event` | Updates an existing event. All fields except `event_id` are optional; only provided fields are PATCHed. **Attendees: full replacement, not merge** — pass the full intended list. | `event_id` (required), then any subset of `subject`/`start`+`end`+`timezone`/`body`+`body_content_type`/`location`/`attendees`/`is_all_day` | `{ updated: <event summary> }` | `Calendars.ReadWrite` |
@@ -129,7 +131,7 @@ Step 8.5 cross-check semantics.
129
131
  | `m365-graph:decline_event` | **Two-phase**. Declines an event the user is invited to (as attendee — distinct from cancel which is for events the user organizes). Sends a decline RSVP unless `send_response: false`. | `event_id` (required), `comment?`, `send_response?` (default `true`), `confirmation_token?` | preview or `{ declined: { event_id, send_response } }` | `Calendars.ReadWrite` |
130
132
  | `m365-graph:search_events_content` | Subject + **body** content search via the Microsoft Search API (POST `/search/query`). Distinct from `search_events` (subject-only via `$filter`). Returns recurrence series masters; for occurrences in a window use `list_events`. | `query` (required), `limit?` (1–50, default 25), `from?` (pagination offset, default 0) | `{ count, total, results: [<event summary>] }` | `Calendars.Read` |
131
133
  | `m365-graph:list_meeting_transcripts` | List available transcripts for a Teams meeting identified by its calendar event ID. Transcripts are post-meeting only and require recording to have been enabled by the organizer. | `event_id` (required) | `{ event_id, meeting_id, count, transcripts: [{ id, meeting_id, created_at, end_at }] }` | `Calendars.Read`, `OnlineMeetings.Read` ¹, `OnlineMeetingTranscript.Read.All` ¹ |
132
- | `m365-graph:get_transcript` | Fetch the text content of a Teams meeting transcript. VTT timing markers are stripped; returns clean readable text capped at 30 000 chars. | `meeting_id` + `transcript_id` (both required, from `list_meeting_transcripts`) | `{ meeting_id, transcript_id, char_count, truncated, transcript }` | `OnlineMeetingTranscript.Read.All` ¹ |
134
+ | `m365-graph:get_transcript` | Fetch the text content of a Teams meeting transcript. VTT timing markers are stripped; returns clean readable text. Long transcripts page via `offset` + `next_offset`; per-call cap and upstream byte cap configurable via `M365_TRANSCRIPT_MAX_CHARS` / `M365_TRANSCRIPT_MAX_BYTES` (defaults 200 000 chars / 10 MB). | `meeting_id` + `transcript_id` (required, from `list_meeting_transcripts`); `offset?` (0..2_000_000_000), `max_chars?` | `{ meeting_id, transcript_id, offset, char_count, next_offset, total_char_count, truncated, vtt_truncated, transcript }` | `OnlineMeetingTranscript.Read.All` ¹ |
133
135
 
134
136
  ¹ **Admin consent required.** `OnlineMeetings.Read` and `OnlineMeetingTranscript.Read.All` must be granted in the Entra app registration under **API permissions → Add a permission → Microsoft Graph → Delegated → Grant admin consent**. Without admin consent these tools return 403 Forbidden.
135
137
 
package/dist/index.d.ts CHANGED
@@ -15,6 +15,29 @@
15
15
  */
16
16
  import { ALL_TOOLS } from "./tools/index.js";
17
17
  export declare const TENANT_ID_RE: RegExp;
18
+ /**
19
+ * Read the package version from `package.json` at runtime, so the MCP
20
+ * server advertises the real shipped version instead of a hardcoded
21
+ * literal that silently drifts away from `package.json` on each bump.
22
+ *
23
+ * Resolution strategy: use `createRequire(import.meta.url)` against
24
+ * `../package.json`. This relies on `package.json` sitting one level
25
+ * above the runtime file, which holds in BOTH layouts the build emits:
26
+ *
27
+ * - Built: dist/index.js → ../package.json = <pkg-root>/package.json
28
+ * - Dev: src/index.ts → ../package.json = <pkg-root>/package.json
29
+ * - Tests: src/index.ts → ../package.json = <pkg-root>/package.json
30
+ *
31
+ * `createRequire` is preferred over a bare JSON import-assertion here
32
+ * because `tsconfig.json` has `rootDir: "src"`, which forbids importing
33
+ * `../package.json` from `src/index.ts`. Going through `createRequire`
34
+ * sidesteps the rootDir constraint without copying or generating files
35
+ * at build time, and stays dependency-free.
36
+ *
37
+ * Exported for unit testing.
38
+ */
39
+ export declare function readPackageVersion(): string;
40
+ export declare const PACKAGE_VERSION: string;
18
41
  /**
19
42
  * Validate the env vars the server needs at startup. Throws with a
20
43
  * specific message on failure; main() catches + exits with stderr +
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;GAaG;AAeH,OAAO,EAAE,SAAS,EAAmB,MAAM,kBAAkB,CAAC;AAE9D,eAAO,MAAM,YAAY,QAC0E,CAAC;AAEpG;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,IAAI,CAgBnE;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,OAAO,mCAAmC,EAAE,MAAM,EACzD,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,EAC5D,OAAO,EAAE;IAAE,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GACzD,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAmBhF;AAiCD;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE;IACvD,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;GAaG;AAgBH,OAAO,EAAE,SAAS,EAAmB,MAAM,kBAAkB,CAAC;AAE9D,eAAO,MAAM,YAAY,QAC0E,CAAC;AAEpG;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAI3C;AAED,eAAO,MAAM,eAAe,QAAuB,CAAC;AAEpD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,IAAI,CAgBnE;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,OAAO,mCAAmC,EAAE,MAAM,EACzD,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,EAC5D,OAAO,EAAE;IAAE,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GACzD,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAmBhF;AAiCD;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE;IACvD,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhB"}
package/dist/index.js CHANGED
@@ -14,6 +14,7 @@
14
14
  * rules enforce this in `juvantlabs/*-mcp-server` repos.
15
15
  */
16
16
  import { realpathSync } from "node:fs";
17
+ import { createRequire } from "node:module";
17
18
  import { pathToFileURL } from "node:url";
18
19
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
19
20
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -23,6 +24,33 @@ import { runSetup } from "./auth/setup.js";
23
24
  import { makeGraphClient } from "./client/graph.js";
24
25
  import { ALL_TOOLS, buildHandlerMap } from "./tools/index.js";
25
26
  export const TENANT_ID_RE = /^(common|organizations|consumers|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/;
27
+ /**
28
+ * Read the package version from `package.json` at runtime, so the MCP
29
+ * server advertises the real shipped version instead of a hardcoded
30
+ * literal that silently drifts away from `package.json` on each bump.
31
+ *
32
+ * Resolution strategy: use `createRequire(import.meta.url)` against
33
+ * `../package.json`. This relies on `package.json` sitting one level
34
+ * above the runtime file, which holds in BOTH layouts the build emits:
35
+ *
36
+ * - Built: dist/index.js → ../package.json = <pkg-root>/package.json
37
+ * - Dev: src/index.ts → ../package.json = <pkg-root>/package.json
38
+ * - Tests: src/index.ts → ../package.json = <pkg-root>/package.json
39
+ *
40
+ * `createRequire` is preferred over a bare JSON import-assertion here
41
+ * because `tsconfig.json` has `rootDir: "src"`, which forbids importing
42
+ * `../package.json` from `src/index.ts`. Going through `createRequire`
43
+ * sidesteps the rootDir constraint without copying or generating files
44
+ * at build time, and stays dependency-free.
45
+ *
46
+ * Exported for unit testing.
47
+ */
48
+ export function readPackageVersion() {
49
+ const require = createRequire(import.meta.url);
50
+ const pkg = require("../package.json");
51
+ return pkg.version;
52
+ }
53
+ export const PACKAGE_VERSION = readPackageVersion();
26
54
  /**
27
55
  * Validate the env vars the server needs at startup. Throws with a
28
56
  * specific message on failure; main() catches + exits with stderr +
@@ -79,7 +107,7 @@ async function runMcpServer() {
79
107
  const logLevel = process.env.MCP_SERVER_LOG_LEVEL ?? "info";
80
108
  const server = new Server({
81
109
  name: "@juvantlabs/m365-graph-mcp-server",
82
- version: "0.1.4",
110
+ version: PACKAGE_VERSION,
83
111
  }, {
84
112
  capabilities: { tools: {} },
85
113
  });
@@ -89,7 +117,7 @@ async function runMcpServer() {
89
117
  server.setRequestHandler(CallToolRequestSchema, async (request) => dispatchToolCall(graph, handlers, request));
90
118
  const transport = new StdioServerTransport();
91
119
  await server.connect(transport);
92
- console.error(`[m365-graph-mcp-server] running on stdio (log level: ${logLevel}, tenant: ${process.env.M365_TENANT_ID}, tools: ${ALL_TOOLS.length})`);
120
+ console.error(`[m365-graph-mcp-server] v${PACKAGE_VERSION} running on stdio (log level: ${logLevel}, tenant: ${process.env.M365_TENANT_ID}, tools: ${ALL_TOOLS.length})`);
93
121
  }
94
122
  /**
95
123
  * Subcommand dispatcher. Exported so tests can verify routing without
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -3,19 +3,35 @@
3
3
  *
4
4
  * Fetch the text content of a Teams meeting transcript. The Graph API
5
5
  * returns VTT (WebVTT subtitle format); this tool strips the timing
6
- * markers and returns clean readable text, capped at 30 000 chars.
6
+ * markers and returns clean readable text.
7
7
  *
8
8
  * Required Graph scope: OnlineMeetingTranscript.Read.All (delegated,
9
9
  * admin consent required).
10
10
  *
11
+ * Caps (defense-in-depth bounds, configurable via env):
12
+ * - Raw VTT stream: M365_TRANSCRIPT_MAX_BYTES (default 10 000 000 / 10 MB)
13
+ * - Parsed-text page: M365_TRANSCRIPT_MAX_CHARS (default 200 000 chars)
14
+ *
15
+ * Paging: when a transcript exceeds the per-call char cap, callers
16
+ * iterate by passing the returned `next_offset` back as `offset` on
17
+ * the next call. The Graph content endpoint returns the whole VTT in
18
+ * one blob — there is no server-side paging primitive — so paging is
19
+ * implemented client-side by slicing the parsed text.
20
+ *
11
21
  * Input:
12
- * meeting_id (string, required) — onlineMeeting id from
22
+ * meeting_id (string, required) — onlineMeeting id from
13
23
  * list_meeting_transcripts
14
- * transcript_id (string, required) — transcript id from
24
+ * transcript_id (string, required) — transcript id from
15
25
  * list_meeting_transcripts
26
+ * offset (integer, optional, 0..2_000_000_000, default 0)
27
+ * — character offset into the parsed transcript text
28
+ * max_chars (integer, optional, 1..M365_TRANSCRIPT_MAX_CHARS,
29
+ * default M365_TRANSCRIPT_MAX_CHARS) — max chars to
30
+ * return in this response
16
31
  *
17
- * Output: plain text transcript content (VTT markup removed) plus
18
- * metadata (meeting_id, transcript_id, char_count, truncated).
32
+ * Output: plain-text transcript slice (VTT markup removed) plus
33
+ * metadata (meeting_id, transcript_id, offset, char_count,
34
+ * next_offset, total_char_count, truncated, vtt_truncated).
19
35
  */
20
36
  import type { Tool } from "../types/tool.js";
21
37
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"get_transcript.d.ts","sourceRoot":"","sources":["../../src/tools/get_transcript.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,KAAK,EAAE,IAAI,EAA6C,MAAM,kBAAkB,CAAC;AA0BxF;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAkB5C;AAkED,eAAO,MAAM,iBAAiB,EAAE,IAAgD,CAAC"}
1
+ {"version":3,"file":"get_transcript.d.ts","sourceRoot":"","sources":["../../src/tools/get_transcript.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAKH,OAAO,KAAK,EAAE,IAAI,EAA6C,MAAM,kBAAkB,CAAC;AAmExF;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAkB5C;AA6GD,eAAO,MAAM,iBAAiB,EAAE,IAAgD,CAAC"}
@@ -3,26 +3,66 @@
3
3
  *
4
4
  * Fetch the text content of a Teams meeting transcript. The Graph API
5
5
  * returns VTT (WebVTT subtitle format); this tool strips the timing
6
- * markers and returns clean readable text, capped at 30 000 chars.
6
+ * markers and returns clean readable text.
7
7
  *
8
8
  * Required Graph scope: OnlineMeetingTranscript.Read.All (delegated,
9
9
  * admin consent required).
10
10
  *
11
+ * Caps (defense-in-depth bounds, configurable via env):
12
+ * - Raw VTT stream: M365_TRANSCRIPT_MAX_BYTES (default 10 000 000 / 10 MB)
13
+ * - Parsed-text page: M365_TRANSCRIPT_MAX_CHARS (default 200 000 chars)
14
+ *
15
+ * Paging: when a transcript exceeds the per-call char cap, callers
16
+ * iterate by passing the returned `next_offset` back as `offset` on
17
+ * the next call. The Graph content endpoint returns the whole VTT in
18
+ * one blob — there is no server-side paging primitive — so paging is
19
+ * implemented client-side by slicing the parsed text.
20
+ *
11
21
  * Input:
12
- * meeting_id (string, required) — onlineMeeting id from
22
+ * meeting_id (string, required) — onlineMeeting id from
13
23
  * list_meeting_transcripts
14
- * transcript_id (string, required) — transcript id from
24
+ * transcript_id (string, required) — transcript id from
15
25
  * list_meeting_transcripts
26
+ * offset (integer, optional, 0..2_000_000_000, default 0)
27
+ * — character offset into the parsed transcript text
28
+ * max_chars (integer, optional, 1..M365_TRANSCRIPT_MAX_CHARS,
29
+ * default M365_TRANSCRIPT_MAX_CHARS) — max chars to
30
+ * return in this response
16
31
  *
17
- * Output: plain text transcript content (VTT markup removed) plus
18
- * metadata (meeting_id, transcript_id, char_count, truncated).
32
+ * Output: plain-text transcript slice (VTT markup removed) plus
33
+ * metadata (meeting_id, transcript_id, offset, char_count,
34
+ * next_offset, total_char_count, truncated, vtt_truncated).
19
35
  */
20
- import { validateRequiredString } from "../types/validators.js";
21
- const CONTENT_CHAR_CAP = 30_000;
36
+ import { validateRequiredString, validateOptionalInteger } from "../types/validators.js";
37
+ // Defaults are generous enough for multi-hour meetings but still bounded
38
+ // against the audit-S7 whole-file-buffering anti-pattern. Both are
39
+ // overridable via env vars at process start (per-tenant subprocess, so
40
+ // the env is the right knob — no per-call override of the absolute cap).
41
+ const DEFAULT_MAX_VTT_BYTES = 10_000_000; // 10 MB raw VTT (~8h+ of speech)
42
+ const DEFAULT_CONTENT_CHAR_CAP = 200_000; // 200k chars parsed (~2h of speech)
43
+ function parsePositiveInt(raw, fallback) {
44
+ if (raw === undefined || raw === "")
45
+ return fallback;
46
+ const n = Number(raw);
47
+ if (!Number.isInteger(n) || n <= 0)
48
+ return fallback;
49
+ return n;
50
+ }
51
+ // Env reads are intentionally written as literal `process.env.<NAME>` (not
52
+ // via a dynamic-key helper) so the README env-var-accuracy CI gate
53
+ // (handbook anti-pattern S2) can grep them and confirm the documented names
54
+ // are actually wired. See .github/workflows/ci.yml § "README env-var accuracy".
55
+ function getMaxVttBytes() {
56
+ return parsePositiveInt(process.env.M365_TRANSCRIPT_MAX_BYTES, DEFAULT_MAX_VTT_BYTES);
57
+ }
58
+ function getMaxChars() {
59
+ return parsePositiveInt(process.env.M365_TRANSCRIPT_MAX_CHARS, DEFAULT_CONTENT_CHAR_CAP);
60
+ }
22
61
  const definition = {
23
62
  name: "m365-graph:get_transcript",
24
63
  description: "Fetch the text content of a Teams meeting transcript. VTT timing markers " +
25
- "are stripped; returns clean readable text capped at 30 000 chars. " +
64
+ "are stripped; returns clean readable text. Long transcripts can be paged " +
65
+ "via the offset + max_chars inputs (see next_offset in the response). " +
26
66
  "Use list_meeting_transcripts to get the meeting_id and transcript_id. Read-only.",
27
67
  inputSchema: {
28
68
  type: "object",
@@ -35,6 +75,20 @@ const definition = {
35
75
  type: "string",
36
76
  description: "Transcript ID from list_meeting_transcripts.",
37
77
  },
78
+ offset: {
79
+ type: "integer",
80
+ minimum: 0,
81
+ maximum: 2_000_000_000,
82
+ description: "Character offset into the parsed transcript text (default 0). " +
83
+ "Pass the previous response's next_offset to fetch the next page.",
84
+ },
85
+ max_chars: {
86
+ type: "integer",
87
+ minimum: 1,
88
+ description: "Maximum number of transcript characters to return in this response. " +
89
+ "Defaults to and is capped by M365_TRANSCRIPT_MAX_CHARS " +
90
+ "(default 200 000).",
91
+ },
38
92
  },
39
93
  required: ["meeting_id", "transcript_id"],
40
94
  },
@@ -79,6 +133,18 @@ export function parseVtt(vtt) {
79
133
  const handler = async (graph, args) => {
80
134
  const meetingId = validateRequiredString(args.meeting_id, "meeting_id");
81
135
  const transcriptId = validateRequiredString(args.transcript_id, "transcript_id");
136
+ const maxVttBytes = getMaxVttBytes();
137
+ const maxChars = getMaxChars();
138
+ const offset = validateOptionalInteger(args.offset, "offset", {
139
+ min: 0,
140
+ max: 2_000_000_000,
141
+ default: 0,
142
+ });
143
+ const pageChars = validateOptionalInteger(args.max_chars, "max_chars", {
144
+ min: 1,
145
+ max: maxChars,
146
+ default: maxChars,
147
+ });
82
148
  const endpoint = `/me/onlineMeetings/${encodeURIComponent(meetingId)}` +
83
149
  `/transcripts/${encodeURIComponent(transcriptId)}/content`;
84
150
  const rawResponse = await graph
@@ -86,15 +152,17 @@ const handler = async (graph, args) => {
86
152
  .query({ $format: "text/vtt" })
87
153
  .get();
88
154
  // Graph SDK may return a ReadableStream for binary/text content types.
89
- // Cap raw VTT at 500 KB before parsing to bound memory before the output cap.
90
- const MAX_VTT_BYTES = 500_000;
155
+ // Cap raw VTT at maxVttBytes before parsing (audit S7: whole-file
156
+ // buffering bound). We flag `vtt_truncated` so callers know the tail
157
+ // of the *upstream* VTT was not read (distinct from output paging).
91
158
  let vttString;
159
+ let vttTruncated = false;
92
160
  if (rawResponse instanceof ReadableStream) {
93
161
  const reader = rawResponse.getReader();
94
162
  const chunks = [];
95
163
  let totalBytes = 0;
96
164
  let done = false;
97
- while (!done && totalBytes < MAX_VTT_BYTES) {
165
+ while (!done && totalBytes < maxVttBytes) {
98
166
  const { done: d, value } = await reader.read();
99
167
  done = d;
100
168
  if (value) {
@@ -103,16 +171,38 @@ const handler = async (graph, args) => {
103
171
  totalBytes += buf.byteLength;
104
172
  }
105
173
  }
106
- if (!done)
174
+ if (!done) {
175
+ vttTruncated = true;
107
176
  reader.cancel().catch(() => undefined);
108
- vttString = Buffer.concat(chunks).toString("utf-8").slice(0, MAX_VTT_BYTES);
177
+ }
178
+ vttString = Buffer.concat(chunks).toString("utf-8");
179
+ if (vttString.length > maxVttBytes) {
180
+ vttString = vttString.slice(0, maxVttBytes);
181
+ vttTruncated = true;
182
+ }
109
183
  }
110
184
  else {
111
- vttString = String(rawResponse ?? "").slice(0, MAX_VTT_BYTES);
185
+ const s = String(rawResponse ?? "");
186
+ if (s.length > maxVttBytes) {
187
+ vttString = s.slice(0, maxVttBytes);
188
+ vttTruncated = true;
189
+ }
190
+ else {
191
+ vttString = s;
192
+ }
112
193
  }
113
- const text = parseVtt(vttString);
114
- const truncated = text.length > CONTENT_CHAR_CAP;
115
- const content = truncated ? text.slice(0, CONTENT_CHAR_CAP) : text;
194
+ const fullText = parseVtt(vttString);
195
+ const totalChars = fullText.length;
196
+ // Slice the requested page out of the parsed text.
197
+ const sliceStart = Math.min(offset, totalChars);
198
+ const sliceEnd = Math.min(sliceStart + pageChars, totalChars);
199
+ const content = fullText.slice(sliceStart, sliceEnd);
200
+ const nextOffset = sliceEnd < totalChars ? sliceEnd : null;
201
+ // `truncated` retained for backward-compat with v0.2.x callers: true when
202
+ // the returned slice does not reach the end of the (in-memory) parsed
203
+ // text. Combined with `vtt_truncated`, callers can distinguish a
204
+ // page-of-many response from a hard upstream-byte loss.
205
+ const truncated = nextOffset !== null;
116
206
  return {
117
207
  content: [
118
208
  {
@@ -120,8 +210,12 @@ const handler = async (graph, args) => {
120
210
  text: JSON.stringify({
121
211
  meeting_id: meetingId,
122
212
  transcript_id: transcriptId,
213
+ offset: sliceStart,
123
214
  char_count: content.length,
215
+ next_offset: nextOffset,
216
+ total_char_count: totalChars,
124
217
  truncated,
218
+ vtt_truncated: vttTruncated,
125
219
  transcript: content,
126
220
  }, null, 2),
127
221
  },
@@ -1 +1 @@
1
- {"version":3,"file":"get_transcript.js","sourceRoot":"","sources":["../../src/tools/get_transcript.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"get_transcript.js","sourceRoot":"","sources":["../../src/tools/get_transcript.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.2.1",
3
+ "version": "0.3.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",