@littlebearapps/outlook-assistant 3.13.0 → 3.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/.env.example +30 -3
  2. package/README.md +67 -27
  3. package/advanced/index.js +44 -174
  4. package/auth/auth-errors.js +23 -1
  5. package/auth/oauth-server.js +7 -1
  6. package/auth/token-manager.js +7 -3
  7. package/auth/token-storage.js +28 -30
  8. package/auth/tools.js +61 -82
  9. package/calendar/attendees.js +36 -0
  10. package/calendar/cancel.js +9 -25
  11. package/calendar/create.js +42 -48
  12. package/calendar/decline.js +10 -25
  13. package/calendar/delete.js +10 -25
  14. package/calendar/index.js +20 -37
  15. package/calendar/list.js +4 -16
  16. package/calendar/preview.js +461 -0
  17. package/calendar/update.js +55 -83
  18. package/categories/index.js +68 -265
  19. package/config.js +29 -1
  20. package/contacts/index.js +72 -128
  21. package/email/attachments.js +43 -125
  22. package/email/conversations.js +44 -78
  23. package/email/delta.js +69 -46
  24. package/email/draft.js +170 -103
  25. package/email/export.js +145 -110
  26. package/email/folder-utils.js +3 -2
  27. package/email/headers.js +11 -49
  28. package/email/index.js +86 -110
  29. package/email/list.js +4 -17
  30. package/email/mail-tips.js +86 -57
  31. package/email/mark-as-read.js +13 -49
  32. package/email/mime.js +39 -51
  33. package/email/read.js +16 -50
  34. package/email/search.js +47 -87
  35. package/email/send.js +82 -48
  36. package/folder/create.js +6 -25
  37. package/folder/delete.js +117 -38
  38. package/folder/index.js +19 -17
  39. package/folder/list.js +5 -17
  40. package/folder/move.js +13 -42
  41. package/folder/resolve.js +11 -6
  42. package/folder/stats.js +18 -27
  43. package/index.js +39 -45
  44. package/llms-install.md +22 -4
  45. package/llms.txt +20 -11
  46. package/outlook-auth-server.js +10 -3
  47. package/package.json +4 -1
  48. package/request-handler.js +217 -116
  49. package/rules/create.js +28 -71
  50. package/rules/index.js +52 -93
  51. package/rules/list.js +7 -19
  52. package/rules/rule-builder.js +59 -22
  53. package/rules/update.js +27 -61
  54. package/server.js +41 -0
  55. package/settings/index.js +162 -145
  56. package/tools.js +30 -0
  57. package/utils/field-presets.js +4 -2
  58. package/utils/graph-api.js +65 -22
  59. package/utils/logger.js +251 -0
  60. package/utils/mock-data.js +91 -2
  61. package/utils/read-only.js +59 -0
  62. package/utils/response-formatter.js +54 -15
  63. package/utils/risk-classes.js +324 -0
  64. package/utils/safe-write.js +372 -6
  65. package/utils/safety.js +247 -42
  66. package/utils/server-instructions.js +73 -0
  67. package/utils/tool-error.js +33 -0
package/index.js CHANGED
@@ -38,15 +38,23 @@ Key environment variables:
38
38
  OUTLOOK_AUTH_METHOD device-code (default) | browser
39
39
  OUTLOOK_AUTH_AUDIENCE common | consumers | organizations | <tenant-guid>
40
40
  OUTLOOK_SHARED_MAILBOX Opt in to shared mailboxes: read | true (work/school only)
41
+ OUTLOOK_READ_ONLY Set to "true" to refuse every tool call that would change,
42
+ send or delete anything (reads and sign-in still work)
41
43
  OUTLOOK_ALLOWED_RECIPIENTS Comma-separated recipient allowlist
42
44
  OUTLOOK_MAX_EMAILS_PER_SESSION Default cap per session for every rate-limited tool
43
- (send-email, draft, manage-rules); 0 or unset = no cap
45
+ (send-email, draft, create-event, manage-rules).
46
+ Unset or empty = no cap. 0 BLOCKS those tools; so does
47
+ any value that isn't a whole number (fails closed)
44
48
  OUTLOOK_MAX_<TOOL>_PER_SESSION Per-tool cap overriding the default, tool name in upper
45
49
  case with _ for -, e.g. OUTLOOK_MAX_SEND_EMAIL_PER_SESSION
50
+ (also covers draft action=send); 0 blocks that tool
46
51
  OUTLOOK_DEFAULT_TIMEZONE IANA timezone for event times (default Australia/Melbourne)
47
52
  OUTLOOK_IMMUTABLE_IDS Set to "true" for message IDs that survive folder moves
48
53
  OUTLOOK_SEARCH_SCAN_LIMIT Local search fallback window (default 500, max 5000)
49
54
  OUTLOOK_REQUEST_TIMEOUT_MS Graph request inactivity timeout (default 60000)
55
+ OUTLOOK_DEBUG Set to "true" for detailed stderr logs (addresses redacted)
56
+ OUTLOOK_EXPORT_DIR Extra folder export/attachment downloads may write to
57
+ (besides the temp directory, ~/Downloads, ~/Documents)
50
58
  USE_TEST_MODE Set to "true" to run against mock data
51
59
 
52
60
  Documentation: https://github.com/littlebearapps/outlook-assistant`;
@@ -74,33 +82,40 @@ Documentation: https://github.com/littlebearapps/outlook-assistant`;
74
82
  process.exit(0);
75
83
  }
76
84
 
77
- const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
78
85
  const {
79
86
  StdioServerTransport,
80
87
  } = require('@modelcontextprotocol/sdk/server/stdio.js');
81
88
  const config = require('./config');
82
- const { createRequestHandler } = require('./request-handler');
83
-
84
- // Import module tools
85
- const { authTools, setToolCount } = require('./auth');
86
- const { calendarTools } = require('./calendar');
87
- const { emailTools } = require('./email');
88
- const { folderTools } = require('./folder');
89
- const { rulesTools } = require('./rules');
90
- const { contactsTools } = require('./contacts');
91
- const { categoriesTools } = require('./categories');
92
- const { settingsTools } = require('./settings');
93
- const { advancedTools } = require('./advanced');
89
+ const { createServer } = require('./server');
90
+
91
+ const { setToolCount } = require('./auth');
92
+ const { TOOLS } = require('./tools');
93
+ const { isDebugEnabled } = require('./utils/logger');
94
+ const {
95
+ blockedTools,
96
+ resolveSessionLimit,
97
+ RATE_LIMITED_TOOLS,
98
+ } = require('./utils/safety');
94
99
 
95
100
  // Log startup information
96
- console.error(`STARTING ${config.SERVER_NAME.toUpperCase()} MCP SERVER`);
101
+ console.error(
102
+ `STARTING ${config.SERVER_NAME.toUpperCase()} MCP SERVER v${config.SERVER_VERSION}`
103
+ );
97
104
  console.error(`Test mode is ${config.USE_TEST_MODE ? 'enabled' : 'disabled'}`);
105
+ if (isDebugEnabled()) {
106
+ console.error(
107
+ 'Debug logging is on (OUTLOOK_DEBUG): stderr includes search terms, subjects and Graph errors, with addresses and IDs redacted.'
108
+ );
109
+ }
98
110
 
99
111
  // F-1 / F-48: warn at startup when safety belts are unset. Mirrors the
100
112
  // warning surfaced by `auth action=about`. Visible to operators reading
101
113
  // stderr; AI clients reading the JSON-RPC stream are unaffected.
114
+ const sessionLimitSet = Object.keys(RATE_LIMITED_TOOLS).some(
115
+ (tool) => resolveSessionLimit(tool).limit !== null
116
+ );
102
117
  if (
103
- !process.env.OUTLOOK_MAX_EMAILS_PER_SESSION &&
118
+ !sessionLimitSet &&
104
119
  !process.env.OUTLOOK_ALLOWED_RECIPIENTS &&
105
120
  !config.USE_TEST_MODE
106
121
  ) {
@@ -108,39 +123,18 @@ if (
108
123
  '⚠ Safety belts not configured. Consider setting OUTLOOK_MAX_EMAILS_PER_SESSION and OUTLOOK_ALLOWED_RECIPIENTS in your .mcp.json env block for safer AI-assisted sending. See `auth action=about` for details.'
109
124
  );
110
125
  }
111
-
112
- // Combine all tools
113
- const TOOLS = [
114
- ...authTools,
115
- ...calendarTools,
116
- ...emailTools,
117
- ...folderTools,
118
- ...rulesTools,
119
- ...contactsTools,
120
- ...categoriesTools,
121
- ...settingsTools,
122
- ...advancedTools,
123
- ];
126
+ // #302: say plainly when a session limit of 0 switches a tool off.
127
+ const blocked = blockedTools();
128
+ if (blocked.length > 0) {
129
+ console.error(
130
+ `Session limits block ${blocked.join(', ')} (0 or an unreadable value). Unset the setting for no limit. See \`auth action=about\`.`
131
+ );
132
+ }
124
133
 
125
134
  // Set dynamic tool count for auth about handler
126
135
  setToolCount(TOOLS.length);
127
136
 
128
- // Create server with tools capabilities
129
- const server = new Server(
130
- { name: config.SERVER_NAME, version: config.SERVER_VERSION },
131
- {
132
- capabilities: {
133
- tools: TOOLS.reduce((acc, tool) => {
134
- acc[tool.name] = {};
135
- return acc;
136
- }, {}),
137
- },
138
- }
139
- );
140
-
141
- // Handle all requests. Dispatch + error-shaping logic lives in
142
- // request-handler.js so it is unit-testable without starting the transport.
143
- server.fallbackRequestHandler = createRequestHandler(TOOLS);
137
+ const server = createServer(TOOLS);
144
138
 
145
139
  // Make the script executable
146
140
  process.on('SIGTERM', () => {
package/llms-install.md CHANGED
@@ -18,6 +18,16 @@ Add to your MCP client configuration:
18
18
  }
19
19
  ```
20
20
 
21
+ ## Plugin Install (Claude Code, GitHub Copilot CLI, Cursor)
22
+
23
+ The plugin in `plugins/outlook-assistant/` runs a pinned server version and adds the `using-outlook-assistant` skill and a safety hook that asks the user before sends, deletes, rules and automatic replies.
24
+
25
+ - Claude Code: `claude plugin marketplace add littlebearapps/outlook-assistant`, then `claude plugin install outlook-assistant@littlebearapps`. The plugin asks for its settings (client ID, read-only mode, confirmation level and others) when enabled.
26
+ - GitHub Copilot CLI: `copilot plugin marketplace add littlebearapps/outlook-assistant`, then `copilot plugin install outlook-assistant@littlebearapps`. No plugin settings: the user gives the client ID at sign-in, and the hook's confirmation level comes from the `OUTLOOK_CONFIRM_LEVEL` environment variable (`outward`, `all-writes` or `off`).
27
+ - Cursor (v3.14.0 plugin or later): loads the folder as a Cursor plugin (`.cursor-plugin/plugin.json`); in Cursor CLI, pass it with `--plugin-dir`. The v3.13.0 plugin fails sign-in in Cursor with `AADSTS900023`; use the manual config instead.
28
+
29
+ Client limits (for example, Cursor's prompt doesn't show the hook's reason): `docs/how-to/getting-started/supported-clients.md`.
30
+
21
31
  ## Prerequisites
22
32
 
23
33
  1. **Node.js 18.18 or newer** must be installed
@@ -71,14 +81,19 @@ Add these to the same `env` block if needed:
71
81
  |----------|---------|
72
82
  | `OUTLOOK_AUTH_AUDIENCE` | `consumers` for Azure apps registered as personal-accounts-only (fixes `AADSTS9002331`); `organizations` or a tenant GUID for work-only apps. Default `common` |
73
83
  | `OUTLOOK_DEFAULT_TIMEZONE` | IANA timezone for calendar times (default `Australia/Melbourne`) |
74
- | `OUTLOOK_MAX_EMAILS_PER_SESSION` | Default per-session cap for `send-email`, `draft` and `manage-rules` (override one tool with `OUTLOOK_MAX_<TOOL>_PER_SESSION`, e.g. `OUTLOOK_MAX_SEND_EMAIL_PER_SESSION`) |
75
- | `OUTLOOK_ALLOWED_RECIPIENTS` | Comma-separated allowlist of recipient domains/addresses |
84
+ | `OUTLOOK_MAX_EMAILS_PER_SESSION` | Default per-session cap, counted separately per tool, for `send-email` (including `draft` send), `draft` create/update/reply/reply-all/forward, `manage-rules` and `create-event` (override one tool with `OUTLOOK_MAX_<TOOL>_PER_SESSION`, e.g. `OUTLOOK_MAX_SEND_EMAIL_PER_SESSION`). Unset = no limit; `0` blocks the tool |
85
+ | `OUTLOOK_ALLOWED_RECIPIENTS` | Comma-separated allowlist of recipient domains/addresses for sends, drafts, rule forwards and event attendees |
86
+ | `OUTLOOK_READ_ONLY` | `true` refuses every tool call that would change something (sending, drafts, moves, deletes, rules, settings, file writes), dry runs included; reads and sign-in still work |
76
87
  | `OUTLOOK_SHARED_MAILBOX` | Opt-in shared-mailbox support, work/school accounts only: `read` or `true` (read and organise). Also add `Mail.Read.Shared` (and `Mail.ReadWrite.Shared` for `true`) in Azure, restart, then run `auth` with `action=authenticate` and `force=true` |
77
88
  | `OUTLOOK_SEARCH_SCAN_LIMIT` | Messages scanned by the local search fallback on personal accounts (default 500, max 5000) |
89
+ | `OUTLOOK_EXPORT_DIR` | Extra folder `export` and attachment downloads may write to (besides the temp directory, `~/Downloads` and `~/Documents`) |
78
90
  | `OUTLOOK_REQUEST_TIMEOUT_MS` | Per-attempt Graph inactivity timeout in milliseconds (default 60000); not an overall deadline |
91
+ | `OUTLOOK_DEBUG` | `true` for detailed stderr logs while troubleshooting (addresses and IDs redacted). Off by default: one line per tool call, no arguments |
79
92
 
80
93
  Run `npx @littlebearapps/outlook-assistant --help` for the full list of environment variables.
81
94
 
95
+ `OUTLOOK_CONFIRM_LEVEL` is not a server variable: the plugin's safety hook reads it from the client's environment in GitHub Copilot, VS Code and Cursor. Don't put it in the server's `env` block.
96
+
82
97
  ## Configuration Files by Client
83
98
 
84
99
  ### Claude Desktop
@@ -86,9 +101,12 @@ File: `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
86
101
 
87
102
  ### Claude Code
88
103
  ```bash
89
- claude mcp add outlook -- npx @littlebearapps/outlook-assistant
104
+ claude mcp add outlook -e OUTLOOK_CLIENT_ID=<user-must-provide> -- npx -y @littlebearapps/outlook-assistant
90
105
  ```
91
106
 
107
+ ### VS Code / GitHub Copilot
108
+ File: `.vscode/mcp.json` in your project root, or the user `mcp.json` (Command Palette → **MCP: Open User Configuration**). VS Code uses a top-level `servers` key instead of `mcpServers`, with `"type": "stdio"` on the entry.
109
+
92
110
  ### Cursor
93
111
  File: `.cursor/mcp.json` in your project root
94
112
 
@@ -111,5 +129,5 @@ After authentication, test with:
111
129
  | Device code "invalid_client" | Enable "Allow public client flows" in Azure → Authentication → Advanced settings |
112
130
  | "Shared-mailbox support is turned off" | Set `OUTLOOK_SHARED_MAILBOX`, restart, and re-authenticate with `force=true` (work/school accounts only) |
113
131
  | "EADDRINUSE :3333" | Run `npx kill-port 3333` then restart auth server |
114
- | Empty API responses | Run `auth` tool with `action=status` to check token |
132
+ | "Authentication required." | Sign in with `auth` `action=authenticate`; `action=status` shows whether a token is saved |
115
133
  | Search returns no results (personal account) | Use `from`, `subject`, `to` filters instead of `query` |
package/llms.txt CHANGED
@@ -26,17 +26,23 @@ Built by [Little Bear Apps](https://littlebearapps.com).
26
26
  - **Progressive search**: Automatically falls back through 4 search strategies when Microsoft's `$search` API is unavailable (personal accounts) — most Graph API wrappers fail silently. Explicit "no results" messaging instead of unfiltered fallback, and `_meta.searchMetadata` reports which strategy answered plus any filter that could not be honoured (`droppedFilters`), so a partially-applied search can never pass as a complete one. Field-scoped `$search` expressions (`from:`/`to:`/`subject:`), which personal accounts reject outright, are translated to equivalent OData filters and retried. Cross-folder search (`searchAllFolders`) reliably returns a superset of inbox results.
27
27
  - **Remote-friendly auth**: Device code flow (default) — no auth server, no port forwarding, no SSH tunnels. State persists across MCP server restarts. Works from Untether, mosh, SSH, and headless environments.
28
28
  - **Email forensics**: Built-in header analysis for DKIM, SPF, DMARC authentication, delivery chains, and spam scores — useful for phishing investigation and compliance
29
- - **Delta sync**: Incremental inbox monitoring — returns only new, modified, and deleted emails since last check, with tokens for continuous polling
29
+ - **Delta sync**: Incremental inbox monitoring — returns only new, modified, and deleted emails since last check, with tokens for continuous polling; every page is labelled initial or incremental (`_meta.syncType`)
30
30
  - **Batch operations**: Flag, move, export, or categorise multiple emails in a single tool call; search-driven export for batch archiving without collecting IDs
31
31
  - **Pre-send intelligence**: Check recipients for out-of-office, mailbox full, delivery restrictions, and moderation before sending — no other Outlook MCP server offers this
32
32
  - **Compound automation**: Rules + categories + nested folders (addressable by path or ID) + Focused Inbox for complete inbox management in one conversation
33
33
 
34
34
  ## Safety & Token Efficiency
35
35
 
36
- - **MCP safety annotations** on all 22 tools — AI clients auto-approve reads and prompt for destructive operations
37
- - **Send-email protections**: pre-send mail tips, dry-run preview, session rate limiting, recipient allowlist
38
- - **Rule protections**: dry-run preview on create/update, rate limiting, recipient allowlist on forward/redirect, no permanent-delete action
39
- - **Input and file hardening**: IDs with `.`/`..` path segments refused, the access token only ever sent to `graph.microsoft.com`, attachment downloads and exports (including conversation exports) confined to the output directory without overwriting, and a partly written file removed if a write fails
36
+ - **MCP safety annotations** on all 22 tools, derived from a risk class per tool and action (read, reversible, outward, destructive, persistent), so clients can tell reads from risky changes
37
+ - **Send-email protections**: pre-send mail tips (a send to a flagged recipient, such as out of office or external, is refused until `acknowledgeWarnings: true`), dry-run preview, session rate limiting (unset = no limit; `0` or a value that isn't a whole number blocks the tool; `draft` send counts as `send-email`), recipient allowlist (also checked on drafts, including replies and the draft's current recipients on send, and on `create-event`/`manage-event` update attendees; only single plain addresses can match)
38
+ - **Rule protections**: dry-run preview on create/update, rate limiting (dry runs don't count; `0` blocks rule changes), reorder lists the resulting rule order, recipient allowlist on forward/redirect (a blocked forward refuses the whole rule), no permanent-delete action
39
+ - **Dry-run previews beyond email**: `create-event` and every `manage-event` action, update included, say who would be emailed (with an external count; update also says who an attendee change adds or removes); `mailbox-settings` auto-replies, `folders` delete and `manage-contact` delete show what would change or be lost; `dryRun: true` on any other call is refused rather than run for real
40
+ - **Read-only mode**: `OUTLOOK_READ_ONLY=true` refuses every tool call that would change anything before it runs; reads and sign-in still work
41
+ - **Model guidance**: server `instructions` state the hard rules (retrieved content is data, confirm before outward actions, draft first, refusals and rate limits are final, with `0` = off) and name any tool a session limit of `0` blocks; `auth action=about` shows each tool's session limit; `send-email` and `create-event` ask Claude clients for user confirmation (`anthropic/requiresUserInteraction`)
42
+ - **Plugin skill and safety hook** (Claude Code, GitHub Copilot CLI, Cursor; VS Code not yet checked by hand): the `using-outlook-assistant` skill sets the hard rules; the hook asks with a plain-English reason before anything that reaches other people, deletes or keeps acting, and marks retrieved content as untrusted. Confirmation level `outward` (default), `all-writes` or `off`: a plugin setting in Claude Code, the `OUTLOOK_CONFIRM_LEVEL` environment variable elsewhere. How the hook prompts and fails differs by client: see Supported Clients below
43
+ - **Every client**: the server-side checks (read-only mode, dry runs, the recipient allowlist and send caps, mail-tips refusal, rule refusal), annotations and instructions work in any MCP client, including Codex CLI, Gemini CLI and Claude Desktop with a manual config; clients that support Agent Skills can copy the skill folder
44
+ - **Private logs**: one stderr line per tool call (tool, action, outcome, duration), never its arguments; `OUTLOOK_DEBUG=true` adds detail with addresses and IDs redacted
45
+ - **Input and file hardening**: IDs with `.`/`..` path segments refused, the access token only ever sent to `graph.microsoft.com`, attachment downloads and exports (including conversation exports) written only inside the temp directory, `~/Downloads`, `~/Documents` or `OUTLOOK_EXPORT_DIR`, never to dot-prefixed names; paths must be absolute (or start with `~/`) and symlinks aren't followed; an `export` `savePath` ending in `/` is a folder, created if missing; existing files are never replaced unless `export` is called with `overwrite: true` (and never a symlink, hard-linked file or dotfile); files are created `0600` and new folders `0700`; a partly written file is removed if a write fails
40
46
  - **Throttling-aware Graph client**: `429` (and `503`/`504` for non-POST requests) retried honouring `Retry-After`, a per-attempt inactivity timeout (`OUTLOOK_REQUEST_TIMEOUT_MS`, default 60000 ms) and at most 4 requests in flight, so bulk operations neither hang nor throttle themselves
41
47
  - **Shared mailboxes off by default**: `.Shared` scopes are requested only when `OUTLOOK_SHARED_MAILBOX` is set (`read` keeps shared access read-only)
42
48
  - **Token-optimised**: 22 tools instead of 55 saves ~11,000 tokens per turn (~64% reduction), improving AI accuracy and context efficiency
@@ -58,18 +64,18 @@ Built by [Little Bear Apps](https://littlebearapps.com).
58
64
  }
59
65
  ```
60
66
 
61
- `OUTLOOK_CLIENT_SECRET` is only needed for the browser sign-in flow; the default device-code flow uses the client ID alone. Claude Code users can instead install the plugin: `claude plugin marketplace add littlebearapps/outlook-assistant`, then `claude plugin install outlook-assistant@littlebearapps`. Requires an Azure app registration with Microsoft Graph delegated permissions. See README for full setup.
67
+ `OUTLOOK_CLIENT_SECRET` is only needed for the browser sign-in flow; the default device-code flow uses the client ID alone. Claude Code users can instead install the plugin (server, skill and safety hook): `claude plugin marketplace add littlebearapps/outlook-assistant`, then `claude plugin install outlook-assistant@littlebearapps`. The same plugin folder also loads in GitHub Copilot CLI (VS Code not yet checked by hand) and, from v3.14.0, Cursor. Requires an Azure app registration with Microsoft Graph delegated permissions. See README for full setup.
62
68
 
63
69
  ## Tool Categories
64
70
 
65
71
  - **Authentication (1 tool)**: `auth` — status, authenticate (device code by default), device-code-complete, about (version, granted scopes, shared-mailbox status)
66
72
  - **Email (8 tools)**: `search-emails`, `read-email`, `send-email`, `draft`, `update-email`, `attachments`, `export`, `get-mail-tips`
67
- - **Calendar (3 tools)**: `list-events` (`startAfter`, `startBefore`, `subject` filters), `create-event`, `manage-event` (update, decline, cancel, delete)
73
+ - **Calendar (3 tools)**: `list-events` (`startAfter`, `startBefore`, `subject` filters), `create-event` (`dryRun`; retry-safe `transactionId`), `manage-event` (update, decline, cancel, delete; `dryRun` on all)
68
74
  - **Contacts (2 tools)**: `manage-contact`, `search-people`
69
75
  - **Folders (1 tool)**: `folders` — list, create, move, stats, delete; folders addressable by nested path (`Parent/Child`) or ID
70
- - **Rules (1 tool)**: `manage-rules` — list, create, update, reorder, delete
76
+ - **Rules (1 tool)**: `manage-rules` — list, create, update, reorder, delete (12 conditions including `hasAttachments`, 9 actions, `except*` exceptions)
71
77
  - **Categories (3 tools)**: `manage-category`, `apply-category`, `manage-focused-inbox`
72
- - **Settings (1 tool)**: `mailbox-settings` — get, set auto-replies, set working hours
78
+ - **Settings (1 tool)**: `mailbox-settings` — get, set auto-replies (`dryRun`; schedules shown as UTC plus a labelled local time), set working hours
73
79
  - **Advanced (2 tools)**: `access-shared-mailbox` (messages, `listFolders`, `folderId`, nested folder paths), `find-meeting-rooms`
74
80
 
75
81
  ## Documentation
@@ -77,12 +83,15 @@ Built by [Little Bear Apps](https://littlebearapps.com).
77
83
  - [README](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/README.md): Full documentation including setup, Azure configuration, and usage
78
84
  - [Tools Reference](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/docs/quickrefs/tools-reference.md): All 22 tools with parameters and safety annotations
79
85
  - [Connect Outlook to Claude](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/docs/how-to/getting-started/connect-outlook-to-claude.md): Step-by-step setup guide for Claude Desktop / Claude Code
86
+ - [Supported Clients](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/docs/how-to/getting-started/supported-clients.md): What each client gets — plugin, skill, safety hook and server-side checks — for Claude Code, GitHub Copilot, Cursor, Codex CLI, Gemini CLI and Claude Desktop
87
+ - [Plugin README](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/plugins/outlook-assistant/README.md): Plugin settings, the skill and the safety hook in each client
88
+ - [Cross-client Matrix](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/docs/cross-client-matrix.md): Which clients and models have been checked against the safety scenarios, and when
80
89
  - [Verify Your Connection](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/docs/how-to/getting-started/verify-your-connection.md): Test and troubleshoot the connection after installation
81
90
  - [Azure Setup](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/docs/guides/azure-setup.md): Azure app registration and API permissions walkthrough
82
91
  - [Troubleshooting](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/docs/troubleshooting.md): Known errors and fixes — auth, search, export, shared mailboxes
83
92
  - [FAQ](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/docs/faq/faq.md): Frequently asked questions — install, accounts, permissions, tokens, send safety, updates, uninstall (also at <https://littlebearapps.com/help/outlook-assistant/faq/>)
84
93
  - [CLAUDE.md](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/CLAUDE.md): Quick reference for development
85
94
  - [CONTRIBUTING](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/CONTRIBUTING.md): Contribution guidelines
86
- - [CHANGELOG](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/CHANGELOG.md): Version history (current: v3.13.0 — marketplace plugin bundle for Claude Code, GitHub Copilot and Cursor; Azure client ID can be given at sign-in and saved locally; client secret documented as browser-flow only)
87
- - [ROADMAP](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/ROADMAP.md): Active milestones (v3.12.x tool description audit, the patch-release fix queue, v3.8.x carry-over, v3.13.0+ new Graph APIs)
95
+ - [CHANGELOG](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/CHANGELOG.md): Version history (current: v3.14.1 — security and safety release: read-only mode, server instructions, more dry-run previews, mail-tips refusal, the plugin skill and a safety hook for Claude Code, GitHub Copilot and Cursor, and fixes for three advisories covering the recipient allowlist, export file writes and dry runs)
96
+ - [ROADMAP](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/ROADMAP.md): Active milestones (v3.14.1 live-test fixes; v3.15.0 structured outputs and paging; v4.0.0 MCP 2026-07-28 and server-side confirmation; the patch-release fix queue; v3.8.x carry-over; v3.16.0+ new Graph APIs)
88
97
  - [SECURITY](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/SECURITY.md): Security policy (report vulnerabilities privately via GitHub private vulnerability reporting; acknowledged within 7 days), token handling, and MCP safety controls
@@ -35,6 +35,9 @@ require('dotenv').config();
35
35
 
36
36
  // Import scopes and token path from central config to stay in sync
37
37
  const { AUTH_CONFIG: centralAuth } = require('./config');
38
+ // Console output never includes the secret, the CSRF state or an auth code,
39
+ // and Azure error text is redacted (it can carry the user's address) (#278).
40
+ const { redact } = require('./utils/logger');
38
41
 
39
42
  // Log to console
40
43
  console.log('Starting Outlook Authentication Server');
@@ -64,7 +67,9 @@ const server = http.createServer((req, res) => {
64
67
 
65
68
  if (query.error) {
66
69
  console.error(
67
- `Authentication error: ${query.error} - ${query.error_description}`
70
+ redact(
71
+ `Authentication error: ${query.error} - ${query.error_description}`
72
+ )
68
73
  );
69
74
  res.writeHead(400, SECURITY_HEADERS);
70
75
  res.end(`
@@ -147,7 +152,7 @@ const server = http.createServer((req, res) => {
147
152
  `);
148
153
  })
149
154
  .catch((error) => {
150
- console.error(`Token exchange error: ${error.message}`);
155
+ console.error(redact(`Token exchange error: ${error.message}`));
151
156
  res.writeHead(500, SECURITY_HEADERS);
152
157
  res.end(`
153
158
  <html>
@@ -253,7 +258,9 @@ const server = http.createServer((req, res) => {
253
258
  // Use the audience from config (defaults to "common"; configurable via
254
259
  // OUTLOOK_AUTH_AUDIENCE for personal-only / single-tenant Azure apps).
255
260
  const authUrl = `${AUTH_CONFIG.authorizeEndpoint}?${querystring.stringify(authParams)}`;
256
- console.log(`Redirecting to: ${authUrl}`);
261
+ console.log(
262
+ `Redirecting to Microsoft sign-in: ${AUTH_CONFIG.authorizeEndpoint}`
263
+ );
257
264
 
258
265
  // Redirect to Microsoft's login page
259
266
  res.writeHead(302, { Location: authUrl });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@littlebearapps/outlook-assistant",
3
- "version": "3.13.0",
3
+ "version": "3.14.1",
4
4
  "mcpName": "io.github.littlebearapps/outlook-assistant",
5
5
  "description": "Outlook Assistant — MCP server with 22 tools for email, calendar, contacts, and settings via Microsoft Graph API",
6
6
  "main": "index.js",
@@ -60,6 +60,8 @@
60
60
  "index.js",
61
61
  "config.js",
62
62
  "request-handler.js",
63
+ "server.js",
64
+ "tools.js",
63
65
  "outlook-auth-server.js",
64
66
  "auth/",
65
67
  "calendar/",
@@ -86,6 +88,7 @@
86
88
  "@commitlint/config-conventional": "^20.4.3",
87
89
  "@eslint/js": "^10.0.1",
88
90
  "@modelcontextprotocol/inspector": "^2.8.0",
91
+ "ajv": "^8.20.0",
89
92
  "eslint": "^10.0.2",
90
93
  "globals": "^17.4.0",
91
94
  "husky": "^9.1.7",