owa mcp
A. 模型上下文协议(MCP) 允许Claude Code完全访问您的Microsoft Outlook日历和电子邮件的服务器-- 无需Azure应用程序注册.
运作原理
Microsoft Outlook Web(Outlook.office.com)在Playwright控制的无头Microsoft Edge浏览器中运行,该浏览器使用您现有的已登录Edge配置文件。当OutlookWeb加载时,它为自己的内部API调用发布Bearer令牌。此服务器拦截这些令牌并针对 outlook.office.com/api/v2.0 REST端点。
结果:满 Calendars.ReadWrite 和 Mail.ReadWrite 只要您已经在Edge浏览器中登录了Microsoft 365,就可以在没有OAuth应用程序注册、没有客户端ID和没有IT参与的情况下使用范围。
代币在约80分钟后过期。 服务器通过在后台重新启动无头浏览器自动刷新。
为什么采用这种方法
许多企业Microsoft 365租户执行阻止第三方OAuth流的条件访问策略(例如Azure CLI、自定义应用程序注册)。托管设备可能会限制哪些应用程序可以进行身份验证。浏览器会话拦截方法之所以有效,是因为它依赖于一个已经满足所有策略要求的身份验证流——与Outlook Web本身使用的相同。
先决条件
- macOS(在macOS 15上测试)
- 微软边缘 安装在
/Applications/Microsoft Edge.app - 在Edge中登录Microsoft 365(打开Edge,转到outlook.office.com,确认您看到了日历)
- Node.js 20+
安装
claude mcp add owa -s user -- npx owa-mcp就是这样。重新启动Claude Code——您应该看到可用的日历工具。
Manual installation (alternative)
git clone https://github.com/benpeter/owa-mcp
cd owa-mcp
npm install
npm run build
claude mcp add owa -s user -- node /absolute/path/to/owa-mcp/dist/index.js可用工具
get_calendar_events
返回时间范围内的日历事件。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
startDateTime | string | 是 | ISO 8601开始 |
endDateTime | string | 是 | ISO 8601结束 |
maxResults | number | no | 最大事件数(默认50,最大100) |
timezone | string | no | IANA时区(默认UTC) |
create_calendar_event
创建新事件。添加与会者会自动发送邀请。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
subject | string | 是 | 事件标题 |
startDateTime | string | yes | 不带偏移量的本地日期时间 |
endDateTime | string | yes | 不带偏移量的本地日期时间 |
timezone | string | no | Windows时区名称(默认“西欧标准时间”) |
body | string | 否 | 事件描述 |
location | string | 否 | 位置名称 |
attendees | 数组 | 否 | [{ email, name?, type? }] --发送邀请 |
isAllDay | boolean | 否 | 全天事件 |
showAs | string | no | 空闲、暂时、忙碌、Oof、在别处工作 |
isOnlineMeeting | boolean | 否 | 创建为团队会议 |
hideAttendees | boolean | 否 | 对其他与会者隐藏与会者列表(默认为false) |
responseRequested | boolean | 否 | 向与会者请求RSVP(默认为true) |
reminderMinutes | number | no | 开始前几分钟提醒。Outlook默认省略,0禁用 |
recurrence | object | 否 | 将此设置为重复事件。看 复发 在......下面 |
update_calendar_event
更新现有事件的字段。仅包括要更改的字段。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
eventId | string | yes | 事件ID |
subject | string | 否 | 新标题 |
startDateTime | string | 否 | 新开始时间 |
endDateTime | string | no | 新结束时间 |
timezone | string | no | 开始/结束时区 |
body | string | no | 新建正文(注意:覆盖团队加入链接) |
location | string | 否 | 新位置 |
showAs | string | no | 新显示为状态 |
isPrivate | boolean | 否 | 标记为私有 |
hideAttendees | boolean | 否 | 对其他与会者隐藏与会者列表 |
responseRequested | boolean | 否 | 向与会者请求RSVP |
reminderMinutes | number | no | 开始前几分钟提醒。0禁用 |
recurrence | object | 否 | 更改重复模式。仅适用于系列主事件。看 复发 在......下面 |
cancel_calendar_event
取消您组织的会议。向与会者发送取消通知并说明原因。支持重复的系列操作。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
eventId | string | yes | 事件ID |
reason | string | 否 | 已向与会者发送取消原因 |
scope | string | 否 | single (默认), thisAndFollowing,或 allInSeries |
delete_calendar_event
从日历中静默删除事件(不发送通知)。支持重复的系列操作。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
eventId | string | yes | 事件ID |
scope | string | 否 | single (默认), thisAndFollowing,或 allInSeries |
respond_to_calendar_event
回复会议:接受、暂时接受或拒绝。尽可能使用OWA的内部服务.svc API,即使组织者禁用了响应请求,也能正常工作(ResponseRequested: false).如果内部API无法解决事件,则返回到标准REST API。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
eventId | string | yes | 事件ID |
response | string | 是 | accept, tentative,或 decline |
comment | string | 否 | 给组织者的消息 |
sendResponse | boolean | 否 | 通知组织者(默认为true) |
proposedStartDateTime | string | 否 | 建议替代开始(暂定/仅拒绝) |
proposedEndDateTime | string | no | 提出替代结尾 |
follow_calendar_event
无需RSVP即可在日历上跟踪事件。显示为免费,组织者未收到通知。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
eventId | string | yes | 事件ID |
comment | string | no | 发送给组织者的以下通知中包含可选消息 |
timezone | string | no | 返回事件的时区 |
get_series_master
检查重复系列的主事件。返回重复模式、已取消的事件和完整的事件详细信息。接受系列中的任何事件ID。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
eventId | string | yes | 序列中的任何事件ID(自动解析) |
timezone | string | no | IANA时区(默认UTC) |
list_series_instances
列出日期范围内重复序列的所有事件。接受系列中的任何事件ID。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
eventId | string | yes | 序列中的任何事件ID(自动解析) |
startDateTime | string | 是 | ISO 8601开始 |
endDateTime | string | 是 | ISO 8601结束 |
timezone | string | no | IANA时区(默认UTC) |
list_mail_folders
列出邮箱中的所有邮件文件夹或特定文件夹的子文件夹。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
parentFolderId | string | no | 列出此文件夹的子文件夹。如果省略,则列出顶级文件夹 |
get_emails
使用可选筛选从特定邮箱文件夹获取电子邮件。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
folderId | string | no | 文件夹ID或已知名称(收件箱、草稿、SentItems、DeletedItems)。默认值:收件箱 |
filter | string | 否 | all, unread, flagged, today, this_week |
limit | number | no | 最大结果数(默认20,最大500) |
pageToken | string | no | 来自先前响应的分页标记 |
search_emails
使用全文查询或结构化过滤器(互斥)搜索电子邮件。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
query | string | no | 全文搜索查询。无法与结构化筛选器组合 |
from | string | 否 | 按发件人电子邮件筛选 |
subject | string | no | 按主题筛选(包含) |
receivedAfter | string | no | ISO 8601日期时间 |
receivedBefore | string | no | ISO 8601日期时间 |
folderId | string | 否 | 搜索文件夹的范围 |
limit | number | no | 最大结果数(默认20,最大500) |
get_email
阅读一封包含全文内容和附件元数据的电子邮件。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
messageId | string | yes | 消息ID |
format | string | 否 | text (默认)或 html |
get_attachment
将电子邮件附件下载到磁盘。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
messageId | string | yes | 消息ID |
attachmentId | string | yes | 来自get_email响应的附件ID |
send_email
一步完成撰写和发送新电子邮件。要获得更多控制,请使用 create_draft + update_draft + send_draft.
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
to | 数组 | 是 | [{ email, name? }] |
subject | string | yes | 主题行 |
body | string | yes | 正文内容 |
bodyType | string | 否 | text (默认)或 html |
cc | array | 无 | 抄送收件人 [{ email, name? }] |
bcc | 数组 | 无 | 密件抄送收件人 |
importance | string | no | 低、正常(默认)、高 |
saveToSentItems | boolean | no | 保存到已发送邮件(默认为true) |
create_draft
创建保存到“草稿”文件夹的新电子邮件草稿。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
to | 数组 | 是 | [{ email, name? }] |
subject | string | yes | 主题行 |
body | string | yes | 正文内容 |
bodyType | string | 否 | text (默认)或 html |
cc | array | 无 | 抄送收件人 |
bcc | 数组 | 无 | 密件抄送收件人 |
importance | string | no | 低、正常(默认)、高 |
create_reply_draft
为发件人创建回复草稿。返回带有预填收件人、引用正文、“RE:”主题的草稿。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
messageId | string | yes | 消息ID |
create_reply_all_draft
全部创建回复草稿。返回包含所有原始收件人、引用正文、“RE:”主题的草稿。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
messageId | string | yes | 消息ID |
create_forward_draft
创建转发草稿。返回带有引用正文的草稿,主题为“FW:”,收件人为非收件人。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
messageId | string | yes | 消息ID |
update_draft
发送前修改草稿。可以更改主题、正文、收件人、重要性。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
messageId | string | yes | 草稿消息ID |
subject | string | 否 | 新主题 |
body | string | no | 新正文内容 |
bodyType | string | 否 | text 或 html |
toRecipients | array | 否 | 替换所有收件人 |
ccRecipients | array | 否 | 替换所有抄送收件人 |
bccRecipients | array | 否 | 替换所有BCC收件人 |
importance | string | no | 低、正常、高 |
send_draft
发送一条草稿消息。从草稿移动到已发送邮件。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
messageId | string | yes | 草稿消息ID |
move_email
将邮件移动到其他文件夹。返回移动的邮件(具有更新的ID)。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
messageId | string | yes | 消息ID |
destinationId | string | yes | 文件夹ID或已知名称(收件箱、草稿、SentItems、已删除项、存档) |
delete_email
删除邮件(移动到“已删除邮件”)。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
messageId | string | yes | 消息ID |
update_email
更新电子邮件属性:标记为已读/未读,标记/取消标记。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
messageId | string | yes | 消息ID |
isRead | boolean | no | 设置为已读(true)或未读(false) |
flagStatus | string | 否 | NotFlagged, Flagged,或 Complete |
示例提示:
- *“我下周有什么会议?”*
- *“明天下午2点和简开一个30分钟的会议”*
- *“拒绝ECCN同步,并注明我正在度假”*
- *“关注分析技术电话,这样我就可以在日历上看到它”*
- *“取消从下周开始的每周同步的所有后续事件”*
- *“周一脱口秀的复发模式是什么?”*
- *“在接下来的3个月里,每周二上午10点创建每周团队同步”*
- *“显示今天未读的电子邮件”*
- *“回复Sarah的电子邮件并将Bob添加到CC”*
- *“将第三季度报告转发给财务团队”*
- *“将时事通讯中的所有电子邮件标记为已读”*
重复对象
被...使用 create_calendar_event 和 update_calendar_event 定义重复事件。
{
"recurrence": {
"pattern": {
"type": "weekly",
"interval": 1,
"daysOfWeek": ["Monday", "Wednesday", "Friday"]
},
"range": {
"type": "endDate",
"startDate": "2026-04-07",
"endDate": "2026-07-07"
}
}
}图案类型: daily, weekly, absoluteMonthly, relativeMonthly, absoluteYearly, relativeYearly
| 模式字段 | 类型 | 描述 |
|---|---|---|
type | string | 必填。图案类型 |
interval | number | 必填。事件间隔(1=每一次,2=每隔一次) |
daysOfWeek | string\[\] | 每周/相对模式的天数 |
dayOfMonth | number | 绝对月/绝对年的月份 |
month | number | 年度模式的月份(1-12) |
index | string | 相对模式的周索引:第一、第二、第三、第四、最后 |
firstDayOfWeek | string | 一周的第一天(默认星期日) |
范围类型: endDate, numbered, noEnd
| 范围字段 | 类型 | 描述 |
|---|---|---|
type | string | 必填。系列如何结束 |
startDate | string | 必填。系列开始时间(YYYY-MM-DD) |
endDate | string | 结束日期(必填) endDate 类型) |
numberOfOccurrences | number | 计数(必填 numbered 类型) |
recurrenceTimeZone | string | 重复日期的时区 |
故障排除
代币获取超时 打开Edge,导航到outlook.office.com,确认您可以看到日历。会话可能已过期,请重新登录。
ErrorAccessDenied API日历 被拦截的令牌不包含日历范围。这是罕见的;尝试退出所有Edge窗口并重新启动。
无头浏览器打开一个可见窗口 这不应该正常发生。如果是这样,请检查没有其他Playwright进程持有Edge配置文件目录锁。
许可证
Apache 2.0——请参阅 许可证.
