@chrischall/office-outlook-mcp 0.6.2 → 0.7.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.
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "metadata": {
9
9
  "description": "MCP server for Outlook / Microsoft 365 — mail, calendar, contacts and tasks via natural language",
10
- "version": "0.6.2"
10
+ "version": "0.7.0"
11
11
  },
12
12
  "plugins": [
13
13
  {
@@ -15,7 +15,7 @@
15
15
  "displayName": "Outlook (Microsoft 365)",
16
16
  "source": "./",
17
17
  "description": "MCP server for Outlook / Microsoft 365 — triage unread mail, reply, answer meeting invites and schedule meetings, plus folders, calendar, contacts and tasks, with confirmation before anything is sent",
18
- "version": "0.6.2",
18
+ "version": "0.7.0",
19
19
  "author": {
20
20
  "name": "Chris Hall"
21
21
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "office-outlook-mcp",
3
3
  "displayName": "Outlook (Microsoft 365)",
4
- "version": "0.6.2",
4
+ "version": "0.7.0",
5
5
  "description": "Outlook / Microsoft 365 for Claude — triage unread mail, reply, answer meeting invites and schedule meetings, plus folders, calendar, contacts and tasks, with confirmation before anything is sent, using your signed-in browser session",
6
6
  "author": {
7
7
  "name": "Chris Hall",
package/README.md CHANGED
@@ -103,11 +103,12 @@ Everything is optional — with nothing set, the server captures from the browse
103
103
  | `OUTLOOK_CAPTURE_TIMEOUT` | Seconds to wait for the tab to make a readable request. Bounds the WHOLE capture, both declared hosts included. Defaults to `30`. |
104
104
  | `OUTLOOK_TOKEN_CACHE` | `false` to stop caching the token between runs. |
105
105
  | `OUTLOOK_TOKEN_FILE` | Path to the cached token. Defaults to `~/.office-outlook-mcp/token.json`. |
106
+ | `OUTLOOK_OUTPUT_DIR` | Absolute directory `outlook_export_messages` and `outlook_export_events` write into. Defaults to `~/Downloads/office-outlook-mcp`. When set, a per-call `dest` must be inside it. See [Bulk export](#bulk-export). |
106
107
 
107
108
  ## Tools
108
109
 
109
110
  **Read** — `outlook_list_folders`, `outlook_list_messages`,
110
- `outlook_get_message`, `outlook_get_unread`, `outlook_list_attachments`,
111
+ `outlook_get_message`, `outlook_list_unread_messages`, `outlook_list_attachments`,
111
112
  `outlook_get_attachment`, `outlook_list_events`, `outlook_get_event`,
112
113
  `outlook_list_calendars`, `outlook_find_meeting_times`,
113
114
  `outlook_get_schedule`, `outlook_get_profile`,
@@ -115,7 +116,7 @@ Everything is optional — with nothing set, the server captures from the browse
115
116
  `outlook_list_categories`, `outlook_list_tasks`
116
117
 
117
118
  **Write** (ask you to confirm first — see [Confirmations](#confirmations)) —
118
- `outlook_send_mail`, `outlook_create_draft`, `outlook_mark_read`,
119
+ `outlook_send_message`, `outlook_create_draft`, `outlook_mark_read`,
119
120
  `outlook_update_message`, `outlook_move_message`, `outlook_create_event`,
120
121
  `outlook_update_event`, `outlook_respond_to_invite`, `outlook_delete_event`,
121
122
  `outlook_reply`.
@@ -146,6 +147,10 @@ what that decision needs in every view: `MyResponse`, `ResponseRequested`,
146
147
  `IsOrganizer`, `IsCancelled`, `Type` (SingleInstance, Occurrence, Exception or
147
148
  SeriesMaster), `ShowAs` and `IsAllDay`, plus `SeriesMasterId` in the full view.
148
149
 
150
+ **Export** — `outlook_export_messages` (mail) and `outlook_export_events`
151
+ (calendar) write JSONL or Markdown files, optionally with attachments, and
152
+ return only where they are; see [Bulk export](#bulk-export).
153
+
149
154
  **Diagnostics** — `outlook_healthcheck`
150
155
 
151
156
  Every read tool takes `view: compact | full | raw`, defaulting to **compact**.
@@ -156,9 +161,10 @@ mailbox time zone, so its preview can name the zone it would book in; that is
156
161
  the one read a preview makes.)
157
162
 
158
163
  Mail and event text is written by other people, so `outlook_list_messages`,
159
- `outlook_get_message`, `outlook_get_unread`, `outlook_get_attachment`,
160
- `outlook_list_events`, `outlook_get_event`, `outlook_find_meeting_times` and
161
- `outlook_get_schedule` wrap every result (all views) in an untrusted-content
164
+ `outlook_get_message`, `outlook_list_unread_messages`, `outlook_get_attachment`,
165
+ `outlook_list_events`, `outlook_get_event`, `outlook_find_meeting_times`,
166
+ `outlook_get_schedule`, `outlook_export_messages` and `outlook_export_events`
167
+ wrap every result (all views) in an untrusted-content
162
168
  envelope — `untrusted_content: true` plus a `note` telling the model to treat
163
169
  the text as data, never instructions (a `view: raw` record that carries its
164
170
  own `untrusted_content`/`note` key is nested under `data`, so it cannot
@@ -173,7 +179,7 @@ before running non-read-only tools — as the real guard on outbound sends.
173
179
 
174
180
  An agent can work through new mail end to end without opening Outlook:
175
181
 
176
- 1. **Read the batch** — `outlook_get_unread` returns the unread messages in a
182
+ 1. **Read the batch** — `outlook_list_unread_messages` returns the unread messages in a
177
183
  folder (default inbox), newest first, each with its plain-text body, in one
178
184
  call. It does **not** mark anything read. Each item has a `kind`: `mail`,
179
185
  `meetingRequest`, `meetingCancelled` or `meetingResponse`; requests and
@@ -198,7 +204,7 @@ An agent can work through new mail end to end without opening Outlook:
198
204
  `outlook_move_message` moves one to another folder.
199
205
  4. **Mark it handled** — `outlook_mark_read` (or `isRead: true` on
200
206
  `outlook_update_message`) on the plain mail you handled, so the next
201
- `outlook_get_unread` returns only what is still new. Answered invites are
207
+ `outlook_list_unread_messages` returns only what is still new. Answered invites are
202
208
  already out of the inbox (see step 2).
203
209
 
204
210
  Replies, forwards, invite responses and new meetings reach other people, so
@@ -208,7 +214,7 @@ each asks you to confirm first — except a reply saved with `draftOnly: true`
208
214
 
209
215
  ## Paging from a time
210
216
 
211
- `outlook_get_unread` and `outlook_list_messages` also page **oldest first**
217
+ `outlook_list_unread_messages` and `outlook_list_messages` also page **oldest first**
212
218
  from a point in time: pass `from` as an ISO 8601 UTC time
213
219
  (`2026-10-01T00:00:00Z`). The result carries `next_from` — pass it back
214
220
  unchanged as `from` for the next page — and `has_more`. To backfill, start
@@ -218,6 +224,70 @@ returns the same position). Messages that share a timestamp are never skipped
218
224
  or repeated across pages, and marking mail read between pages loses nothing.
219
225
  `from` cannot be combined with `nextLink`, `sinceHours`, `search` or `skip`.
220
226
 
227
+ ## Bulk export
228
+
229
+ `outlook_export_messages` exports mail and `outlook_export_events` exports
230
+ the calendar in bulk, thousands of records at a time, and none of their text
231
+ enters the conversation. The server pages the mailbox (or calendar) and writes
232
+ the records to files. The tool returns only a small manifest: where the files
233
+ are, their sizes, the record and attachment counts, the date span, and
234
+ `has_more` plus a `cursor`. Have the agent read the files with shell tools
235
+ (`jq`, `grep`, `rg`, `head`) rather than opening them whole.
236
+
237
+ - **Mail arguments:** `folder` (a well-known name such as `inbox` or
238
+ `sentitems`, or a folder id; `all` exports the whole mailbox; default
239
+ `inbox`), `since` and `until` (ISO 8601), `search` (full-text, spans the
240
+ mailbox). Mail is exported oldest first.
241
+ - **Event arguments:** `since` and `until` (ISO 8601, both required, at most
242
+ two years apart) and `calendar` (a calendar id; default, the default
243
+ calendar). Events come from the calendar view, so a recurring series is
244
+ expanded into its individual occurrences. Times are wall-clock times in the
245
+ mailbox's time zone, named on each record as `time_zone`.
246
+ - **Both:** `format` (`jsonl`, the default, or `markdown`), `attachments`
247
+ (default `false`), `dest`, `cursor`, `max_items` (default 5000, max 50000)
248
+ and `budget_seconds` (default 90, max 600).
249
+ - **Files:** `part-0001.jsonl` holds one JSON record per message (id,
250
+ conversation id, subject, from, to/cc/bcc, dates, flags, categories, web link
251
+ and the full plain-text body). Its first line is an `_export` header that
252
+ names the source, account, arguments and an untrusted-content note.
253
+ An event record carries the id, iCal UID, type and series id, subject,
254
+ start, end, time zone, location, organizer, attendees with their responses,
255
+ your response, show-as, categories, the join link and the full plain-text
256
+ body.
257
+ `format: "markdown"` writes `part-0001.md`, a readable transcript (one
258
+ section per message or event), instead.
259
+ `manifest.json` lists the counts and any errors, and the files: on disk
260
+ every part's files (it is rewritten as each part finishes); in a blob zip
261
+ the files in that zip.
262
+ - **Attachments:** with `attachments: true`, each file attachment of up to
263
+ 50 MB is saved as `attachments/<short id>/<name>` (the name sanitized), and
264
+ the record lists its attachments, each with its relative `path`, or with
265
+ `skipped` and the reason. Attached Outlook items (a forwarded email or
266
+ event), cloud-file links (OneDrive/SharePoint), larger files and failed
267
+ downloads are skipped. One bad attachment never fails the export.
268
+ - **Resuming:** each call stops at `max_items` or `budget_seconds`, whichever
269
+ comes first. While `has_more` is true, pass `cursor` back unchanged. The
270
+ next call continues the same export as `part-0002`, `part-0003` and so on.
271
+ With attachments on, the budget is checked between small groups of
272
+ records, so a stop can fall inside a page; the cursor resumes at the next
273
+ record. If Outlook refuses the credential (including while downloading an
274
+ attachment), or keeps returning 429 after three
275
+ Retry-After waits, the call keeps what it already wrote and returns the
276
+ cursor. Re-authenticate, then resume.
277
+
278
+ Where the files go depends on how the server runs:
279
+
280
+ | mode | when | `location` in the result |
281
+ | --- | --- | --- |
282
+ | `disk` | any local (stdio) install, the default | an **absolute local directory**, `<dir>/outlook-mail-<YYYYMMDD-HHmmss>/` (or `outlook-events-…`); each file entry carries its absolute `path` |
283
+ | `blob` | hosted on mcp-host, which sets both `MCP_BLOB_BASE_URL` and `MCP_BLOB_SIGNING_KEY` | a **signed download link** to one zip per call (`part-NNNN.zip`, which includes `manifest.json`), valid for **1 hour** (`url_expires_at`) |
284
+
285
+ On disk, `<dir>` is the per-call `dest`, else `OUTLOOK_OUTPUT_DIR`, else
286
+ `~/Downloads/office-outlook-mcp`. A `dest` must be inside `OUTLOOK_OUTPUT_DIR`
287
+ when that is set. Otherwise it must be inside `~/Downloads`, `~/Documents` or
288
+ `~/Desktop`. A resumed cursor's directory is checked against the same roots
289
+ again.
290
+
221
291
  ## Confirmations
222
292
 
223
293
  Every write asks you to confirm before anything is sent or changed (except a