Skip to main content
Glama
outlook-mcp

outlook-mcp

by ajs117

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
OUTLOOK_MCP_CONFIGNoOverrides the path of the config file (default ~/.outlook_mcp_config.json) that stores the protected senders keep-list.
OUTLOOK_MCP_CLIENT_IDYesYour Azure app registration's Application (client) ID, used for the OAuth device-code login to Microsoft Graph.

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
list_foldersA

List all mail folders (Inbox, Archive, Deleted Items, custom folders, etc.) with their ids and display names.

inbox_summaryA

Quick counts for the inbox: total messages and unread messages.

list_messagesA

List messages in a folder, newest first (unless searching).

Returns compact rows keyed by a short ref handle (not the raw Graph id) — pass that ref to get_message / move / delete / the bulk_* tools.

Args: folder: folder id or well-known name (inbox, archive, deleteditems, sentitems, drafts, junkemail). top: max number of messages to return per page (ignored if fetch_all is True). skip: number of messages to skip, for manual paging (ignored if fetch_all is True). filter_query: raw OData $filter, e.g. "receivedDateTime le 2026-01-01T00:00:00Z" or "isRead eq false". search: free-text search (Graph $search); when set, filter_query/order are ignored. fetch_all: if True, follow pagination automatically and return up to max_results messages instead of a single page of top. Use this for bulk operations over a whole folder. max_results: cap on messages returned when fetch_all is True (safety limit, default 500). include_keywords: attach a short salient-keyword list per message (subject+preview) for triage. include_preview: attach the full plaintext preview per message. Prefer include_keywords for triage and get_message for a full read — a preview per message across a big folder is costly.

get_messageA

Get one message by ref (or raw id). Body is returned as plaintext and truncated to max_chars to keep it token-cheap.

Args: message_id: a short ref from list_messages (e.g. "m12"), or a raw Graph id. include_body: set False to get metadata only (subject/from/date), no body. max_chars: truncate the plaintext body to this many characters (0 = no limit).

archive_messageB

Move a message (by ref or raw id) to the Archive folder.

move_messageB

Move a message (by ref or raw id) to a folder (id or well-known name).

delete_messageA

Move a message (by ref or raw id) to Deleted Items — recoverable from there until you empty it. Marks it read first (mark_as_read=False to keep it unread) so deleted mail doesn't linger in your unread count.

mark_readB

Mark a message (by ref or raw id) as read or unread.

create_reply_draftA

Create a draft reply to a message (by ref or raw id). Does NOT send it; a human reviews/sends from Outlook.

bulk_mark_readB

Mark many messages (refs or raw ids) read/unread in one call (Graph $batch).

bulk_move_messagesB

Move many messages (refs or raw ids) to a folder (id or well-known name) in one call.

bulk_archive_messagesB

Move many messages (refs or raw ids) to the Archive folder in one call.

bulk_delete_messagesA

Move many messages (refs or raw ids) to Deleted Items in one call, marking them read first (mark_as_read=False to keep them unread).

Refuses and deletes nothing if any message is from a protected sender (see protected_senders) — re-call with allow_protected=True to override. Senders are only known for messages this server has already listed or read; refs it has never seen cannot be checked.

bulk_by_queryA

Find every message matching a query and apply one action to all of them in a single call — the message ids never enter the conversation, so this is by far the cheapest way to triage in bulk.

action: one of archive, delete, mark_read, mark_unread, move (move requires destination_folder, which may be a folder display name). folder / filter_query / search: same matching semantics as list_messages (fetches all matches up to max_results). received_before / received_after: ISO dates (e.g. "2026-01-01"); applied client-side AFTER matching, so they compose with search — which Graph itself won't combine with a date $filter. Use these for "old " sweeps, e.g. search="delivery" + received_before to clear old shipping mail. only_newsletters: keep only bulk/newsletter mail (messages with a List-Unsubscribe header) among the matches, e.g. archive all newsletters older than a week. Costs an extra batched header pass over the matches. Note this is a bulk-sender signal, not a junk one — plenty of wanted mail (order updates, voucher codes, statements) carries the header too. senders_only: keep only matches from these sending addresses (exact, case-insensitive). Graph rejects a sender $filter combined with $orderby, so this is applied client-side — it is the supported way to act per sender. Pair it with sender_summary to pick the addresses. on_protected: what to do about matches from protected senders (see protected_senders): "exclude" (default, skip them and report), "error" (do nothing at all and report), "include" (ignore the list). dry_run: TRUE by default — returns how many messages would be affected plus a small sample of subjects/senders, and does nothing. Review it, then call again with dry_run=False to actually run the action. This guards against a bad filter nuking the wrong mail.

create_draftA

Compose a brand-new draft email (NOT a reply). It is saved to Drafts and never sent — you review and send it from Outlook.

Args: to: recipient email addresses. subject: subject line. body: message body (plain text by default; set html=True to send HTML). cc: optional cc email addresses. html: treat body as HTML instead of plain text.

create_folderB

Create a mail folder. parent_folder (id or display name) nests it; omit for a top-level folder. Useful before moving mail into a new folder.

sender_summaryA

Group a whole folder by sending address and report, per sender, how many messages there are and how many were actually opened.

This is the tool to reach for before proposing anything for deletion. A sender's read rate is measured evidence of whether the mailbox owner wants their mail; guessing from the brand name is not, and gets it wrong.

Returns rows {sender, brand, domain, count, read, unread, read_pct, newest, oldest, sample_ref}, biggest sender first. brand is a heuristic display label — never group or delete by it. brand_shared: true marks a row whose brand label also belongs to another address in the result (e.g. a billing subdomain and a marketing subdomain of one company): those are different senders and must stay separate.

Args: folder: folder id or well-known name. min_count: drop senders with fewer than this many messages. top: return at most this many sender rows (after sorting by count). max_results: cap on messages scanned. unread_only: summarise only unread mail.

find_newslettersA

Scan a folder for bulk mail (messages carrying a List-Unsubscribe header) and report how each sender can be unsubscribed.

Grouped by sender by default, because unsubscribing is per sender while the underlying listing is per message — the ungrouped form makes the model dedupe 200 rows by hand to reach the ~50 decisions that actually exist. Each row carries read/unread counts so a sender can be judged on engagement rather than on what its name suggests.

IMPORTANT: the List-Unsubscribe header marks a bulk sender, not junk. Order confirmations, delivery updates, statements and voucher codes all carry it. Treat this as a list of candidates to show the user, never as a list to sweep.

Returns {checked, headers_ok, header_fetch_failed, newsletter_messages, senders: [...]}. The header counts are there so a discrepancy between this and bulk_by_query(only_newsletters=True) is visible rather than mysterious: header sub-requests that fail are silently dropped from the scan.

Args: folder: folder id or well-known name. max_check: how many recent messages to scan. group_by_sender: set False for the raw per-message rows.

unsubscribeA

Unsubscribe from the bulk sender of a message (ref or raw id).

Reads the message's List-Unsubscribe headers and:

  • method "one-click": with execute=True, performs the RFC 8058 one-click POST and returns the HTTP status — no browser needed.

  • method "mailto": with execute=True, creates a DRAFT unsubscribe email to the sender's unsubscribe address for you to send (our mail scope can create but not send mail).

  • method "weblink": returns the URL for you to open in a browser; not auto-fetched, since blindly GETting links embedded in email is unsafe.

With execute=False (default) it only reports the available method/target so you can decide. Caveat: unsubscribing confirms your address is live, so do it for legitimate senders — for actual spam, prefer delete/block instead.

unsubscribe_manyA

Unsubscribe from many bulk senders in one call.

Deduplicates on the unsubscribe target, never on the sender: LinkedIn job alerts all arrive from one address but carry a different savedSearchId each, so skipping by sender leaves most streams subscribed while reporting success. Two messages for the same stream still carry different per-message tokens and so both get posted — a wasted request is cheaper than a missed unsubscribe.

Same per-message semantics as unsubscribe(), but the header fetch is batched and the whole sweep is one tool call instead of one per sender.

Returns {attempted, unsubscribed, needs_browser, drafted, failed, results: [...]}. needs_browser collects the senders whose only working route is a URL a human must open — including one-click endpoints that rejected the POST — so nothing fails silently.

protected_sendersA

Read or edit the keep-list of senders that bulk operations won't touch.

Patterns are matched case-insensitively against the sending address: one containing * or ? is a glob over the whole address ("*@edfenergy.com"), one without is a substring test ("dwp"). Use this for the mail that would be expensive to lose — benefits, legal, medical, bills, anything with a case number — so a broad sweep can't reach it.

bulk_by_query excludes protected senders by default and says how many it held back; bulk_delete_messages refuses outright. Both can be overridden per call once you've looked.

Call with no arguments to just read the list.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A3.5/5.0

Scored across 21 tools

Disambiguation3/5

The core distinction between single-message and bulk tools is mostly clear, but bulk_by_query overlaps heavily with the dedicated bulk_* tools and with archive_message/move_message/delete_message/mark_read. archive_message also largely duplicates move_message to Archive, and find_newsletters overlaps with bulk_by_query(only_newsletters=True), so an agent has several plausible routes for the same operation.

Naming Consistency3/5

Most tools use snake_case and are readable, but the naming convention is mixed: many are verb_noun (list_messages, move_message, create_draft), while others are noun-centric or phrase-based (inbox_summary, sender_summary, bulk_by_query, protected_senders). It is not chaotic, but the pattern is not predictable enough for a high score.

Tool Count3/5

At 21 tools, the server is in the heavy borderline range. The domain is complex enough to justify many operations, but there is noticeable duplication between general bulk actions, dedicated bulk tools, and single-message action tools, which inflates the surface.

Completeness4/5

The tool set covers the main mail triage lifecycle well: folders, listing/reading messages, summaries, drafts and reply drafts, single and bulk move/delete/archive/mark operations, newsletter discovery/unsubscribe, and protected senders. Minor gaps remain, such as sending mail, attachment handling, folder rename/delete, and draft editing, but core workflows are covered.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues