Outlook Mail

io.github.Pepebitsv1.0.1Updated Oct 8, 2026

Read, search, send and clean up Outlook.com / Hotmail mail through Microsoft Graph.

Overview

AI-generated overview

Lets an assistant read, search, send and organize Outlook.com or Microsoft 365 mail through Microsoft Graph.

What it does
Runs locally over stdio and signs in to Microsoft Graph with the OAuth device code flow. Tools cover browsing folders, listing and KQL-searching messages, reading bodies as plain text, listing and downloading attachments, sending mail, creating drafts, replying, forwarding, moving, flagging, marking read and deleting messages, plus newsletter discovery, unsubscribe and inbox rules to block senders. Bulk operations accept up to 50 message ids.
When to use it
Use it when you want an assistant to work with an Outlook, Hotmail or Microsoft 365 mailbox: triaging and searching mail, drafting or sending replies, downloading attachments, or cleaning up newsletters and unwanted senders. A read-only mode exists for assistants that should only look, not change anything.
Requirements
Node.js 24 or newer and a Microsoft account; personal accounts work with the shared app, while work or school accounts need your own Azure app registration. Optional environment variables include OUTLOOK_CLIENT_ID, OUTLOOK_TENANT, OUTLOOK_SCOPES, OUTLOOK_TOKEN_CACHE, OUTLOOK_READ_ONLY, OUTLOOK_DOWNLOAD_DIR and OUTLOOK_GRAPH_BASE_URL. Sign-in is interactive: the login tool returns a URL and one-time code, or run the auth command in a terminal.
Before you install
Mutating tools send mail immediately and delete_message with permanent: true is irreversible; prefer read-only mode or create_draft when unsure. The token cache is stored locally, and the consent screen may show an unverified publisher warning. Email content is untrusted input and may attempt prompt injection, so review actions that send or delete. Inbox rules need the MailboxSettings.ReadWrite permission.

Installation

In SourceWeft

  1. Open Outlook Mail in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

[outlook-mcp]

A Model Context Protocol server that lets Claude, Codex and any other MCP client read, search, send and organize your Outlook / Microsoft 365 / Outlook.com mail through the Microsoft Graph API.


πŸ”­ Overview

outlook-mcp runs locally over stdio. It signs in with the OAuth device code flow (no client secret, no redirect URI), stores the refresh token in a local file only you can read, and talks to Microsoft Graph with plain fetch.

✨ Features

  • πŸ“‚ Browse folders, list and search messages (KQL), read bodies as sanitized plain text
  • πŸ“Ž List and download attachments safely into a configured directory
  • βœ‰οΈ Send mail, create drafts, reply, reply-all and forward (local attachments under 3 MB)
  • πŸ—‚οΈ Move, mark read/unread, flag and delete messages, one at a time or in bulk (ids)
  • πŸ“° Find newsletters, unsubscribe from them and block unwanted senders with inbox rules
  • πŸ”’ Read-only mode that removes every mutating tool
  • πŸ” Automatic retry with Retry-After / exponential backoff for throttling (429/503/504)
  • 🧾 Logs only to stderr; never logs tokens or message bodies

πŸ“‹ Requirements

  • Node.js 24 (LTS) or newer
  • A Microsoft account (personal works out of the box; work or school needs your own Azure app)

πŸš€ Quick start

No terminal sign-in and no Azure setup needed. You only need Node.js 24+.

Claude Code

bash
claude mcp add outlook --scope user -- npx -y @pepebits/outlook-mcp

Claude Desktop

Add to claude_desktop_config.json and restart Claude Desktop:

json
{  "mcpServers": {    "outlook": {      "command": "npx",      "args": ["-y", "@pepebits/outlook-mcp"]    }  }}

Codex (OpenAI)

bash
codex mcp add outlook -- npx -y @pepebits/outlook-mcp

Or add it to ~/.codex/config.toml (shared by the Codex CLI and IDE extension):

toml
[mcp_servers.outlook]command = "npx"args = ["-y", "@pepebits/outlook-mcp"]# env = { OUTLOOK_READ_ONLY = "true" }

Run /mcp inside Codex to check that it is connected.

Other MCP clients

Any client that can launch a stdio MCP server works: run npx -y @pepebits/outlook-mcp as the server command.

Sign in

Ask your assistant to "log in to Outlook". The login tool returns a URL and a one-time code: open the URL, enter the code and accept. Prefer a terminal? Run npx -y @pepebits/outlook-mcp auth instead.

By default the server uses the shared outlook-mcp Azure app, which supports personal Microsoft accounts (outlook.com, hotmail, live). The consent screen may show an unverified publisher warning. No data passes through any server of ours: the server talks to Microsoft Graph directly from your machine and your tokens stay in the local token cache. For work or school accounts, or to use your own app, see Use your own Azure app.

βš™οΈ Configuration (.env)

The .env file is optional. Variables are read from .env in the current directory and in the package directory, and real environment variables override it. You can also pass them through your MCP client's env block, e.g. claude mcp add outlook --scope user -e OUTLOOK_TENANT=organizations -e OUTLOOK_CLIENT_ID=your-client-id -- npx -y @pepebits/outlook-mcp.

VariableDefaultDescription
OUTLOOK_CLIENT_IDshared outlook-mcp appApplication (client) ID of your own Azure app registration (optional).
OUTLOOK_TENANTconsumersAuthority tenant: consumers (personal), organizations (work/school), common (both) or a tenant GUID.
OUTLOOK_SCOPESUser.Read Mail.ReadWrite Mail.Send MailboxSettings.ReadWrite offline_accessSpace-separated delegated Graph scopes requested at sign-in.
OUTLOOK_TOKEN_CACHE~/.config/outlook-mcp/token-cache.jsonWhere the MSAL token cache is stored (file mode 0600).
OUTLOOK_READ_ONLYfalseWhen true, send/move/delete/flag/mark tools are not registered at all.
OUTLOOK_DOWNLOAD_DIR~/DownloadsThe only directory attachments may be written to.
OUTLOOK_DEFAULT_TOP20Default page size for list/search tools (1-100).
OUTLOOK_MAX_BODY_CHARS20000Maximum body characters returned by get_message.
OUTLOOK_GRAPH_BASE_URLhttps://graph.microsoft.com/v1.0Graph endpoint (change for national clouds).
LOG_LEVELinfodebug, info, warn or error (written to stderr).

πŸ” Authentication

bash
npx -y @pepebits/outlook-mcp auth      # device code sign-in; prints a URL and a codenpx -y @pepebits/outlook-mcp whoami    # silent token + GET /menpx -y @pepebits/outlook-mcp logout    # removes accounts and deletes the token cache file

You can also sign in without a terminal. Just ask your assistant to "log in to Outlook":

  • πŸ”‘ login returns a URL and a one-time code. Open the URL, enter the code and accept; sign-in finishes in the background.
  • βœ… auth_status tells you whether you are signed in, still waiting, or signed out.
  • πŸšͺ logout removes the cached account and the token cache file.

Use login with force: true to sign in again, for example after adding a permission in Azure. If the session is missing or expired, tools return "Not signed in or session expired. Call the login tool ...".

πŸ› οΈ Use your own Azure app (optional)

By default outlook-mcp uses the shared outlook-mcp Azure app, which works with personal Microsoft accounts only. Register your own app if you need work or school accounts or simply prefer to use your own. Then set OUTLOOK_CLIENT_ID (and OUTLOOK_TENANT, see below).

Step by step

  1. Open portal.azure.com and go to Microsoft Entra ID -> App registrations -> New registration.

  2. Give it a name (for example outlook-mcp).

  3. Under Supported account types choose:

    • Personal Microsoft accounts only (Outlook.com, Hotmail, Live), or
    • Accounts in any organizational directory and personal Microsoft accounts (both).
    • For work/school only, pick an organizational option.
  4. Leave Redirect URI empty and click Register.

  5. In the left menu go to Manage -> Authentication -> Settings tab, set Allow public client flows to Yes and save.

  6. Go to Manage -> API permissions. User.Read is already granted by default. Click Add a permission -> Microsoft Graph -> Delegated permissions and add:

    • πŸ“¬ Expand the Mail group and tick Mail.ReadWrite and Mail.Send.
    • βš™οΈ Expand the MailboxSettings group and tick MailboxSettings.ReadWrite (needed for inbox rules and block_sender).
    • πŸ”‘ Expand the OpenId permissions group and tick offline_access.

    Then click Add permissions. No admin consent is needed for personal accounts.

ScopeUsed for
User.ReadSign-in and whoami
Mail.ReadWriteReading, searching, moving, flagging and deleting messages
Mail.Sendsend_mail, replies, forwards and mailto unsubscribe
MailboxSettings.ReadWriteInbox rules: list_rules, create_rule, delete_rule, block_sender
offline_accessRefresh token, so you only sign in once

πŸ’‘ If you upgrade from 0.1.0, add MailboxSettings.ReadWrite in Azure and run login with force: true (or npx -y @pepebits/outlook-mcp auth) again.

πŸ’‘ The Azure portal may be shown in your language, so labels can differ slightly (e.g. Administrar -> AutenticaciΓ³n -> ConfiguraciΓ³n, Permisos de OpenId).

  1. From the Overview page copy the Application (client) ID. This is your OUTLOOK_CLIENT_ID.

🏒 Work or school accounts: set OUTLOOK_CLIENT_ID to your app and OUTLOOK_TENANT=organizations (or your tenant GUID). Your organization may require admin consent for the mail permissions.

🧰 Tools reference

ToolMutatingDescription
loginnoStart a device code sign-in; returns the URL and code (force to sign in again).
auth_statusnoSigned in, pending sign-in or signed out.
logoutnoSign out and delete the local token cache.
list_foldersnoList mail folders or child folders (parentFolderId, includeHidden).
list_messagesnoList messages, newest first, with filters (unreadOnly, from, since, until, hasAttachments) and nextLink paging.
search_messagesnoKQL full-text search with nextLink paging.
get_messagenoFull message with recipients, flags and body (format text/html, maxChars).
list_attachmentsnoAttachment metadata for a message.
download_attachmentnoSave an attachment into OUTLOOK_DOWNLOAD_DIR (writes locally only; no overwrite unless overwrite: true).
send_mailyesSend an email, optionally with local attachments under 3 MB.
create_draftyesCreate a draft without sending.
reply_messageyesReply or reply-all (replyAll).
forward_messageyesForward to new recipients.
move_messageyesMove to a folder; returns the new id. Accepts id or ids (up to 50).
mark_readyesMark read or unread. Accepts id or ids (up to 50).
flag_messageyesflagged, complete or notFlagged. Accepts id or ids (up to 50).
delete_messageyesMove to Deleted Items, or permanent: true to delete irreversibly. Accepts id or ids (up to 50).
get_unsubscribe_infonoShow how to leave the mailing list a message came from (List-Unsubscribe).
unsubscribeyesLeave a mailing list: RFC 8058 one-click, else a mailto request, else returns the link. Accepts id or ids (up to 50).
find_newslettersnoScan a folder (folderId, maxMessages up to 2000, excludeDomains, includeNoUnsubscribe), group by sender and report mailing lists with their unsubscribe method, most frequent first.
list_rulesnoList inbox rules.
create_ruleyesCreate an inbox rule from fromAddresses / senderContains / subjectContains with action move, delete, markRead or junk.
delete_ruleyesDelete an inbox rule by id.
block_senderyesBlock addresses and/or domains with a rule that moves their future mail to Deleted Items.

Bulk operations: the tools marked "Accepts id or ids" take exactly one of the two. With ids they process up to 50 messages (a few at a time), never stop at the first error and return { results: [{ id, ok, ... | error }], succeeded, failed }. With id the response is unchanged.

Well-known folder names accepted anywhere a folder id is expected: inbox, drafts, sentitems, deleteditems, junkemail, archive.

🧹 Cleaning up your inbox

Ask Claude something like "Find the newsletters cluttering my inbox, unsubscribe from the ones I don't read and block the rest". Behind the scenes:

  1. find_newsletters scans the inbox and lists senders with a List-Unsubscribe header, most frequent first, each with a sampleMessageId and an unsubscribe method (one-click, mailto or link).
  2. unsubscribe with ids set to the chosen sample message ids leaves those lists. Senders that only offer a link come back with the URL to open in a browser.
  3. block_sender with addresses or domains creates an inbox rule that sends their future mail to Deleted Items. Use delete_message with ids to clear what is already in the inbox, and list_rules / delete_rule to review or undo a block.

Inbox rules need the MailboxSettings.ReadWrite permission (see the Azure steps above). Do not unsubscribe from spam or phishing: it confirms your address is active. Block those senders instead.

πŸ‘οΈ Read-only mode

Set OUTLOOK_READ_ONLY=true to register only the non-mutating tools. The mutating tools do not exist for the client, so they cannot be called at all. Combine it with a token cache created using only User.Read Mail.Read (set OUTLOOK_SCOPES accordingly and re-run npx -y @pepebits/outlook-mcp auth) for defense in depth.

πŸ›‘οΈ Security

  • πŸ”‘ The token cache is stored locally with mode 0600 in a 0700 directory, written atomically.
  • πŸ™… No client secret exists: this is a public client using device code flow.
  • 🀐 Tokens and message bodies are never logged; MSAL PII logging is disabled.
  • πŸ“₯ Attachment downloads are confined to OUTLOOK_DOWNLOAD_DIR; path traversal is rejected.
  • ⚠️ delete_message with permanent: true is irreversible, and send_mail, reply_message and forward_message send immediately. Prefer read-only mode or create_draft when in doubt.
  • 🧠 Email content is untrusted input: a malicious message may try to instruct the model (prompt injection). Review actions that send or delete.

🩺 Troubleshooting

SymptomFix
AADSTS7000218 (client assertion / secret required)Enable Allow public client flows in Azure -> Manage -> Authentication -> Settings.
AADSTS50020 or wrong tenantThe account type does not match OUTLOOK_TENANT. Use consumers for personal, organizations for work/school, common for both, and make sure the app registration supports that account type.
"Not signed in or session expired"Ask the assistant to call login, or run npx -y @pepebits/outlook-mcp auth.
Search returns "Invalid search query"search_messages uses KQL, e.g. from:alice subject:"report" hasattachments:true. Graph returns at most about 250 results per search, and results are not sorted.
"Message not found" after a moveMessage ids change when a message is moved. Use the newId returned by move_message or list the folder again.
"Access denied for inbox rules"Add MailboxSettings.ReadWrite in Azure -> API permissions, make sure it is in OUTLOOK_SCOPES, then run npx -y @pepebits/outlook-mcp auth again.
Access denied / consent requiredAdd the missing delegated permission, or ask an admin for consent.
Server does not start in a clientCheck stderr logs; if you use your own app, OUTLOOK_CLIENT_ID must be set via .env or the client's env block.

πŸ§‘β€πŸ’» Development

bash
git clone https://github.com/Pepebits/outlook-mcp.gitcd outlook-mcpnpm installcp .env.example .env        # optionalnpm run buildnpm test

Run it from source in your MCP client:

bash
claude mcp add outlook --scope user -- node /absolute/path/outlook-mcp/dist/index.js

Use npm run inspect to try the tools in the MCP Inspector.

🚒 Releasing (maintainers)

  1. Move the [Unreleased] notes in CHANGELOG.md under the new version, bump the version in package.json and server.json (top level and package), commit and push.
  2. Tag it: git tag -a vX.Y.Z -m "Short summary" && git push origin vX.Y.Z. The Release workflow runs the tests, stages the version on npm (Trusted Publishing, with provenance) and creates the GitHub release.
  3. Approve the staged version on npmjs.com (or npm stage approve <stage-id>), which needs your 2FA.
  4. The workflow waits for the approval, lists the version in the MCP Registry and announces the release on Telegram. If you approve more than ~6 hours later, the wait times out: run the Release workflow by hand (Actions β†’ Release β†’ Run workflow) with the tag to announce it.

πŸ—ΊοΈ Roadmap

  • πŸ“… Calendar support (Calendars.ReadWrite)
  • πŸ“¦ Large attachments through upload sessions
  • πŸ‘₯ Contacts

🀝 Contributing

Issues and pull requests are welcome.

bash
npm installnpm run typechecknpm testnpm run build

Please keep code, comments and docs in English, add tests for new behavior, and never log secrets or message content.

πŸ“„ License

MIT

Source: README.md at commit 8505169

Tools

0
Tool metadata has not been indexed yet.

Version history

1
  1. v1.0.1LatestOct 8, 2026