Outlook MCP Server
The README references the sibling gmail-mcp-proxy project, which provides the same MCP integration pattern for Gmail: OAuth-based access to a personal Gmail account's mail (and calendar), with in-memory token storage and tools analogous to this server's mail search, listing, reading, sending, drafting, and labeling operations. The README compares the two, noting Gmail's atomic label add/remove and single consistent calendar surface versus Outlook's read-modify-write categories and dual calendar endpoints.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Outlook MCP Serversearch my inbox for emails from Sarah about the budget"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Outlook MCP Server
Self-hosted MCP server that exposes a personal Outlook.com account (mail + calendar, via Microsoft Graph) to Claude.ai (or any MCP client) via a standard OAuth 2.0 flow - no pre-generated credentials, and no tokens persisted to disk (they live only in memory - see How it works).
Personal accounts only. This deliberately uses Microsoft's consumers-tenant
endpoint, which structurally excludes work/school (Azure AD) accounts - only
outlook.com / hotmail.com / live.com-style personal Microsoft accounts can ever sign in.
Sibling project to gmail-mcp-proxy, which does the same thing for Gmail - see Outlook vs Gmail below for where the two diverge.
Quick Links
Related MCP server: Outlook MCP Server
How it works
Claude.ai ──[OAuth]──► This server ──[OAuth]──► Microsoft
Claude.ai ──[MCP]────► This server ──[Graph API]──► Outlook mail / calendarThe server acts as an OAuth proxy: it presents itself as an OAuth 2.0 authorization server to Claude, and internally delegates authentication to Microsoft. After the user grants access, Microsoft Graph tokens are stored server-side (in memory) and injected per-request. A short-lived JWT is issued to Claude as the bearer token.
Multiple accounts - add the server twice in Claude with different alias URLs
(/personal/mcp, /family/mcp). Each session is isolated; authenticate each with a
different Microsoft account.
Tools
Tool | Description |
| Outlook account profile, plus |
| The running proxy version - compare with the Changelog to spot a stale cached tool list |
| Search with Graph's |
| Messages inside one specific folder (id or well-known name like |
| Full message with decoded body and attachment metadata |
| All messages in a conversation (Outlook's equivalent of a Gmail thread), oldest first |
| Download an attachment's bytes (base64) by |
| Send, or reply within a conversation via |
| Save a draft ( |
| List drafts |
| Send an existing draft |
| Replace the content of an existing draft |
| Permanently delete a draft |
| Top-level folders by default; pass |
| Count folders in the mailbox (or one subtree via |
| Create a folder, optionally nested |
| Rename a folder |
| Permanently delete a folder |
| Re-parent a folder (and its contents/subfolders) under another folder |
| The mailbox's master category list (color-coded tags) |
| Add/remove categories on a message |
| Move a message to another folder |
| Move a message to Junk Email |
| Move a message to Deleted Items |
| Server-side inbox rules (see Server-side rules) |
| Create a server-side rule by sender / recipient ( |
| Delete a server-side rule |
| All calendars |
| Events in a time window (defaults to now-+30 days) |
| Search events by keyword |
| Single event by ID |
Calendar is read-only in this version, and there are no Contacts tools - both are easy additions on Graph, deliberately deferred; see Outlook vs Gmail.
Prerequisites
A GitHub account with this repo forked (or cloned) into it
An Azure account (free) - used only to register an OAuth app, no billing needed
A place to run the server with HTTPS - self-hosting (Python 3.12+ or Docker) behind Tailscale or your own reverse proxy is the documented path; see Setup
Configuration
Variable | Description |
| Azure App registration Application (client) ID |
| Azure App registration client secret - expires within 24 months, see Notes |
| Secret for signing session JWTs (any random string) |
| Public base URL, no trailing slash, e.g. |
| Optional. Comma-separated allowlist of OAuth redirect URIs |
| Optional. Python logging level ( |
| Optional. Comma-separated list of connector aliases (e.g. |
| Optional. Total attempts (1-5) for an outbound Graph API call (read or write) before giving up on a retryable status (429/5xx). Defaults to |
| Optional. Max attachment size (1-25MB, decoded) |
| Optional. Port the server listens on. Defaults to |
Read-only accounts
To connect an account you want Claude to only ever read from - never send, delete, or
modify - add its alias to READ_ONLY_ALIASES, e.g. READ_ONLY_ALIASES=family for a
connector added at /family/mcp. That account's Microsoft OAuth grant will only ever
request read scopes (Mail.Read, Calendars.Read, MailboxSettings.Read, plus the
sign-in basics openid, offline_access and User.Read) - no write scope is ever issued for it, so even a
bug in this server can't make it send or delete anything; Graph rejects it regardless.
The server also refuses write tool calls itself with a clear error, as a second layer.
Enforcement is server-side and unconditional - which alias a request comes in
through is derived from the URL path on every single request, both at /authorize
(when deciding which Microsoft OAuth scopes to request) and on every /mcp call
afterward, not something the client asserts. A restricted alias stays restricted
even if its bearer token is ever presented to a different connector's endpoint.
Server-side rules
list_rules, create_rule and delete_rule manage Outlook inbox rules through Graph's
mailFolders/inbox/messageRules. These run inside Exchange when mail arrives, so a rule
that deletes or moves mail from a sender does not mark it read (marking read is a
separate action you opt into) - unlike moving messages from a client.
They need the
MailboxSettings.Read(list) andMailboxSettings.ReadWrite(create/delete) scopes. An account connected before these tools existed must be removed and re-added in Claude so the Microsoft consent screen grants them; a 403 mentioningMailboxSettingsmeans that consent is missing.create_ruleworks on the Inbox only and refuses adisplay_namethat is already used. Conditions (at least one):sender_addresses(exact),sender_containsandrecipient_contains(word match on the sender / To-Cc address, like Outlook's "sender address" and "recipient address" conditions). Actions:delete,move(needs a real folder id fromlist_folders),mark_read_onlyorcategorize, andassign_categoriescan be added to any of them. Rules stop later rules by default; passstop_processing=falsefor a rule (e.g. a categorize-only one) that should let the rest run.list_rulesalso showsexceptionsandhasError. There is no edit tool - delete and re-create.
Development
pip install -r requirements-dev.txt
pytest # test suite
ruff check . # lint
mypy # type check (config in pyproject.toml)Tests mock all Graph API calls (via respx) and cover the pure-logic helpers (PKCE,
alias parsing, recipient parsing) plus tool behavior that's easy to get wrong - the
consumers-tenant-only OAuth requirement, refresh-token rotation, read-only enforcement,
and move_message's new-id semantics. No live Microsoft credentials needed to run them.
Outlook vs Gmail
Where this diverges from the Gmail sibling project:
Harder / more work:
Categories need read-modify-write (no atomic add/remove on Graph), vs. Gmail's atomic label add/remove.
Calendar listing needs two different endpoints (
calendarViewfor time-range/recurrence-expansion vs.events/$search), vs. Gmail's single consistent surface.move_messagereturns a new message id - anything holding the old id afterward will fail. Gmail message ids never change.move_folder, by contrast, keeps the folder's original id - confirmed by live testing; onlyparentFolderIdchanges.Folder hierarchy is a real tree (
parentFolderId), vs. Gmail's flat/-named labels.Two account-registration facts must be exactly right, with no forgiving fallback: the
consumers-tenant-only endpoint, and "Personal Microsoft accounts only" in Azure Portal - get either wrong and work/school accounts could authenticate.The Azure client secret expires within 24 months (Google's doesn't) - needs a calendar reminder, not a code fix.
Refresh tokens roll on every use and expire after ~90 days of account inactivity - a different failure mode than Google's, and the rotated token must always be re-stored.
Easier / genuine advantages:
read_messageis simpler -body.content/body.contentTypearrive as ready JSON, no MIME-tree walking or base64url decoding.Attachment ids are stable across repeated reads of the same message - no Gmail-style partId/attachmentId mismatch bug to work around.
Reply is a native Graph action (
/reply) - no manualIn-Reply-To/ReferencesMIME header construction.$searchon messages returns full fields per hit already, with no separate enrichment round-trip needed (Gmail'ssearch_emailsneeds one).Graph explicitly documents and honors
Retry-After- a more reliable throttling signal than Gmail's docs provide.Calendar write, free/busy,
findMeetingTimes, and a full Contacts API are all natively easy on Graph - deliberately deferred here, not technical gaps.
After a connector update
Claude keeps the tool list it loaded in each chat's history, so a chat can keep showing an older tool set after you upgrade the server. "Reconnect" does not refresh it. To get the new tools into an existing chat:
Delete and re-add the connector in Claude.
Restart the Claude app if it still shows the old tools.
In the chat, run
/compact- this reloads the tool definitions from the server.Only start a new chat if that still doesn't fix it.
To check, call get_version in the chat and compare it with the newest
Changelog entry.
Notes
The running version is logged at startup (
journalctl -u outlook-mcp-proxy | grep starting) and matches the newest Changelog entry.If you expose the server with Tailscale Funnel,
/authorize,/tokenand the OAuth metadata are reachable from the public internet by design (Claude's servers need them). They are bounded (a cap on pending sign-ins, PKCE and a redirect allowlist) and/mcpneeds a valid bearer token, but treat the URL as public.Sessions are stored in memory - a server restart requires re-authentication in Claude.ai
Runs as a single process - don't scale to multiple replicas or
uvicorn --workers N. Session/state stores are per-process in-memory, so a request landing on a different process than the one that authenticated it would fail as if unauthenticated.Microsoft access tokens are refreshed automatically using the stored refresh token, which Microsoft frequently rotates on every use - the server always stores whatever comes back.
Personal Microsoft account refresh tokens roll on a ~90-day inactivity window - an account genuinely unused for that long needs the same re-auth as after a restart.
The Azure app registration's client secret expires within 24 months. Rotate it in Azure Portal → your app → Certificates & secrets before then, update
MS_CLIENT_SECRET, and restart the service.The server issues 30-day JWTs; Claude re-authenticates when they expire.
This server cannot be deployed
Maintenance
Related MCP Connectors
Hosted email MCP for your own Gmail, Outlook.com, Microsoft 365, iCloud or IMAP inbox: read, search, draft, reply in thread, forward and file mail. It moves or flags up to 500 messages in one call, and a send leaves exactly one copy in Sent. A calendar is a separate connection, and connecting one adds diary and scheduling tools.
Your Gmail, Calendar, Drive, GitHub, Oura, wallet and confirmed profile facts in any MCP client.
- MailowsOAuthcom.mailows
Give AI agents their own email inboxes: list, read and send mail via scoped, revocable OAuth grants.
Permissioned access to Outlook, OneDrive and Teams via the user's own Microsoft account
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
- AlicenseAqualityAmaintenanceLets Claude read email and read/write calendar events for personal Microsoft accounts (Hotmail/Outlook/Live) via Microsoft Graph API, filling the gap where the official connector only supports work/school accounts.6MIT
- AlicenseAqualityDmaintenanceA local MCP server that connects Claude Desktop to a personal Hotmail/Outlook.com mailbox via Microsoft Graph API, enabling email management, rule handling, and composing messages.25MIT