使用说明
owa mcp
A. 模型上下文协议(MCP) 允许Claude Code完全访问您的Microsoft Outlook日历和电子邮件的服务器-- 无需Azure应用程序注册.
运作原理
服务器通过以下方式驱动专用的、持久的谷歌Chrome浏览器 chrome开发工具mcp,使用自己的Chrome配置文件(与您的日常驱动程序Chrome分开保存),以便登录会话在重新启动后仍然有效。它将浏览器导航到OutlookWeb(Outlook.office.com),并监视它发出的网络请求。当Outlook Web加载时,它为自己的内部API调用发布Bearer令牌;此服务器拦截这些令牌并针对 outlook.office.com/api/v2.0 REST端点。
结果:满 Calendars.ReadWrite 和 Mail.ReadWrite 范围,无需OAuth应用程序注册,无需客户端ID,也无需IT参与——只要您可以在自动化浏览器中登录Microsoft 365即可。
代币在约80分钟后过期。 服务器不会在每次刷新时重新启动浏览器,而是在收购过程中保持单个chrome devtools mcp连接(及其浏览器)的活动状态,并简单地重新导航到Outlook Web以触发新的令牌请求。Chrome窗口从浏览器首次启动的那一刻起就可见(从不无头),因此您可以在需要时登录。如果在60秒内没有找到活动会话,则请求失败,并显示一条消息,要求您登录并重试——因为连接保持活动状态,您可以根据需要(包括MFA)等待多长时间,并在完成后重试,而不会丢失浏览器会话。
为什么采用这种方法
许多企业Microsoft 365租户执行条件访问策略,阻止托管设备上的第三方OAuth流(例如Azure CLI、自定义应用程序注册)。浏览器会话拦截方法之所以有效,是因为它依赖于已经满足这些策略要求的身份验证流——与Outlook Web本身使用的身份验证流程相同。这已被证实在至少一个条件访问强制的公司环境中与Chrome SSO一起工作;它是否适用于你的组织取决于你组织的具体政策。
先决条件
- macOS(在macOS 15上测试)
- 谷歌浏览器 已安装
- chrome开发工具mcp 可通过
npx--验证npx chrome-devtools-mcp@latest --version;服务器在首次使用时自动生成它,无需手动设置 - 登录到Microsoft 365(第一个令牌请求会打开一个可见的Chrome窗口——如果系统提示,请在那里登录)
- 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 | 重复日期的时区 |
故障排除
令牌获取超时/未找到活动会话 自动化Chrome窗口已经打开(浏览器启动后立即可见,而不仅仅是超时),并已导航到Outlook Web。切换到它并按照自己的节奏登录(包括MFA),然后简单地重试请求——浏览器连接保持活跃,因此重复使用相同的会话,您不需要在后续调用中再次登录。
ErrorAccessDenied API日历
被拦截的令牌不包含日历范围。这是罕见的;尝试使用自动化配置文件退出任何Chrome窗口(~/Library/Application Support/owa-mcp/chrome-profile)然后重试——服务器将自动重新启动它。
许可证
Apache 2.0——请参阅 许可证.