Skip to main content
Outlook Assistant · v3.7.3 minor release ·

Outlook Assistant v3.7.3 — E2E Sweep: 25 Real-World Fixes

Outlook Assistant v3.7.3 lands a comprehensive E2E sweep against a live personal Outlook.com mailbox: MCP boundary param coercion, strict unknown-param rejection, file outputDir, ID surfacing, and 20+ targeted bug fixes.

Highlights

Single chokepoint for MCP param coercion

most MCP clients deliver array, boolean, integer, and number params as JSON-encoded strings. v3.7.3 walks each tool's inputSchema once at the dispatch boundary and coerces values into the right JS type. No more 'manage-rules isEnabled silently ignored' or 'update-email ids iterates char-by-char'.

Strict unknown-param rejection

every tool now sets additionalProperties: false at the MCP boundary. typo a param name (verbosity on folders list) and you get an explicit error listing valid params, not silent-ignore. param-name aliases added so canonical and legacy names both work.

File output: outputDir honoured everywhere

attachments download, export target=message, export target=conversation all now respect outputDir. Defaults to os.tmpdir() instead of cwd. Auto-creates the target directory. Deprecated savePath alias kept for back-compat.

Diagnostics that actually diagnose

auth action=about now shows displayName <email> at the top of the block. folders create and manage-rules create return the new ID inline (was missing before). manage-event accept properly documents itself as unsupported on personal Outlook.com instead of failing silently.

What’s new in v3.7.3

This release is the result of a manual end-to-end sweep against a live personal Outlook.com mailbox — every tool, every action permutation, every reasonable param shape. 48 findings filed across 7 GitHub issues (#159 tracker, #160-#165 by theme); 25+ fixes shipped here. v3.7.4 picks up two more (#168, #169) that surfaced in re-verification.

I’ll spare the line-by-line — see the CHANGELOG for the full list. The highlights:

MCP boundary chokepoint

Every MCP client delivers params slightly differently. Some send arrays as JSON strings; some send booleans as "true" / "false"; some send numbers as decimal-formatted strings. Pre-3.7.3, each tool handler tried to deal with this individually, and the work was inconsistent. The visible failures were random: manage-rules isEnabled was silently ignored, update-email ids iterated character-by-character (one call → 400+ Graph errors), apply-category categories array literally didn’t work via MCP at all.

utils/schema-coerce.js handles it now. Single function, walks the tool’s inputSchema, coerces each value, hands the handler real JS types. 36 unit + integration tests covering each coercion path. Add a tool, no extra coercion code needed.

Strict unknown-param rejection

Same idea — additionalProperties: false on every tool’s input schema. Typo a param and you get “Unknown param ‘verbosit’. Valid params: format, count, …” instead of silently ignoring it. Param-name aliases let backwards-compatible names continue to work (manage-event takes id or eventId; manage-rules takes displayName to match Graph’s field name; manage-category takes deprecated set and categoryId; etc.).

File output everywhere

attachments download outputDir, export target=message outputDir, export target=conversation outputDir — all now honour the param. Default to os.tmpdir() rather than the current working directory (which was rarely what callers wanted). Auto-create the target directory if it doesn’t exist. Kept the deprecated savePath alias.

IDs on creates

folders create and manage-rules create previously didn’t surface the new resource’s ID. The agent had to list, find by name, hope the name was unique. v3.7.3 adds **ID**: <id> to the response and surfaces it in _meta.

Identity in auth about

Before: token diagnostics, scopes, expiry, last refresh — no indication of which mailbox. After: displayName <email> at the top of the block via a single GET /me. Surprisingly hard to live without once you have it.

Safety-belt warnings

OUTLOOK_MAX_EMAILS_PER_SESSION and OUTLOOK_ALLOWED_RECIPIENTS are off by default — sensible for tool authors but error-prone if you forget to set them and start sending real email. Server startup now warns when they’re unset and prints a copy-paste snippet. Ships a .mcp.json.example with both pre-wired.

Other notable fixes

  • read-email strips zero-width tracking-pixel chars (U+200B..U+200F, U+2060, U+FEFF) — was bloating tokens by hundreds of chars on Gmail-relayed messages.
  • set-auto-replies enabled=false properly transitions scheduleddisabled (was previously a silent no-op).
  • set-auto-replies enabled=true (no schedule) on personal accounts now warns when Graph silently coerces the request to disabled.
  • manage-contact list uses $count: true and shows “Showing N of M” with a skip: N hint when more pages exist.
  • find-meeting-rooms and get-mail-tips distinguish “feature not available on this account type” from generic permission errors.

This is the largest single release of fixes Outlook Assistant has had. The mailbox sweep was 12 hours of pure regression-finding and the resulting 25-ish fixes are a significant trust upgrade — the small things that used to surprise you no longer surprise you.

Frequently asked questions

What's the chokepoint and why does it matter?
Most MCP clients (Claude Desktop, Claude Code, Codex, etc.) deliver tool params as strings — even when the tool's schema says the param is an array, boolean, integer, or number. Pre-3.7.3 each handler had to coerce its own params, and the work was inconsistent — manage-rules forgot to coerce isEnabled, update-email iterated 'ids' as a string per character producing 400+ Graph errors, apply-category's array shape didn't deserialise correctly. v3.7.3 walks the inputSchema once at the dispatch boundary and coerces every value into the right JS type before the handler sees it. One place to fix means one place that can't drift.
Will additionalProperties: false break my existing setup?
Only if you were sending typo'd params that the tool was silently ignoring. Real param names still work. The strict rejection means typos that previously failed silently now fail loudly with the list of valid params — better feedback for the agent. Legacy aliases were added for the most common renames (manage-event accepts id alongside eventId, manage-rules accepts displayName alongside name to match Graph's field, etc.) so existing scripts that depended on alternate names still work.
What was wrong with auth about previously?
It returned diagnostics — token expiry, scopes, last refresh — but didn't tell you whose mailbox the token was for. v3.7.3 adds a single GET /me round-trip and prints displayName plus email at the top. If you have multiple Outlook accounts and you've forgotten which one the agent is talking to, this is the call that tells you.