| authA | Manage authentication with the Microsoft Graph API. action=status (default) returns the current auth state, refreshing an expired access token while the refresh token is still valid (~90 days); call it first to check before other tools. action=authenticate starts sign-in: method: "device-code" (default, works headlessly) returns a code + URL for the user to visit; method: "browser" uses the local auth server on :3333 (run npm run auth-server first). force: true re-authenticates over an existing valid session. If sign-in reports that OUTLOOK_CLIENT_ID is not configured, ask the user for their Azure Application (client) ID and pass it as clientId. action=device-code-complete finishes device-code sign-in once the browser shows it succeeded. action=about returns server version, configured audience, scope list and other diagnostics. Tokens persist to ~/.outlook-assistant-tokens.json and survive server restarts. |
| list-eventsA | List calendar events for the signed-in user (read-only). By default returns upcoming events (start ≥ now). Optional startAfter, startBefore and subject filters find past, current or specifically-named events; supplying any of them replaces the default "now" lower bound and the filters are AND-ed together. Results are oldest first, except when the search only looks backwards (startBefore without startAfter, or subject alone), where they are newest first. Each event shows its subject, location, start/end, a body preview and its id. Use count (default 10, max 100) to control page size. Each start/end is returned as a canonical UTC ISO-8601 instant (e.g. 2026-04-02T22:00:00.000Z) followed by a labelled local rendering in the configured display timezone (default Australia/Melbourne; override with OUTLOOK_DEFAULT_TIMEZONE) — the UTC value is authoritative, so consumers never have to guess the zone. |
| create-eventA | Create a new calendar event on the signed-in user's default calendar. Returns the created event with its id, webLink, and (if attendees are present) an auto-generated online-meeting URL — attendees receive invitations on save, so pass dryRun: true first to preview who would be invited (and how many are external) without creating anything. When OUTLOOK_ALLOWED_RECIPIENTS is set, every attendee must be allowed or nothing is created. Times use the configured timezone (default Australia/Melbourne; override with OUTLOOK_DEFAULT_TIMEZONE); omit the Z suffix to send local time. Use manage-event action=update to modify an event after creation, or manage-event action=cancel/delete to remove it. Real creates count against the session limit (OUTLOOK_MAX_CREATE_EVENT_PER_SESSION, else OUTLOOK_MAX_EMAILS_PER_SESSION); 0 refuses every create. |
| manage-eventA | Manage an existing calendar event. dryRun: true previews any action without changing or sending anything: who would be emailed, with an external count (update also: who is added or removed, and the PATCH body). action=update edits fields via PATCH (subject, start, end, attendees, body, location, isOnlineMeeting, sensitivity, showAs, importance, categories, reminderMinutesBeforeStart); only fields you pass change. action=decline declines an invitation (optional comment; sendResponse: false declines without notifying the organiser). action=cancel cancels an event you organised and emails attendees. action=delete removes the event from your calendar (Graph documents no guaranteed recovery); deleting a meeting you organised that has attendees still emails them a cancellation, so use cancel with a comment to control that message. Returns the updated event on update; a confirmation otherwise. There is no accept action: accept invitations in the Outlook UI, as Graph's accept verb is unreliable. |
| search-emailsA | Search, list, delta-sync or thread-group emails (read-only); parameters set the mode. No params: recent emails in folder (default inbox). query/from/to/subject/date filters: search, combined as an OData filter. searchExpression (deprecated alias kqlQuery): a raw Graph $search expression. deltaMode: true: current state plus a deltaToken to pass back next time for changes only. groupByConversation: true: conversation threads. conversationId: every message in one thread. internetMessageId: the message with that RFC Message-ID. sharedMailbox (alias email) searches a shared/delegated mailbox, custom folders and nested paths included. Personal Outlook.com accounts have limited $search, so the tool falls back to OData filters and a recent listing automatically; structured filters (from/subject/receivedAfter/hasAttachments/unreadOnly) give cleaner results there. Returns up to count messages (id/subject/from/receivedDateTime/preview); outputVerbosity expands them. |
| read-emailA | Read a single email by id (read-only). Returns subject, from/to/cc, date and the body as Markdown (HTML stripped to text): up to 2,000 characters by default, up to 40,000 with outputVerbosity: full; a cut body ends with a note on how to get the rest. With headersMode: true: returns RFC-822 forensic headers in place of the body (DKIM, SPF, DMARC, Received chain, Message-ID, Authentication-Results) — importantOnly: true for the security-relevant subset, groupByType: true for a category-bucketed view, raw: true for JSON. With includeHeaders: true (non-headers-mode): adds basic headers alongside the body. If the id came from a shared/delegated mailbox (e.g. via search-emails or access-shared-mailbox with sharedMailbox set), you MUST pass the same sharedMailbox (or alias email) here — message IDs are mailbox-scoped, and reading a shared-mailbox id without it fails with 404 ErrorInvalidMailboxItemId. |
| send-emailA | Compose and send an email immediately (destructive: sends external comms). Returns a confirmation. Safety controls: dryRun: true returns the composed message for review without sending; checkRecipients: true runs get-mail-tips first and returns its warnings. If the tips show an out-of-office reply, a full mailbox, a delivery restriction or external recipients, the send is refused until repeated with acknowledgeWarnings: true. Personal Outlook.com accounts return no tips, and no warnings is not proof of delivery. Subject to the session limit (OUTLOOK_MAX_SEND_EMAIL_PER_SESSION, else OUTLOOK_MAX_EMAILS_PER_SESSION; 0 refuses every send) and recipient allowlist (OUTLOOK_ALLOWED_RECIPIENTS) when configured; both refuse before any Graph request. For a review-before-send workflow, use draft (action=create → update → send); a draft can be checked in Outlook before it goes. Comma-separated recipient strings or arrays both accepted. |
| draftA | Draft lifecycle for review-before-send workflows (destructive: covers send and delete). action=create saves a new draft and returns its id (dryRun: true previews without saving; checkRecipients: true runs mail-tips first). action=update patches a draft by id (only fields passed change). action=send sends a draft and counts against the send-email session limit (0 refuses every send). action=delete moves a draft to Recoverable Items (restorable for a limited time). update/send/delete refuse any id that is not an unsent draft. action=reply/reply-all creates a reply draft from a message id (comment prepends text; not with body). action=forward creates a forward draft (needs id and to). The recipient allowlist (OUTLOOK_ALLOWED_RECIPIENTS) applies to create/update/forward, to the draft's current to/cc/bcc on send, and to reply/reply-all, whose draft is deleted if a recipient is not allowed. Returns the draft on create/update/reply/forward; a status on send/delete. |
| update-emailA | Update message state without modifying content (idempotent — safe to retry). action=mark-read/mark-unread sets isRead on a single message by id. action=flag sets a follow-up flag with optional dueDateTime/startDateTime: ISO 8601 with a time, kept as that exact instant when it has Z or a ±hh:mm offset and read in OUTLOOK_DEFAULT_TIMEZONE when it has none; date-only or unparseable values are refused before any change. With only dueDateTime, the start is 09:00 on the due date, or the due time if earlier. action=unflag clears the flag; action=complete marks it done. Flag/unflag/complete take id (single) or ids (batch, updated one at a time: one PATCH each, not Graph $batch). sharedMailbox (alias email) updates messages in a shared/delegated mailbox (default: the signed-in account; needs Mail.ReadWrite.Shared and delegate access). Returns a status per message. |
| attachmentsA | Inspect or retrieve email attachments. action=list (default) returns metadata for all attachments on messageId (id, name, contentType, size, isInline) — read-only. action=view returns inline content for text/JSON/XML attachments via attachmentId; binary types require download. action=download saves the attachment under a new, unique name in outputDir (default system temp directory, auto-created; must be inside the temp directory, ~/Downloads, ~/Documents or OUTLOOK_EXPORT_DIR) and returns the saved file path. messageId is required for all actions; attachmentId is required for view/download. If messageId came from a shared/delegated mailbox, pass the same sharedMailbox (or alias email) — attachment IDs are scoped to the message and fail under /me otherwise. Use outputVerbosity to control list field count. |
| exportA | Export emails to files. target=message (default) exports one email by id (mime/eml/markdown/json/csv) to savePath: a directory (or a path ending in /, created if missing) gets a new, unique file name; a file path is created new and an existing file is replaced only with overwrite: true. target=messages batch-exports emailIds, or matches for searchQuery/query, into outputDir, at most 100 messages per call. target=conversation exports a thread (up to 1000 messages) by conversationId into outputDir (eml/mbox/markdown/json/html/csv; order: "reverse" for newest first). target=mime returns raw RFC-822 MIME for id (headersOnly, base64, maxSize, default 1MB). Files are written only inside the system temp directory (the default), ~/Downloads, ~/Documents or OUTLOOK_EXPORT_DIR, never to dot-prefixed names. Pass sharedMailbox (alias email) when the ids come from a shared mailbox. includeAttachments defaults to true for one message, false for batch. |
| get-mail-tipsA | Pre-send recipient validation via Graph POST /me/getMailTips (read-only; uses the existing Mail.Read scope — no extra permissions). Returns per-recipient tips covering automatic replies (out-of-office), mailbox full status, custom admin mail tips, delivery restrictions, moderation requirements, external-vs-internal scope, max message size, and group member counts (total + external). Use ahead of send-email or draft action=create to catch issues like OOO replies or external-recipient warnings before the message goes out; send-email/draft accept checkRecipients: true to invoke this automatically. Accepts either a comma-separated string or an array of addresses; tipTypes filters which tips are requested (defaults to all). |
| foldersA | Manage mail folders. Address a folder by name, by slash-separated path for nested folders (e.g. Inbox/Clients/Acme, case-insensitive) or by ID; a bare name matches a unique top-level folder first, then nested ones (an ambiguous name returns the candidates). action=list (default) returns the tree with each folder's path and id (includeItemCounts, includeChildren). action=create makes name under the root or parentFolder/parentFolderId. action=move moves emailIds into targetFolder/targetFolderId. action=stats returns total/unread counts for folder or folderId. action=delete removes a folder (folderName/path or folderId) with everything in it, subfolders included. It skips Deleted Items and Graph documents no restore path, so pass dryRun: true first to see what would be lost. Protected folders (Inbox, Sent Items, etc.) can't be deleted. Every action accepts sharedMailbox (alias email) to work in a shared or delegated mailbox (default: your own). |
| manage-rulesA | Server-side inbox rules (destructive: covers delete; dryRun previews create/update). Rules run on the Exchange server whichever client is open. action=list (default) returns rules with id/name/sequence; includeDetails: true adds conditions/actions/exceptions. action=create builds a rule from condition params (12, e.g. fromAddresses, containsSubject, bodyContains, hasAttachments, importance, sensitivity), action params (9, e.g. moveToFolder/copyToFolder — folder name, nested path like Triage/Delete, or ID — forwardTo, redirectTo, assignCategories, markAsRead, delete) and optional except* exceptions. action=update patches fields by ruleId or ruleName. action=reorder changes priority via sequence (lower runs first). action=delete removes a rule. The recipient allowlist applies to forwardTo/redirectTo. There is no permanentDelete action. Changes count against the session limit (OUTLOOK_MAX_MANAGE_RULES_PER_SESSION, else OUTLOOK_MAX_EMAILS_PER_SESSION); 0 refuses them. |
| manage-contactA | Full CRUD over the signed-in user's personal Outlook contacts (destructive: covers delete action). action=list (default) returns contacts with pagination via skip/count (default 50). action=search returns contacts matching query against name/email (default 25). action=get returns full contact detail by id. action=create adds a new contact and returns its id. action=update patches the given fields by id (only fields passed are changed). action=delete removes the contact by id; it skips Deleted Items, so treat it as permanent and pass dryRun: true first to confirm which contact it is. Use outputVerbosity (minimal/standard/full) on list/search to control field count. Searches only your personal contact store; for relevance-ranked search across contacts, the directory and recent communications, use search-people. |
| search-peopleA | Relevance-ranked search across personal contacts, organisation directory, and recent communications via the Microsoft Graph People API (read-only). Returns people objects with displayName, emailAddresses, companyName, jobTitle, and relevance metadata, for "who is X?" or "who do I email about Y?" lookups. For entries from your personal contact store only, use manage-contact action=search. |
| manage-categoryA | Manage the user's master category list (the colour-coded labels available across mail/calendar/contacts). action=list (default) returns categories with id/displayName/color. action=create adds a new category — displayName required, color optional (preset0-preset24, e.g. preset0=Red, preset7=Blue). action=update (alias set — deprecated) changes name/colour by id. action=delete removes a category — this does NOT untag messages already labelled with it; existing messages retain the orphaned label until manually cleaned. Use apply-category to tag/untag specific messages. |
| apply-categoryA | Tag or untag email messages with master categories (those created via manage-category). action=set (default) replaces the message's category set with the supplied categories array. action=add appends categories to whatever's already on the message. action=remove removes only the named categories, leaving the rest. Accepts either messageId (single) or messageIds (batch: one request per message). categories are matched by display name — names must already exist in the target mailbox's master list. For your own mailbox, create them via manage-category first; for a shared mailbox, the names must already exist there (manage-category only manages the signed-in account's master list). Pass sharedMailbox (or alias email) to categorise messages in a shared/delegated mailbox (default: the signed-in account; requires Mail.ReadWrite.Shared + delegate access). Returns per-message confirmation. |
| manage-focused-inboxA | Manage Focused Inbox sender overrides — explicit rules that force messages from a given sender into Focused or Other regardless of the ML classifier. action=list (default) returns existing overrides with id/sender/classifyAs. action=set creates or updates an override for emailAddress (optional name), routing future mail to focused (default) or other. action=delete removes the override for emailAddress. Note: this only works on accounts that have Focused Inbox enabled — personal Outlook.com accounts without it return an empty list. |
| mailbox-settingsA | Read or update mailbox-level settings (idempotent — safe to retry; sets are PATCH-style and merge with existing state). action=get (default) returns settings — use section to filter (language, timeZone, workingHours, automaticRepliesSetting, or all). action=set-auto-replies configures out-of-office: enabled true/false, optional startDateTime/endDateTime (ISO 8601) for scheduled mode, internalReplyMessage and (optionally) externalReplyMessage and externalAudience (none/contactsOnly/all); pass dryRun: true to preview who would get replies without changing anything. action=set-working-hours updates the schedule: startTime/endTime (HH:MM) and daysOfWeek (array of monday..sunday). Returns the updated settings object on set actions. |
| access-shared-mailboxA | List emails or folders in a shared mailbox the signed-in user can access (read-only). Returns messages from sharedMailbox (alias email) and folder (default inbox) with id/subject/from/receivedDateTime/preview, the same shape as search-emails list mode. folder takes a well-known name (inbox, sent, archive…), a custom/localized display name (e.g. Archiv), a nested path (e.g. Inbox/Vendors/Acme), or pass a raw folderId. listFolders: true enumerates the shared mailbox's folder tree (names, paths, IDs, counts), to find custom subfolders before reading them. Needs the mailbox delegated to the signed-in user in Exchange (admin-configured). outputVerbosity sets field count and count (default 25, max 50) page size. For search and filters over a shared mailbox, use search-emails with sharedMailbox set. Custom/localized names, nested paths and listFolders need the server opt-in setting OUTLOOK_SHARED_MAILBOX (work/school only); without it folder must be a well-known name or a folder ID. |
| find-meeting-roomsA | Discover bookable meeting rooms in the user's organisation via the Graph rooms endpoint (read-only). Returns room resources with displayName, emailAddress, building, floor, capacity, and bookingType — suitable for piping into create-event as attendees. Filter by query (matches name/email), building, floor, or minimum capacity. Returns empty list on personal accounts (the rooms endpoint is M365-only). Use outputVerbosity to control field count. |