Outlook MCP Server
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
Outlook MCP server
An MCP server that gives Claude, or any MCP client, access to your Outlook.com or Microsoft 365 mailbox through Microsoft Graph. It runs on your machine as a single Python file. You choose which kinds of changes it may make, mail is only ever sent from a draft you approved, and every bulk action has to restate what it is about to touch.
Features
Read: folders and subfolders, message lists, keyword or KQL search (mailbox-wide or per folder), single messages, whole threads, attachments.
Write: create, edit, reply to and forward drafts, with Markdown converted to clean HTML, then send an approved draft.
Clean up: move, archive, delete, categorize and junk-report in batches, archive by criteria instead of by id, empty Junk or Deleted Items.
Triage: rank senders by volume, find newsletters, old unread mail and large messages, collect ids for a bulk action.
Unsubscribe through the
List-Unsubscribeheader, only for senders that pass DKIM and DMARC.Inbox rules: list, create, update and delete server-side rules, and suggest rules from the senders that flood you.
Related MCP server: Outlook MCP Server
Requirements
Python 3.10 or newer, and uv or pip.
An Outlook.com, Hotmail, Live, or Microsoft 365 account.
A free Azure app registration (below). No paid subscription is needed.
Installation
Register an app in Azure
Open https://entra.microsoft.com, go to App registrations and choose New registration.
Name it (for example
Outlook MCP) and pick the account type: personal accounts use Personal Microsoft accounts only; work or school accounts use Accounts in this organizational directory only.Leave the redirect URI empty and register. Copy the Application (client) ID.
Under Authentication, set Allow public client flows to Yes.
Under API permissions, add the Microsoft Graph delegated permissions
User.Read,Mail.ReadWriteandMail.Send. AddMailboxSettings.ReadWritetoo if you want the inbox-rule tools. Work accounts may need an admin to grant consent.
Install the server
git clone https://github.com/kennymatsudo/outlook-mcp
cd outlook-mcp
uv syncOr with pip:
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install .Sign in
Copy .env.example to .env, fill in OUTLOOK_CLIENT_ID, then:
uv run outlook-mcp login # pip: python outlook_mcp.py loginIt prints a code and a URL. Open the URL, enter the code and approve. Refresh
tokens keep you signed in; run login again if a tool reports that the session
expired, and logout to remove the cached tokens.
Configuration
All settings are environment variables. The server also reads a .env file
next to outlook_mcp.py (ignored by git); real environment variables win.
Variable | Default | Meaning |
| none, required | Application (client) ID from the Azure registration. |
|
|
|
|
| Which groups of mail-changing tools exist: |
|
| Tokens and logs, created owner-only. |
|
| Where |
Set them in whichever place fits:
# .env next to outlook_mcp.py
OUTLOOK_CLIENT_ID=00000000-0000-0000-0000-000000000000
OUTLOOK_TENANT=consumers
OUTLOOK_PERMISSIONS=draft,organize,attachments// the "env" block of your MCP client's server entry (see Usage)
"env": {
"OUTLOOK_CLIENT_ID": "00000000-0000-0000-0000-000000000000",
"OUTLOOK_TENANT": "consumers",
"OUTLOOK_PERMISSIONS": "draft,organize,attachments"
}# Claude Code
claude mcp add outlook -e OUTLOOK_CLIENT_ID=... -e OUTLOOK_PERMISSIONS=read -- ...Restart the client after changing a setting.
Permission groups
Reading and triage tools are always available. Every tool that changes mail or writes to disk belongs to one group. A tool in a disabled group is not offered to the model at all, and the server tells the model which groups are off so it says so instead of improvising.
Group | Tools |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
OUTLOOK_PERMISSIONS=read makes the server read-only.
OUTLOOK_PERMISSIONS=draft,organize lets the model write drafts and tidy
folders but never send, delete or change rules.
Within an enabled group, your client's own tool approval is the control that
holds. In the Claude app, set send_draft, unsubscribe, the delete, purge
and rule tools, move_messages, report_junk and report_not_junk to
Ask before use.
Usage
Claude desktop app (Settings, Developer, Edit Config), with absolute paths:
{
"mcpServers": {
"outlook": {
"command": "uv",
"args": ["run", "--directory", "/ABSOLUTE/PATH/outlook-mcp", "outlook-mcp"],
"env": {
"OUTLOOK_CLIENT_ID": "00000000-0000-0000-0000-000000000000",
"OUTLOOK_TENANT": "consumers"
}
}
}
}With pip, the command is /ABSOLUTE/PATH/outlook-mcp/.venv/bin/python and
the args are ["/ABSOLUTE/PATH/outlook-mcp/outlook_mcp.py"] (Windows:
.venv\\Scripts\\python.exe). Leave out env if you use a .env file.
Claude Code:
claude mcp add outlook -e OUTLOOK_CLIENT_ID=... -e OUTLOOK_TENANT=consumers \
-- uv run --directory /ABSOLUTE/PATH/outlook-mcp outlook-mcpThings to ask:
"What unread email do I have today?"
"Draft a reply to the latest message from Alice saying I'll send the report Friday."
"Who sends me the most mail? Unsubscribe me from the newsletters I never open."
"Archive everything older than a year that I've already read."
"Save the invoice attached to the message from Acme and tell me the total."
A full cleanup runs mailbox_overview, sender_stats and find_bulk_mail to
see where the volume is, archive_matching to clear the backlog,
find_unsubscribable then unsubscribe to stop newsletters, suggest_rules
then create_rule for senders that cannot be unsubscribed, and finally
empty_folder on Junk.
Tools
Area | Tools |
Account and folders |
|
Reading |
|
Drafting and sending |
|
Organizing |
|
Deleting |
|
Junk |
|
Triage |
|
Unsubscribing |
|
Inbox rules |
|
Each tool's description, shown to the model, says when to use it and what it returns. A few behaviours worth knowing:
Draft bodies are written as Markdown (paragraphs, lists, bold, italic, links) and converted to HTML, so they look in Outlook the way they looked in chat.
update_draftrefuses anything that is not a draft.A move gives each message a new id, returned as
new_message_ids.report_junktrains Outlook's spam filter and blocks the sender, which moving a message to Junk does not do.save_attachmentnever overwrites a file, and attached emails and cloud links cannot be saved.Inbox rules run on Microsoft's servers, so they keep working when this server is off, and they apply only to mail arriving after they are created. They need the
MailboxSettings.ReadWritepermission; if you add it later, runlogoutandloginagain.
Security
Changes require a restated count
move_messages, archive_messages, delete_messages,
permanently_delete_messages, report_junk, report_not_junk and
unsubscribe fail unless confirm_count equals the number of items passed.
Called without it, they report what they would have touched so the model can
show you first. archive_matching previews the match count and ten samples,
needs an age or a sender so a whole folder can never be archived by accident,
and works in slices of 1000. empty_folder only accepts Junk or Deleted Items,
and its count must match the folder at the moment it runs. delete_rule
requires the rule's current name.
Email is untrusted input
Email is written by strangers, and some of it will try to give the model orders. The server marks and flags; it never blocks a tool call. The approval steps above are what hold.
Zero-width, bidi-override and Unicode tag characters are stripped from everything returned to the model, so text invisible in Outlook never reaches it. Tag characters can spell out hidden ASCII; that text is decoded and scanned before it is stripped.
Message bodies are fenced between
[BEGIN UNTRUSTED EMAIL CONTENT]markers (a forged marker inside an email is rewritten and flagged), and the server's instructions tell the model never to follow text found in email.Subjects, previews, bodies and sender names are matched against a short list of English attack phrasings: "ignore all previous instructions", role overrides, text addressed to an AI, this server's own tool names, "forward all emails to", a Markdown image with a query string, "without asking the user", requests for the system prompt or an API key, and chat-template markup. A match adds
injection_warningto the result so the model can tell you. Expect occasional false positives and expect a reworded attack to pass: this is an alarm, not a filter, and it is deliberately not extended with synonyms or other languages, because each addition adds more noise than cover.Every tool that changes mail appends to
audit_log.jsonlin the cache directory: tool, arguments and outcome. Bodies are logged as a length only.
Unsubscribing is conservative
Both unsubscribe tools read only the List-Unsubscribe header, never links in
the body. find_unsubscribable groups senders by method:
Method | Meaning | What |
| RFC 8058 (https plus | One fixed POST to a public https host, no redirects |
| Unsubscribe-by-email address | Outlook sends the email; that message goes to Deleted Items |
| Only a web page | Nothing; the link is returned for you to open |
| No unsubscribe header | Nothing; use |
| In Junk, or failed DKIM/DMARC | Nothing; unsubscribing would confirm your address to a spammer |
Authentication comes from Microsoft's own Authentication-Results header, and
every such header must pass. Attempts are logged to unsubscribe_log.jsonl;
senders still mailing three days after a successful unsubscribe are flagged
still_sending on later runs and need a rule.
Troubleshooting
Message | Fix |
| Add it to |
| Run |
| Enable Allow public client flows in the app registration. |
| Account type mismatch: check the registration's account type and |
| Add the missing API permission, then |
Rule tools say they need | Add that delegated permission, then |
| Use |
A tool is missing from the model's list | Its group is off in |
| Intended: the model must confirm the count with you first. |
| Ids change on move; use |
Draft created "but its text could not be added" | The draft is in Drafts with only the quoted thread; delete it and retry. |
A rule exists but mail is not moving | Check |
Development
uv sync
uv run pytestThe tests cover everything that needs no mailbox: Markdown-to-HTML, injection scanning, confirmation guards, sender authentication, the unsubscribe decision, attachment file naming, draft editing and permission parsing.
License
This server cannot be deployed
Maintenance
Related MCP Connectors
Connect any IMAP/SMTP mailbox to Claude & ChatGPT: search, read, sort, draft. Sends only with OK.
Connect any mailbox to Claude, ChatGPT & AI: read, send, reply, schedule & search emails.
Email infrastructure for AI agents — send, receive, search, and reply to email over MCP.
Manage Microsoft 365 email, calendar, contacts and inbox rules via the Graph API with OAuth 2.0.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceConnects Claude with Microsoft Outlook through the Graph API, providing comprehensive email, calendar, folder management, and rules creation capabilities.19MIT
- AlicenseNot gradedqualityCmaintenanceConnects Claude to Microsoft Outlook through the Microsoft Graph API, enabling email management (list, search, read, send) and calendar operations (list, create, accept, decline, delete events) via OAuth 2.0 authentication.1MIT
- FlicenseNot gradedqualityDmaintenanceProvides Claude Desktop and Claude Code with access to Microsoft 365 email and calendar services via the Microsoft Graph API. It enables users to manage emails, search folders, schedule calendar events, and check availability through natural language commands.-
- FlicenseAqualityBmaintenanceEnables Claude to manage Outlook calendar events and Microsoft To Do tasks for a specific mailbox via Microsoft Graph API.7-