关于 outlook-mac-mcp
outlook-mac-mcp 通过 Microsoft Graph 将 MCP 客户端连接到 Outlook 邮箱,面向个人 Microsoft 账户,也支持工作或学校账户。它提供邮件读取与搜索工具,日历修改则需通过配置标志启用。
主要功能
- 01列出、搜索、计数和读取邮件
- 02浏览邮箱文件夹并统计发件人
- 03查看当天和即将到来的日历事件
- 04按姓名前缀或完整邮箱搜索联系人
- 05启用后预览并应用日历修改
适用场景
- 01按发件人、日期或搜索词查找邮件
- 02检查未读邮件和大容量邮件
- 03查看日历中的近期活动
- 04应用前预览日历修改
MCP 相关
该 stdio MCP 服务通过 Microsoft Graph 向 MCP 客户端提供 Outlook 邮件、日历和联系人工具。创建、更新和删除日历事件需启用配置标志;目前尚未实现邮件发送。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
outlook-mac-mcp
适用于 Microsoft Outlook 的 MCP 服务,专为使用消费级基础设施而非 Exchange Online 的个人 Microsoft 帐户 (Hotmail、Outlook.com、Live)打造,因此官方的 “Claude for Outlook”加载项和 Microsoft 365 连接器均不支持这些帐户。
后端:Microsoft Graph API,使用经用户同意的委派式最小权限范围。
Python,传输方式为 stdio,不收集遥测数据。
为什么不使用 AppleScript
社区开发的 Outlook Mac MCP 服务会通过 AppleScript 操控应用。此方式仅适用于旧版 Outlook。2026 年 8 月,Microsoft 取消了在新版 Outlook 中支持 AppleScript 的计划,且向新版 Outlook 的迁移将于 2026 年 10 月结束。本项目有意不依赖 AppleScript。
本项目的参考环境运行的是新版 Outlook(Outlook 菜单中有“旧版 Outlook”切换项),该环境无法使用 AppleScript 自动化。这是决定不采用 AppleScript 的关键因素。
技术要求
运行环境
| 组件 | 要求 | 说明 |
|---|---|---|
| macOS | 13 Ventura 或更高版本 | 使用 Keychain 存储令牌 |
| Python | 3.12+ | 使用 uv 管理;依赖版本固定在 uv.lock 中 |
| MCP 客户端 | 任意 stdio 客户端(Claude Desktop、Claude Code) | 已通过 Claude Desktop 测试 |
| 网络 | 仅允许通过 HTTPS 连接到 login.microsoftonline.com 和 graph.microsoft.com | 不会向其他地址发起出站请求 |
Microsoft 帐户和应用注册
| 项目 | 要求 |
|---|---|
| 帐户类型 | 个人 Microsoft 帐户(Hotmail / Outlook.com / Live)或工作/学校帐户 |
| 应用注册 | 在 Microsoft Entra ID 中注册一次(免费;个人帐户需要有自己的租户,可通过 Azure Portal 创建) |
| 支持的帐户类型 | “任何组织目录中的帐户和个人 Microsoft 帐户” |
| 身份验证 | 设备代码流(MSAL,公共客户端,无客户端密钥) |
| Authority | https://login.microsoftonline.com/consumers |
| 默认请求的范围 | Mail.Read、Calendars.Read、Contacts.Read、offline_access、User.Read |
OUTLOOK_MCP_ENABLE_CALENDAR_WRITE=true 时添加的范围 | Calendars.ReadWrite(参见可选:日历写入) |
| 管理员同意 | 不需要——上述每个范围均可由用户同意 |
offline_access、openid 和 profile 是保留范围:MSAL 会自行将它们添加到每个请求中,如果显式传入则会报错。应用注册时会为这些范围授予同意,但它们不会出现在代码请求的范围列表中;正是这项同意生成了 Keychain 缓存使用的刷新令牌。
应用注册中列出的权限可以比服务请求的权限更广泛。令牌只会包含当前运行配置所请求的范围:只有在配置标志开启时才会请求写入范围,而该标志默认关闭;开启后会触发重新登录和同意提示。
不需要
- Microsoft Outlook 桌面应用(服务直接与 Graph 通信,不与应用通信)
- Exchange Online / Microsoft 365 商业租户
- macOS 辅助功能或自动化权限
- Node.js、Bun 或任何非 Python 运行环境
已验证的环境
按验证日期的时间顺序排列(从最早到最晚)。
| 版本 | 操作系统 | Python | MCP 客户端 | 账户类型 | 已安装的 Outlook 应用 | 状态 |
|---|---|---|---|---|---|---|
| 0.1.0 | macOS 27.0 (Golden Gate), Apple M5 | 3.14.7 | Claude Desktop | 个人(@hotmail.com) | Outlook for Mac 16.112.4 (26090911),新版 Outlook,M365 Subscription — 服务未使用 | 已验证 2026-09-14 |
| 0.2.0(启用日历写入) | macOS 27.0 (Golden Gate), Apple M5 | 3.14.7 | Claude Desktop | 个人(@hotmail.com) | 同上 | 已验证 2026-09-15 |
| 0.9.0(截至 delete_event) | macOS 27.0 (Golden Gate), Apple M5 | 3.14.7 | Claude Desktop | 个人(@hotmail.com) | 同上 | 已验证 2026-09-17 |
只有当该行列出的工具在相应环境中针对真实邮箱返回正确结果后,才会将其状态设为 已验证。欢迎提交新增行,请注明准确的版本号。
已验证的工具
按工具名称的字母顺序排列。有一个已发布的工具尚未列入此表 — 它有单元测试和 respx 覆盖,但尚未针对真实邮箱进行实时验证:
search_contacts— 测试邮箱中目前还没有可供搜索的联系人。
| 工具 | 验证日期 | 检查内容 |
|---|---|---|
count_emails | 2026-09-15 | 按一个月的接收时间范围查询,返回了准确计数。 |
create_event | 2026-09-15, 2026-09-16, 2026-09-17 | 创建了定时事件和全天事件;Graph 接受了使用解析后时区名称的全天事件负载,且两者返回后均可正常读取。预览中的正文已正确写入所创建的事件。没有正文的事件也成功创建,确认已修复 Graph 将未发送的正文默认设为 HTML 的问题。 |
delete_event | 2026-09-17 | 删除了在 preview_event_deletion 下预览的事件令牌对应的事件;直接在 Outlook 中确认该事件已从日历中移除。 |
get_email | 2026-09-14 | 返回了文本正文,并遵循 Prefer 标头;格式错误的 ID nope 返回为 ErrorInvalidIdMalformed,并映射为 InvalidRequestError。 |
list_emails | 2026-09-15 | sort=oldest、limit=1 返回了文件夹中最早的邮件及准确总数;精确发件人筛选搭配 sort=newest 返回了唯一匹配项,且 Graph 接受发件人筛选与 $orderby 组合使用,没有出现 InefficientFilter 错误。 |
list_folders | 2026-09-17 | 正确发现了 100 多个自定义文件夹,包括多层嵌套的文件夹,每个文件夹的未读数和总数均准确。实时确认了文档所述的限制:没有公认标志的 Microsoft 管理文件夹(Deleted Items)按预期显示在 custom 中,与真正由用户创建的文件夹并列。 |
list_largest_emails | 2026-09-16 | 返回了按扩展属性中真实大小排序的结果,skipped 接近零。 |
list_todays_events | 2026-09-15 | 在没有事件的日期准确返回了零个事件。 |
list_unread_emails | 2026-09-14 | 通过 Graph 读取 Hotmail 收件箱。 |
list_upcoming_events | 2026-09-15 | 按最早时间优先返回了匹配的事件;确认全天事件和定时事件均正确映射到解析后的时区。 |
preview_event | 2026-09-15, 2026-09-16 | 返回了定时事件和全天事件的摘要与令牌;未达到截断阈值的正文在预览中完整显示,且与原文一致。 |
preview_event_deletion | 2026-09-17 | 在执行任何删除之前,显示了完整事件(包含每个字段,未作缩写),并给出了不可撤销警告。 |
preview_event_update | 2026-09-17 | 时间更改(10:00–10:30 -> 11:00–11:30)生成了差异摘要,仅显示已更改字段及旧值 -> 新值。 |
search_emails | 2026-09-14, 2026-09-15, 2026-09-17 | 匹配多封邮件的词语返回了准确总数;scope=subject 和 scope=sender 各自返回了范围更窄但仍准确的子集;试图跳出短语范围的词语未匹配到任何内容,也没有返回 400。将 next_page_token 作为 page_token 传回后,返回了内容确实不同的第二页(日期范围不同,且没有重复第一页中的项目),该页的 total/total_is_exact 仍然准确。 |
top_senders | 2026-09-15 | 完整扫描收件箱时触及了配置的上限,并返回 coverage_is_complete=false;客户端按描述要求明确报告了覆盖不完整。 |
update_event | 2026-09-17 | 精确应用了预览中的时间更改(10:00–10:30 -> 11:00–11:30);更新后的事件仅反映了这一更改。 |
以下每个工具都已在上述环境中针对真实邮箱完成验证;search_contacts 有单元测试和 respx 覆盖,但尚未进行实时验证(见上文)。
搜索引号处理还通过实时正向对照检查进行了验证,参见
集成测试。
范围
- v1(只读): 未读邮件、按文件夹(已知文件夹或自定义文件夹,通过完整路径)获取邮件、按词条搜索、按 ID 读取一封邮件(包含正文)、列出文件夹、今天 / 即将到来的日历事件、搜索联系人。
- v2: 创建和更新日历事件——需通过配置标志启用,默认关闭;删除日历事件——需通过第二个标志启用,即使第一个标志已开启,默认仍关闭;标记为已读——尚未实现。
- v3: 发送邮件——需通过配置标志启用,默认关闭,并且每次调用都需明确确认。
工具
读取工具始终会注册。标记为 v2, flagged 的四个工具仅在 OUTLOOK_MCP_ENABLE_CALENDAR_WRITE=true 时注册(请参阅
可选:日历写入)。标记为 v2, flagged + calendar delete 的 preview_event_deletion 和
delete_event 还需设置 OUTLOOK_MCP_ENABLE_CALENDAR_DELETE=true(请参阅
可选:日历删除)。按工具名称的字母顺序排序。
| 工具 | 功能 |
|---|---|
count_emails | 使用与 list_emails 相同的筛选条件,精确统计匹配的邮件数量,但不列出邮件。 |
create_event (v2, flagged) | 创建通过 preview_event 预览并由令牌标识的日历事件。 |
delete_event (v2, flagged + calendar delete) | 删除通过 preview_event_deletion 预览并由令牌标识的日历事件。此操作不可撤销。 |
get_email | 按 ID 获取一封邮件,包含正文。 |
list_emails | 列出文件夹中的邮件,可组合使用任意筛选条件(已读状态、发件人、日期范围、附件),按时间从新到旧或从旧到新排序,并返回精确总数。 |
list_folders | 列出邮箱的已知文件夹及其未读和项目总数,并通过遍历邮箱目录树列出每个用户创建的文件夹,每个文件夹均以完整路径标识。 |
list_largest_emails | 按字节大小从大到小列出文件夹中最大的邮件;每次调用最多扫描 10,000 封匹配邮件。无法确定大小的邮件会单独计入 skipped。 |
list_todays_events | 按时间从早到晚列出今天的日历事件。 |
list_unread_emails | 按时间从新到旧列出文件夹中的未读邮件。 |
list_upcoming_events | 列出从现在起至未来 1–30 天内的日历事件。 |
preview_event (v2, flagged) | 验证新日历事件并返回令牌和摘要,但不创建事件。 |
preview_event_deletion (v2, flagged + calendar delete) | 获取现有日历事件并返回令牌和摘要,完整显示所有字段,不删除任何内容。 |
preview_event_update (v2, flagged) | 获取现有日历事件,验证请求的更改,并返回令牌和差异摘要(旧值 -> 新值,仅显示已更改的字段),但不应用任何更改。 |
search_contacts | 按显示名称前缀或完整匹配的电子邮件地址搜索联系人。 |
search_emails | 在文件夹中搜索词条,并按相关性而非日期排序。 |
top_senders | 按发件人发送的邮件数量对文件夹中的发件人排序;每次调用最多扫描 10,000 封匹配邮件。 |
update_event (v2, flagged) | 应用通过 preview_event_update 预览并由令牌标识的更改。仅更改实际传递给预览的字段。 |
自定义文件夹
自定义文件夹是指用户在 Outlook 中创建的任何文件夹,不包括五个已知文件夹(收件箱、归档、垃圾邮件、已发送邮件、草稿)。search_emails、list_emails、count_emails、top_senders、list_largest_emails 和 list_unread_emails 都接受以下某一种值作为 folder 参数:
- 按名称指定已知文件夹,不区分大小写 —
folder="inbox"、folder="INBOX"和folder="Archive"都会解析为同一个文件夹。 all— 合并所有已知文件夹。无论有多少个自定义文件夹,都不会包含它们:folder="all"。- 按完整路径指定自定义文件夹,路径必须与
list_folders在custom下报告的完全一致(一个邮箱中可能有多个同名文件夹;完整路径可用于区分它们):folder="Entrevistas/Work/AWS"。 - 顶层自定义文件夹,即没有父文件夹的文件夹:
folder="Seguros"。
先运行 list_folders,查找可用的确切路径,然后将该字符串作为 folder 传入。解析自定义路径时,每次调用都会额外遍历一次邮箱的文件夹树(与 list_folders 为其 custom 列表所做的遍历相同);调用之间不会缓存结果。
folder 可与工具已接受的所有其他筛选条件组合使用:
# Well-known folder (unchanged)
search_emails(term="Cargill", folder="archive")
# All well-known folders (unchanged — never includes custom folders)
count_emails(folder="all")
# A custom folder, addressed by its full path
list_emails(folder="Entrevistas/Work/AWS", sort="oldest")
# A top-level custom folder
top_senders(folder="Seguros")
# A custom folder combined with a date range
list_emails(
folder="Entrevistas/Work/AWS",
received_after="2026-01-01T00:00:00+00:00",
sort="oldest",
)
# A custom folder combined with an exact sender filter
count_emails(folder="Entrevistas/Work/AWS", sender="[email protected]")
# A custom folder combined with a search term
search_emails(term="offer letter", folder="Entrevistas/Work/AWS")
拼写错误会被拒绝,不会被悄悄路由到其他文件夹。 如果 folder 值与某个已知文件夹名称接近,相差一两个字符,例如 folder="inbx",就会报错并指出它可能想要指定的值("inbx" is not a recognized folder -- did you mean 'inbox'?),而不会遍历整个邮箱的文件夹树,去查找名为 inbx 的自定义文件夹。
已知限制: 此拼写检查采用粗略的编辑距离启发式算法,而非词典查找。名称恰好与某个已知文件夹名称相差一个字符的真实自定义文件夹——例如名为 Archives 的文件夹——无法与 archive 的拼写错误区分,因此也会被拒绝。目前唯一的解决办法是重命名该文件夹。
安全模型
- 最小权限:令牌只能执行所请求的作用域允许的操作,即使服务进程遭到入侵也不例外。
- 令牌存储在 macOS Keychain 中,绝不会存储在文件或环境变量里。
- 电子邮件内容一律视为不可信输入。服务绝不会执行邮件正文中的指令。
- 结构化 JSON 日志写入
stderr(stdout用于 MCP 传输)。日志仅包含元数据和计数,不包含主题、正文、地址或联系人姓名。
架构
domain/ entities and rules — no Graph, no MCP
application/ use cases depending on ports (interfaces)
infrastructure/ Graph API adapter — the only place that knows Microsoft
interface/mcp/ tool registration and input/output translation only
依赖关系向内指向。更换后端只需改动 infrastructure/。
架构概览
依赖关系向内指向。Graph 适配器实现了大多数端口;唯一的例外是 Clock,由 SystemClock 实现。由于它从不与 Microsoft 通信,因此位于 infrastructure/graph 之外。domain/ 和 application/ 中的内容都不会导入这两者。
flowchart TB
subgraph interface["interface/mcp — translation only"]
tools["MCP tools<br/>pydantic input · flat output views"]
end
subgraph application["application — use cases"]
uc["ListUnreadEmails · SearchEmails · GetEmail<br/>ListEmails · CountEmails · TopSenders · ListLargestEmails<br/>ListTodaysEvents · ListUpcomingEvents<br/>PreviewEvent · CreateEvent<br/>PreviewEventUpdate · UpdateEvent<br/>PreviewEventDeletion · DeleteEvent<br/>ListFolders · SearchContacts"]
ports["Ports (Protocol)<br/>MailRepository · CalendarRepository · CalendarWriter<br/>ContactRepository · MailFolderRepository · Clock"]
end
subgraph domain["domain — entities and rules"]
ent["Email · Event · Contact · Page · TimeWindow<br/>frozen dataclasses · no Graph, no MCP"]
end
subgraph infra["infrastructure/graph — the only place that knows Microsoft"]
adapters["Graph adapters<br/>query builders · JSON→entity mappers"]
auth["MSAL device-code<br/>token cache in macOS Keychain"]
http["httpx client<br/>host-pinned to graph.microsoft.com"]
end
clock["infrastructure/system_clock<br/>SystemClock — reads the resolved time zone"]
tools --> uc
uc --> ports
uc --> ent
adapters -. implements .-> ports
clock -. implements .-> ports
adapters --> http
http --> auth
一次读取调用的完整流程。输入会先经过验证,然后才成为查询;日志仅记录元数据和计数,不记录内容。
sequenceDiagram
participant CD as Claude Desktop
participant S as MCP server (stdio)
participant UC as Use case
participant A as Graph adapter
participant K as macOS Keychain
participant G as Microsoft Graph
CD->>S: tools/call list_unread_emails {folder, limit}
S->>S: validate input (pydantic) → request object
S->>UC: execute(request)
UC->>A: list_unread(folder, limit)
A->>K: read cached token (MSAL silent refresh)
K-->>A: access token
A->>G: GET /me/mailFolders/inbox/messages?$filter…&$orderby…&$top…&$count=true
G-->>A: JSON page + @odata.count
A-->>UC: Page[Email]
UC-->>S: Page[Email]
S-->>CD: {items, returned, total, total_is_exact}
Note over S: JSON log to stderr: correlation id, tool, duration, count — never content
开发
uv sync
uv run ruff check .
uv run ruff format --check .
uv run mypy
uv run pytest
集成测试
标记为 @pytest.mark.integration 的测试会访问真实的 Microsoft Graph API,默认会被排除。它们需要已完成登录(参见[安装](#3-sign-in-once)),并且环境中要有客户端 ID:
export OUTLOOK_MCP_CLIENT_ID=<your client id>
uv run pytest -m integration
这些测试会读取已登录的邮箱,但绝不会向其中写入内容,并且会自行准备测试夹具:无需存在特定邮件;如果邮箱中没有可供测试的内容,测试会跳过,而不是失败。
其中有一个测试至关重要,并非可有可无。test_search_query_live.py 会验证 Graph 将搜索词解析为字面文本,而不是查询:它会以安全形式和本项目之前使用的形式发送同一个字符串,并将结果数量与从邮箱本身获取的发件人进行比较。单元测试无法证明这一点:它只能断言我们发送的字节,而事实上,即使搜索词被当作查询执行,所有单元测试也都能通过。修改任何与查询引用、转义或编码有关的内容后,都要运行此测试。
安装
1. 在 Microsoft Entra ID 中注册应用
按照Microsoft 帐户和应用注册下的表格操作。记下应用程序(客户端)ID——它不是机密,但用于标识你的注册信息,不应放入此仓库。
2. 安装
git clone https://github.com/valter-araujo/outlook-mac-mcp.git
cd outlook-mac-mcp
uv sync
3. 登录一次
MCP 服务不会自行启动登录流程:设备代码流程会阻塞数分钟等待浏览器,而 stdio 服务没有地方显示代码,因为 stdout 承载着 MCP 协议。请改为通过带外方式进行身份验证:
export OUTLOOK_MCP_CLIENT_ID=<your client id>
uv run outlook-mac-mcp sign-in
代码和 URL 会打印到 stderr。打开 URL,输入代码并批准请求的权限范围。生成的令牌会存储在 macOS Keychain 的 outlook-mac-mcp 服务下;它绝不会写入文件或环境变量。
只有在刷新令牌过期或你撤销授权时,才需要重新执行此操作。
4. 将 Claude Desktop 指向此服务
编辑 ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"outlook-mac-mcp": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/outlook-mac-mcp", "run", "outlook-mac-mcp"],
"env": {
"OUTLOOK_MCP_CLIENT_ID": "<your client id>"
}
}
}
}
此配置需要正确设置以下三项:
OUTLOOK_MCP_CLIENT_ID必须位于env块中。 Claude Desktop 会将服务作为 GUI 进程启动,因此不会继承你的 shell 环境:在~/.zshrc中执行的export对它不可见。env块是服务唯一能读取到的配置。- 在
--directory中使用绝对路径。 启动的进程不会从你的项目目录开始运行。 - **
uv必须位于启动器的PATH中,**这同样不是你的 shell 的PATH。如果服务无法启动,请将"command": "uv"替换为which uv返回的绝对路径(通常为~/.local/bin/uv)。
重启 Claude Desktop。list_unread_emails 和其他读取工具应会出现在工具列表中;四个创建/更新工具仅在启用写入标志时才会出现,而 preview_event_deletion/delete_event 还需要启用删除标志(参见可选:日历删除)。
可选:日志级别
OUTLOOK_MCP_LOG_LEVEL 用于设置详细程度(默认值为 INFO)。结构化 JSON 日志会写入 stderr,且仅包含元数据——工具名称、关联 ID、耗时、结果和项目数量,不会包含主题、地址或正文。将其添加到同一个 env 块中。
可选:时区
日历工具会统一使用一个时区表示所有时间,并以此确定“今天”的日期。默认情况下,这就是操作系统报告的计算机时区。若要覆盖默认值,请将 OUTLOOK_MCP_TIMEZONE 与 IANA 名称(例如 America/Sao_Paulo 或 Europe/Lisbon)一起添加到同一个 env 块中。服务启动时会验证该名称:如果名称无效,服务和 sign-in 都会因 ConfigurationError 而停止。启动时会记录解析后的时区。
可选:日历写入
默认关闭。在 env 块中设置 OUTLOOK_MCP_ENABLE_CALENDAR_WRITE=true 会带来两项变化:服务会在读取范围之外请求 Calendars.ReadWrite 范围,并注册创建和更新工具。接受的值为 true、false、1 和 0;其他任何值都会导致服务以 ConfigurationError 停止。
由于范围集合发生变化,Keychain 中已有的令牌将不再满足要求,因此在你重新登录之前,所有工具都会失败并提示“no usable cached credential”。请在同一个 shell 中设置该标志后运行登录,并批准新的授权提示,其中现在会列出日历写入权限:
export OUTLOOK_MCP_CLIENT_ID=<your client id>
export OUTLOOK_MCP_ENABLE_CALENDAR_WRITE=true
uv run outlook-mac-mcp sign-in
再次关闭该标志不会缩减已授予的权限;如果你想撤销写入权限,请前往 https://account.live.com/consent/Manage 撤销。
启用该标志后,会出现四个工具,组成两组独立的“预览后确认”配对:创建和更新。第三组配对是删除,需要在此标志之外再启用一个额外标志——请参阅可选:日历删除——正是因为它是唯一无法撤销应用操作的一组配对。每组配对始终采用两步握手,且各自拥有独立的令牌命名空间:某组配对的令牌会被其他所有配对的应用工具拒绝,而不仅仅是不能在本组之外重复使用。
preview_event接收新事件的完整详情——主题;带 UTC 偏移量的开始和结束时间;全天标志;可选的自由文本地点;可选的纯文本正文,最多 32,768 个字符;最多 50 个与会者地址;可选的提醒提前时间(分钟);可选的敏感度(normal、personal、private或confidential);以及可选的显示为忙闲状态(free、tentative、busy、oof或workingElsewhere)——对其进行验证,并返回一行摘要和一个不透明令牌。不会写入任何内容。create_event只接收该令牌并执行实际更改。preview_event_update接收事件 ID 以及相同字段的任意子集,全天标志除外;创建后无法更改该标志,并且始终沿用当前事件的值。可更新字段包括:主题、开始时间、结束时间、地点、正文、与会者、提醒提前时间、敏感度和显示为状态。该工具会获取当前事件,并返回一个令牌和一份摘要,其中逐项显示每个已更改字段的差异,即旧值 -> 新值,而不是只显示更改后的状态。调用中未提供的字段将保持原样。update_event只接收该令牌,并仅应用已更改的字段。
每个应用工具的令牌都只能使用一次,且仅在同一服务进程中有效;未知令牌、已使用的令牌,或由其他配对的预览工具签发的令牌都会被拒绝;服务重启后,所有待处理草稿都会被清除。下一节介绍的删除配对也遵循此规则。
每个工具的说明都会指示客户端在应用更改前展示摘要并征得用户同意;如果任何内容来自电子邮件,还必须在预览前就每个细节征得明确确认。电子邮件是不可信输入;邮件可以被精心编写,用来诱使模型更改你的日历,而决定权始终在用户手中,绝不在邮件手中。
可选:删除日历事件
默认关闭,且独立于日历写入——仅设置
OUTLOOK_MCP_ENABLE_CALENDAR_DELETE=true 不会产生任何效果。
只有两个标志都设为 true 时,才会注册 preview_event_deletion 和 delete_event:日历写入会构建这两个工具调用所需的 Graph 日历写入器,而此标志则会在此基础上增加唯一不可逆的操作。不会请求额外的 Graph 权限范围——日历写入本就需要的 Calendars.ReadWrite 在 Graph 端也涵盖删除操作,因此无需在可选:日历写入之外额外征求授权。
export OUTLOOK_MCP_CLIENT_ID=<your client id>
export OUTLOOK_MCP_ENABLE_CALENDAR_WRITE=true
export OUTLOOK_MCP_ENABLE_CALENDAR_DELETE=true
uv run outlook-mac-mcp sign-in
preview_event_deletion 接收事件 ID,获取当前事件,并返回一个令牌和一份摘要,完整展示事件的每个字段,不作缩写——主题、开始时间、结束时间、位置、正文和参会者——以便确认时准确显示将被删除的内容。当存在两个相似事件,只有完整详情才能区分它们时,这一点尤为重要。delete_event 只接收该令牌并删除事件;服务端无法撤销此操作。这对工具遵循与创建和更新相同的令牌规则——令牌只能使用一次,使用独立命名空间,并且其他任何工具对都无法使用其令牌。
故障排除
| 症状 | 原因 |
|---|---|
| 工具失败并提示“no usable cached credential” | 尚未完成步骤 3,或令牌已被撤销。请重新运行 sign-in。 |
服务启动失败并显示 ConfigurationError | env 块中缺少 OUTLOOK_MCP_CLIENT_ID,或 OUTLOOK_MCP_TIMEZONE 不是 IANA 时区名称。 |
| Claude Desktop 中未显示服务 | 启动器的 PATH 中没有 uv;请为 command 使用绝对路径。 |
免责声明
本项目按“原样”提供,不附带任何形式的保证(参见 LICENSE)。作者不对他人如何配置、运行或部署此代码负责,也不对由此造成的数据丢失或任何其他后果负责。
日历写入工具会通过 Microsoft Graph 执行实际更改,并且此服务无法撤销 delete_event 操作。请先使用影响较小或可丢弃的事件进行测试——参见可选:日历写入——再将其用于任何重要事项。
许可证
MIT
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。