内容
# outlook-mcp




`outlook-mcp` 是一个适用于本地 Microsoft Exchange 的 MCP 服务器,通过 EWS(`exchangelib`)。它为兼容 MCP 的客户端提供了一个单一的、可测试的 Python 服务,允许访问电子邮件、日历、联系人、文件夹、附件和可用性数据。
## 简要描述
适用于本地 Microsoft Exchange(EWS)的安全 MCP 服务器,包含用于电子邮件、日历、联系人、文件夹、附件和空闲/忙碌可用性的工具。
## 建议的存储库主题/标签
`mcp`, `model-context-protocol`, `exchange`, `microsoft-exchange`, `ews`, `outlook`, `email`, `calendar`, `contacts`, `python`, `automation`, `exchangelib`
## 亮点
- 电子邮件操作:列出、搜索、读取、发送、回复、转发、移动、复制、删除、标记
- 日历操作:列出、创建、更新、删除、响应邀请、查找空闲时间段
- 联系人操作:搜索、读取、创建、更新、删除
- 文件夹操作和附件下载
- 通过 `NTLM` 和 `Basic` 进行 Exchange 身份验证
- 通过 `stdio` 和 `SSE` 进行 MCP 传输
- 集中式错误映射和单一 `ExchangeClient` 抽象
- 默认情况下提供隐私安全的烟雾检查输出
- 包含 Docker 支持和 GitLab CI/CD 流水线
## 工具目录
### 系统
- `ping_exchange`
- `get_mailbox_info`
### 电子邮件
- `list_emails`
- `get_email`
- `search_emails`
- `send_email`
- `reply_email`
- `forward_email`
- `move_email`
- `copy_email`
- `delete_email`
- `mark_email`
- `list_folders`
- `create_folder`
- `create_draft`
- `send_draft`
- `get_attachment`
### 日历
- `list_events`
- `get_event`
- `create_event`
- `update_event`
- `delete_event`
- `respond_to_invite`
- `find_free_slots`
- `get_my_availability`
- `list_calendars`
### 联系人
- `search_contacts`
- `get_contact`
- `create_contact`
- `update_contact`
- `delete_contact`
## 典型用例
- 将 Claude Desktop 或其他 MCP 客户端连接到本地 Exchange
- 搜索收件箱消息并获取完整的电子邮件内容
- 从 AI 工作流发送或草拟电子邮件
- 检查日历并创建会议
- 检查可用于调度的空闲/忙碌时间窗口
- 搜索个人联系人或全局地址列表
- 通过受控的 MCP 边界公开 Exchange 操作,而不是直接的邮箱脚本
## 安全说明
当前代码的作用:
- 仅连接到在 `EXCHANGE_SERVER` 中配置的 Exchange/EWS 端点
- **不**包含遥测、分析或第三方数据导出逻辑
- 将机密存储在环境变量/`.env` 中
- 通过 `.gitignore` 忽略本地机密文件(`.env`、`.env.*`,同时保留 `.env.example`)
- 仅记录工具名称、状态、持续时间和错误代码;**不**记录消息正文、附件内容或密码
- 通过 `.dockerignore` 从 Docker 构建上下文中排除 `.env`、测试、缓存和版本控制系统元数据
您仍需谨慎:
- `EXCHANGE_VERIFY_SSL=false` 禁用 TLS 证书验证,仅应在受信任的内部/自签名环境中使用
- `get_attachment` 将文件写入磁盘,因此请选择一个安全的目标目录
- `outlook-mcp-smoke` 默认情况下是隐私安全的,仅打印被屏蔽的邮箱信息和计数;如果您明确希望在 stdout 中包含真实的收件箱/事件数据,请设置 `OUTLOOK_MCP_SMOKE_INCLUDE_DATA=true`
- 如果您启用了带有 `LOG_FILE` 的文件日志记录,请保护该文件与操作系统权限
- 如果您从 CI 发布 Docker 镜像,请保护 GitLab/GitHub 项目访问和注册表权限
## 快速开始
```bash
uv venv
source .venv/bin/activate
uv pip install -e .[dev]
cp .env.example .env
outlook-mcp
```
默认情况下,服务器在 `stdio` 模式下运行。设置 `MCP_TRANSPORT=sse` 以启动 HTTP 服务器。
## 配置
示例 `.env`:
```dotenv
EXCHANGE_SERVER=https://mail.company.com/EWS/Exchange.asmx
EXCHANGE_USERNAME=DOMAIN\\username
EXCHANGE_PASSWORD=secret
EXCHANGE_EMAIL_ADDRESS=user@company.com
EXCHANGE_VERIFY_SSL=true
EXCHANGE_AUTH_TYPE=NTLM
EXCHANGE_VERSION=EXCHANGE_2016
EXCHANGE_TIMEOUT=30
EXCHANGE_MAX_RETRIES=3
EXCHANGE_TIMEZONE=Europe/Moscow
EXCHANGE_IMPERSONATE_AS=
ATTACHMENT_MAX_SIZE_MB=10
MCP_TRANSPORT=stdio
MCP_SSE_HOST=127.0.0.1
MCP_SSE_PORT=8080
LOG_LEVEL=INFO
LOG_FILE=
```
注意:
- 当 `EXCHANGE_USERNAME` 不是 SMTP 地址时,请设置 `EXCHANGE_EMAIL_ADDRESS`
- `OAuth2` 在配置中保留,但当前版本仅支持使用 `NTLM` 或 `Basic` 进行实时身份验证
- `EXCHANGE_IMPERSONATE_AS` 在配置了 Exchange 权限的情况下启用邮箱模拟
- `ATTACHMENT_MAX_SIZE_MB` 在发送/回复/转发/草拟带有本地附件时强制执行
## Claude Desktop 示例
```json
{
"mcpServers": {
"outlook": {
"command": "outlook-mcp",
"env": {
"EXCHANGE_SERVER": "https://mail.company.com/EWS/Exchange.asmx",
"EXCHANGE_USERNAME": "DOMAIN\\username",
"EXCHANGE_PASSWORD": "secret",
"EXCHANGE_EMAIL_ADDRESS": "user@company.com",
"EXCHANGE_AUTH_TYPE": "NTLM"
}
}
}
}
```
## 烟雾检查
填充 `.env` 后,运行:
```bash
outlook-mcp-smoke
```
默认输出经过净化处理,以确保更安全的验证。如果您故意希望在输出中包含样本邮箱/事件数据:
```bash
OUTLOOK_MCP_SMOKE_INCLUDE_DATA=true outlook-mcp-smoke
```
## Docker
```bash
docker build -t outlook-mcp .
docker run --rm --env-file .env outlook-mcp
```
## GitLab CI/CD
存储库包含 `.gitlab-ci.yml`,具有以下阶段:
- `lint` — 运行 `ruff`
- `test` — 运行 `pytest`
- `build` — 将 Python 包工件构建到 `dist/`
- `release` — 在默认分支和标签上构建并将 Docker 镜像推送到 GitLab 容器注册表
默认镜像标记行为:
- 默认分支:推送 `:$CI_COMMIT_SHORT_SHA` 和 `:latest`
- Git 标签:推送 `:$CI_COMMIT_TAG`
使用 GitLab 内置注册表变量:
- `CI_REGISTRY`
- `CI_REGISTRY_USER`
- `CI_REGISTRY_PASSWORD`
- `CI_REGISTRY_IMAGE`
## 开发
```bash
uv run --python 3.12 --with '.[dev]' ruff check .
uv run --python 3.12 --with '.[dev]' pytest -q
```
## 项目说明
- 实现围绕单一的 `ExchangeClient` 抽象,以便身份验证、传输、重试和错误映射保持集中式。
- 错误以适合 MCP `isError=true` 处理的结构化 JSON 形式返回。
- `RTK.md` 不存在于此存储库中,因此实现遵循 `PLAN.md`。