内容
# outlook-triage-mcp
MCP 服务器,用于 Microsoft 365 邮件 — 通过 Microsoft Graph 从 Claude 搜索、分类和整理您的收件箱:每日简报摘要,可重复执行的收件箱规则,附件提取。设备代码身份验证,默认只读。
---
##
您的收件箱,由 Claude 分类 — 无需分享密码。这台 MCP 服务器通过 Microsoft Graph 将 Claude(代码或桌面版)连接到 Microsoft 365 邮箱,使用设备代码登录和本地令牌缓存。它使用确定性关键词启发式(运行时无 LLM 调用,运行时除您要求 Claude 读取的内容外,机器上不会留下任何消息内容),构建晨间简报,并且仅在您明确选择加入时,才能为收件箱规则提供一致的服务。
### 功能
- **每日简报** — 将过去 N 小时的收件箱邮件分类为 `紧急` / `需要处理` / `资讯` / `新闻通讯`,并渲染 Markdown 摘要。启发式是确定性的,可配置的(环境变量或 JSON 文件);您已经阅读过的消息永远不会被标记为待处理。
- **搜索和阅读** — Graph `$search`/`$filter` 消息搜索任意文件夹;全文正文;从 PDF / DOCX / XLSX 附件中本地提取文本(pypdf, python-docx, openpyxl — 解析 100% 本地)。
- **可重复收件箱规则** — `ensure_inbox_rule` 收敛邮箱状态:已经正确的规则触发 **零** 写调用,不一致的规则被修补,缺失的规则被创建(包括文件夹)。运行一百次,得到一个规则。
- **设备代码身份验证** — MSAL 公共客户端流程:`auth_status` 工具为您提供一个 URL 和一个代码;从任意浏览器登录。令牌缓存在 `~/.local/share/outlook-triage-mcp/`(从不存储在仓库中,`0600` 权限)并静默刷新。
- **默认只读** — 服务器请求仅 `Mail.Read` / `MailboxSettings.Read` 作用域,除非您设置 `OUTLOOK_MCP_ENABLE_WRITE=1`。
- **重试/回退** — Graph 调用尊重 `Retry-After` 在 429 时,并在 5xx 时指数回退。
### ⚠️ 写访问
**`ensure_inbox_rule` 是唯一写入您邮箱的工具。** 所有其他工具都严格只读(并且在 MCP 工具元数据中注释为只读)。规则配置默认禁用:工具在您使用 `OUTLOOK_MCP_ENABLE_WRITE=1` 启动服务器并使用写入作用域重新身份验证之前拒绝运行。服务器从不发送、删除、移动或标记消息。
### 工具
| 工具 | 访问 | 描述 |
| --- | --- | --- |
| `auth_status()` | 只读 |令牌状态;启动设备代码身份验证并在需要登录时返回 URL + 代码 |
| `search_messages(query, folder="inbox", top=20, since=None)` | 只读 |搜索(KQL)或列出消息;`since` 接受 ISO 8601 或相对时间(`24h`,`7d`) |
| `get_message(message_id, include_attachments=False)` | 只读 |全文 + 元数据;可选地从 PDF/DOCX/XLSX 附件中本地提取文本 |
| `daily_briefing(hours=24)` | 只读 | Markdown 摘要,分类为紧急 / 需要处理 / 资讯 / 新闻通讯 |
| `list_inbox_rules()` | 只读 |收件箱规则清单,包含条件和操作 |
| `ensure_inbox_rule(name, from_contains, move_to_folder)` | **写入** |一致地收敛一条规则(发件人包含 X → 移动到文件夹 Y);如果缺少文件夹,则创建文件夹 |
连接后示例提示:
> "给我过去 48 小时的每日简报。"
> "在收件箱中搜索有关 Q3 发票的消息并读取最新的一个,包括附件。"
> "确保有一条规则可以将所有来自 recruiting@ 的邮件移动到 Recruiters 文件夹。" *(需要写入模式)*
### 工作原理
```mermaid
flowchart LR
subgraph Claude["Claude (代码 / 桌面版)"]
C[MCP 客户端]
end
subgraph Server["outlook-triage-mcp (本地)"]
T[FastMCP 工具]
H[启发式分类器<br/>确定性,无 LLM]
A[MSAL 设备代码身份验证<br/>令牌缓存 ~/.local/share]
G[Graph 客户端<br/>重试 + 回退]
X[附件提取<br/>PDF / DOCX / XLSX,本地]
end
M[(Microsoft Graph<br/>Microsoft 365 邮箱)]
C <-->|stdio JSON-RPC| T
T --> H
T --> X
T --> G
G --> A
G <-->|HTTPS,委托范围| M
```
### 安装
```bash
git clone https://github.com/giuseppeferretti/outlook-triage-mcp
cd outlook-triage-mcp
python -m venv .venv && source .venv/bin/activate
pip install -e ".[attachments]" # 附件额外功能启用 PDF/DOCX/XLSX 解析
```
### 配置 Claude
**Claude 代码:**
```bash
claude mcp add outlook-triage -- /path/to/.venv/bin/outlook-triage-mcp
```
**Claude 桌面版** (`claude_desktop_config.json`):
```json
{
"mcpServers": {
"outlook-triage": {
"command": "/path/to/.venv/bin/outlook-triage-mcp",
"env": {
"OUTLOOK_MCP_USER_EMAIL": "you@yourcompany.com"
}
}
}
}
```
首次使用:要求 Claude 调用 `auth_status`,打开它返回的验证 URL,输入代码,完成。令牌缓存在本地;您几乎不需要再次登录。
### 配置(环境变量)
| 变量 | 默认值 | 用途 |
| --- | --- | --- |
| `OUTLOOK_MCP_CLIENT_ID` | Microsoft Graph CLI 公共客户端(`14d82eec-…`) | Azure AD 应用注册。默认值为 Microsoft 自己的 Graph CLI 公共客户端,已预授权用于大多数租户的委托邮件范围(较旧的 Azure CLI 客户端因 `Mail.*` 而被阻止 - AADSTS65002)。如果您的租户阻止它,请注册您自己的公共客户端应用并启用设备代码流和委托 `Mail.Read` + `MailboxSettings.Read`,然后设置此变量。 |
| `OUTLOOK_MCP_TENANT_ID` | `common` | 限制登录到特定租户 |
| `OUTLOOK_MCP_USER_EMAIL` | — |您的地址;用于选择缓存的帐户和分类自发邮件 |
| `OUTLOOK_MCP_ENABLE_WRITE` | `0` |设置为 `1` 以启用 `ensure_inbox_rule`(下次登录时请求写入范围) |
| `OUTLOOK_MCP_CACHE_DIR` | `~/.local/share/outlook-triage-mcp` |令牌缓存位置 |
| `OUTLOOK_MCP_CLASSIFY_FILE` | — |JSON 文件覆盖启发式关键词列表 |
| `OUTLOOK_MCP_URGENT_KEYWORDS` / `OUTLOOK_MCP_ACTION_KEYWORDS` / `OUTLOOK_MCP_NEWSLETTER_SENDERS` / `OUTLOOK_MCP_NEWSLETTER_KEYWORDS` / `OUTLOOK_MCP_VIP_SENDERS` | 内置列表 |单个启发式列表的逗号分隔覆盖 |
| `OUTLOOK_MCP_MAX_ATTACHMENT_BYTES` | `5242880` |附件大于此值时,将列出附件而非解析 |
分类文件示例(`classify.json`):
```json
{
"urgent_keywords": ["urgent", "asap", "outage"],
"action_keywords": ["please review", "sign off"],
"vip_senders": ["ceo@yourcompany.com"],
"newsletter_sender_patterns": ["noreply@", "digest@"]
}
```
### 开发
```bash
pip install -e ".[dev]"
pytest # 全部离线:fixture JSON + 假 Graph + stdio 烟雾测试
OUTLOOK_MCP_LIVE_TESTS=1 pytest tests/test_graph_live.py # 可选,真实 Graph
```
测试套件需要 **无 Microsoft 帐户**:分类和规则一致性测试在伪造的 Graph 响应下运行,MCP 烟雾测试使用官方 SDK 客户端启动真正的 stdio 服务器,并验证工具列表和所需的身份验证行为。
### 来源
该服务器是从 **生产 Microsoft 365 自动化系统** 中提取的 — 一个每日简报机器人和一致的收件箱规则配置程序,每天早上为实际控制工作流运行。战斗测试的部分内容被保留下来(带有令牌缓存的设备代码身份验证,Graph 重试/回退,写入免费分类,一致的规则配置),客户端特定的启发式算法被泛化为可配置的关键词列表。 [portfolio.iterlabs.com.br](https://portfolio.iterlabs.com.br) 上的案例研究。
---
*Built with AI-assisted development; designed, verified, and operated by Giuseppe Ferretti.*