
Outlook Mac Mcp
io.github.valter-araujo由 GitHub 帳號 valter-araujo 發布v0.9.0更新於 Oct 24, 2026
MCP server for Outlook personal accounts (Hotmail/Outlook.com) via Microsoft Graph API
概覽
讓助理透過 Microsoft Graph 讀取與搜尋個人 Outlook.com 或 Hotmail 信箱與行事曆,並可選用需明確開啟的行事曆寫入功能。
- 可以做什麼
- 讀取類工具涵蓋未讀郵件、資料夾清單與未讀及總數統計、依關鍵字搜尋郵件、依 id 取得含內文的郵件、郵件計數、最大郵件、寄件人排行、聯絡人搜尋,以及今天與即將到來的行事曆事件。行事曆的建立、更新與刪除各自是一組先預覽後確認的工具:預覽工具回傳摘要與一次性權杖,對應的套用工具才真正執行變更。寫入與刪除工具在未開啟對應開關時不會註冊。
- 適用情境
- 適合需要讓助理處理官方 Outlook 增益集與 Microsoft 365 連接器不支援的個人 Microsoft 帳戶(Hotmail、Outlook.com、Live),並且希望在不依賴 AppleScript 或桌面應用程式的情況下存取信箱與行事曆。僅供讀取時不需要額外開關。
- 執行需求
- 需要 macOS 13 或以上版本、由 uv 管理的 Python 3.12+,以及 stdio 類型的 MCP 用戶端(例如 Claude Desktop)。需要一次性在 Microsoft Entra ID 註冊應用程式,並在用戶端的 env 區塊中以 OUTLOOK_MCP_CLIENT_ID 提供用戶端 id,還需要一次性裝置代碼登入。需要能透過 HTTPS 連線至 login.microsoftonline.com 與 graph.microsoft.com。選用變數:OUTLOOK_MCP_LOG_LEVEL、OUTLOOK_MCP_TIMEZONE、OUTLOOK_MCP_ENABLE_CALENDAR_WRITE、OUTLOOK_MCP_ENABLE_CALENDAR_DELETE。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 Outlook Mac Mcp,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
outlook-mac-mcp
MCP server for Microsoft Outlook, built for personal Microsoft accounts (Hotmail, Outlook.com, Live) that run on the consumer infrastructure rather than Exchange Online — and are therefore not supported by the official "Claude for Outlook" add-in nor by the Microsoft 365 connector.
Backend: Microsoft Graph API with delegated, user-consented, least-privilege scopes.
Python, transport stdio, no telemetry.
Why not AppleScript
Community MCP servers for Outlook on Mac drive the app through AppleScript. That path only works with Legacy Outlook. In August 2026 Microsoft cancelled the planned AppleScript support in New Outlook, and the transition to New Outlook ends in October 2026. This project deliberately does not depend on it.
The reference environment for this project runs New Outlook (the "Legacy Outlook" toggle is present in the Outlook menu), where AppleScript automation is unavailable. This was the deciding factor.
Technical requirements
Runtime
Microsoft account and app registration
offline_access, openid and profile are reserved scopes: MSAL appends them
to every request on its own and raises if they are passed explicitly. They are
consented at the registration but never appear in the list the code asks for —
that consent is what yields the refresh token behind the Keychain cache.
The app registration may list broader permissions than the server requests. The token only ever carries the scopes the running configuration asks for: the write scope is requested only behind a config flag that is off by default, and turning it on triggers a new sign-in and consent prompt.
Not required
- Microsoft Outlook desktop app (the server talks to Graph, not to the app)
- Exchange Online / Microsoft 365 business tenant
- Accessibility or Automation permissions on macOS
- Node.js, Bun, or any non-Python runtime
Validated environments
Ordered chronologically by validation date (oldest first).
A row moves to validated only after the tools it names return correct results on that environment, against a real mailbox. Contributions of new rows are welcome — please include exact versions.
Validated tools
Sorted alphabetically by tool name. One shipped tool is not in this table yet — it has unit and respx coverage but no live validation against a real mailbox:
search_contacts— no contact exists in the test mailbox to search for yet.
Every tool below has been validated against a real mailbox on the environment above;
search_contacts has unit and respx coverage but no live validation yet (see above).
Search quoting is additionally covered by a live positive-control check, see
Integration tests.
Scope
- v1 (read-only): unread emails, emails by folder (well-known or custom, by full path), search by term, read one email by id (body included), list folders, today's / upcoming events, contact search.
- v2: create and update calendar events — behind a config flag, off by default; delete calendar events — behind a second flag, off by default even when the first one is on; mark as read — not yet built.
- v3: send email — behind a config flag, off by default, with explicit per-call confirmation.
Tools
Read tools are always registered. The four tools marked v2, flagged register only
when OUTLOOK_MCP_ENABLE_CALENDAR_WRITE=true (see
Optional: calendar write). preview_event_deletion and
delete_event, marked v2, flagged + calendar delete, additionally need
OUTLOOK_MCP_ENABLE_CALENDAR_DELETE=true (see
Optional: calendar delete). Sorted alphabetically by tool name.
Custom folders
A custom folder is any folder the user created in Outlook — not one of the five
well-known folders (inbox, archive, junk email, sent items, drafts). search_emails,
list_emails, count_emails, top_senders, list_largest_emails and
list_unread_emails all accept one of the following as their folder argument:
- A well-known folder by name, matched case-insensitively —
folder="inbox",folder="INBOX"andfolder="Archive"all resolve the same way. all— every well-known folder, merged. Custom folders are never included, however many exist:folder="all".- A custom folder by its full path, exactly as
list_foldersreports it undercustom(folder names repeat across a mailbox; the full path is what disambiguates them):folder="Entrevistas/Work/AWS". - A top-level custom folder, which has no parent to qualify it:
folder="Seguros".
Run list_folders first to discover the exact paths available, then pass that string
as folder. Resolving a custom path costs one extra walk of the mailbox's folder tree
per call (the same walk list_folders does for its custom list) — nothing is cached
between calls.
folder combines with every other filter a tool already accepts:
Typos are rejected, not silently misrouted. A folder value close to a well-known
name — one or two characters off, e.g. folder="inbx" — raises an error naming the
value it was likely meant to be ("inbx" is not a recognized folder -- did you mean 'inbox'?) instead of walking the whole mailbox tree looking for a custom folder
literally called inbx.
Known limitation: this typo check is a coarse edit-distance heuristic, not a
dictionary lookup. A genuine custom folder whose name happens to be one edit away from
a well-known one — for example a folder literally named Archives — is
indistinguishable from a typo of archive and gets rejected the same way. Renaming the
folder is the only workaround today.
Security model
- Least privilege: the token can only do what the requested scopes allow, even if the server process is compromised.
- Tokens are stored in the macOS Keychain, never in files or environment variables.
- Email content is treated as untrusted input. The server never acts on instructions found inside message bodies.
- Structured JSON logs go to
stderr(stdout is the MCP transport). Logs contain metadata and counts only — never subjects, bodies, addresses, or contact names.
Architecture
Dependencies point inward. Swapping the backend touches infrastructure/ only.
Architecture at a glance
Dependencies point inward. The Graph adapters implement most ports; the one exception
is Clock, implemented by SystemClock, which lives outside infrastructure/graph
since it never talks to Microsoft. Nothing in domain/ or application/ imports either.
One read call end to end. Input is validated before it becomes a query; logs carry metadata and counts, never content.
Development
Integration tests
Tests marked @pytest.mark.integration reach the real Microsoft Graph API and are
deselected by default. They need a completed sign-in (see
Installation) and the client id in the environment:
They read the signed-in mailbox but never write to it, and they provision their own fixtures: no particular message has to exist, and a test skips rather than fails if the mailbox yields nothing to work with.
One of them is load-bearing rather than incidental. test_search_query_live.py checks
that Graph parses a search term as literal text instead of as a query, by sending the
same string in the safe form and in the form this project used to send, and comparing
result counts against a sender taken from the mailbox itself. A unit test cannot show
this: it can only assert the bytes we send, and every unit test passed while terms were
in fact being executed as queries. Run it after touching anything about how a query is
quoted, escaped or encoded.
Installation
1. Register the app in Microsoft Entra ID
Follow the table under Microsoft account and app registration. Note the Application (client) ID — it is not a secret, but it identifies your registration and does not belong in this repository.
2. Install
3. Sign in once
The MCP server never starts a sign-in of its own: the device-code flow blocks for minutes waiting for a browser, and a stdio server has nowhere to show the code, because stdout carries the MCP protocol. Authenticate out of band instead:
The code and the URL are printed to stderr. Open the URL, enter the code, and approve
the requested scopes. The resulting token is stored in the macOS Keychain under the
service outlook-mac-mcp; it is never written to a file or an environment variable.
Repeat this only when the refresh token expires or you revoke consent.
4. Point Claude Desktop at the server
Edit ~/Library/Application Support/Claude/claude_desktop_config.json:
Three things this configuration has to get right:
OUTLOOK_MCP_CLIENT_IDmust be in theenvblock. Claude Desktop launches the server as a GUI process, which does not inherit your shell environment: anexportin~/.zshrcis invisible to it. Theenvblock is the only thing the server sees.- Use an absolute path in
--directory. The launched process does not start in your project directory. uvmust be on the launcher'sPATH, which is likewise not your shell's. If the server fails to start, replace"command": "uv"with the absolute path fromwhich uv(typically~/.local/bin/uv).
Restart Claude Desktop. list_unread_emails and the other read tools should appear in
the tool list; the four create/update tools appear only with the write flag on, and
preview_event_deletion/delete_event need the delete flag on top of that (see
Optional: calendar delete).
Optional: log level
OUTLOOK_MCP_LOG_LEVEL sets the verbosity (default INFO). Structured JSON logs go to
stderr and carry metadata only — tool name, correlation id, duration, outcome and item
count, never subjects, addresses or bodies. Add it to the same env block.
Optional: time zone
Calendar tools express every time in one zone and decide what "today" means from it.
By default that is the machine's time zone, as reported by the operating system. To
override it, add OUTLOOK_MCP_TIMEZONE with an IANA name (for example
America/Sao_Paulo or Europe/Lisbon) to the same env block. The name is validated
at startup: an unknown one stops both the server and sign-in with a
ConfigurationError. The resolved zone is logged at startup.
Optional: calendar write
Off by default. Setting OUTLOOK_MCP_ENABLE_CALENDAR_WRITE=true in the env block
does two things: the server requests the Calendars.ReadWrite scope in addition to the
read scopes, and it registers the create and update tools. Accepted values are true,
false, 1 and 0; anything else stops the server with a ConfigurationError.
Because the scope set changes, the token already in the Keychain no longer satisfies it and every tool fails with "no usable cached credential" until you sign in again. Run the sign-in with the flag set in the same shell, and approve the new consent prompt, which now lists calendar write access:
Turning the flag off again does not shrink the consent already granted; revoke it at https://account.live.com/consent/Manage if you want the write permission gone.
With the flag on, four tools appear, as two independent preview-then-confirm pairs: create and update. A third pair, delete, needs its own additional flag on top of this one — see Optional: calendar delete — precisely because it is the one pair whose apply step cannot be undone. Each pair is always a two-step handshake, and each has its own token namespace — a token from one pair is refused by every other pair's apply tool, not just reused within its own.
preview_eventtakes the full details of a new event — subject; start and end with UTC offsets; an all-day flag; an optional free-text location; an optional plain-text body, up to 32,768 characters; up to 50 attendee addresses; an optional reminder lead time in minutes; an optional sensitivity (normal,personal,privateorconfidential); and an optional free/busy status to show as (free,tentative,busy,ooforworkingElsewhere) — validates them, and returns a one-line summary plus an opaque token. Nothing is written.create_eventtakes only that token and performs the real change.preview_event_updatetakes an event id and any subset of the same fields except the all-day flag, which is never changeable after creation and always carries over from the current event: subject, start, end, location, body, attendees, reminder lead time, sensitivity and show-as. It fetches the current event, and returns a token plus a summary showing the diff for each changed field as old value -> new value — never just the resulting state. A field left out of the call is left exactly as it is.update_eventtakes only that token and applies just the changed fields.
Every apply tool's token works exactly once and only within the same server process; an unknown token, an already used token, or a token issued by a different pair's preview tool is refused, and a server restart discards every pending draft. This rule holds across every pair, including delete, described next.
Every tool description instructs the client to show the summary and get the user's agreement before applying, and to get explicit confirmation of every detail before even previewing when any of it came from email content. Email is untrusted input; a message can be written to talk a model into changing your calendar, and the user, never the email, decides.
Optional: calendar delete
Off by default, and independent of calendar write — setting
OUTLOOK_MCP_ENABLE_CALENDAR_DELETE=true by itself does nothing.
preview_event_deletion and delete_event register only when both flags are
true: calendar write builds the Graph calendar writer these two tools call through,
and this flag then adds the one irreversible action on top of it. No additional Graph
scope is requested — Calendars.ReadWrite, already required by calendar write, covers
delete on the Graph side too, so no extra consent prompt is needed beyond the one from
Optional: calendar write.
preview_event_deletion takes an event id, fetches the current event, and returns a
token plus a summary showing every field of the event, unabbreviated — subject, start,
end, location, body and attendees — so the confirmation shows exactly what would be
removed. This matters most when two similar events exist and only their full detail
tells them apart. delete_event takes only that token and deletes the event; this
cannot be undone by the server. The pair follows the same token rules as create and
update — single use, its own namespace, refused by every other pair's apply tool.
Troubleshooting
Disclaimer
This project is provided "as is", without warranty of any kind (see LICENSE). The author is not responsible for how others configure, run, or deploy this code, nor for data loss or any other consequence of doing so.
The calendar-write tools perform real changes through Microsoft Graph, and
delete_event cannot be undone by this server. Test against a low-stakes or
disposable event first — see Optional: calendar
write — before relying on it for anything that
matters.
License
MIT
來源:README.md,提交 5293ca7
工具
0版本歷史
2- v0.9.0最新Sep 18, 2026
- v0.7.0Sep 17, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分