惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
News | PayPal Newsroom
云风的 BLOG
云风的 BLOG
GbyAI
GbyAI
Engineering at Meta
Engineering at Meta
B
Blog RSS Feed
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
The Register - Security
The Register - Security
L
LangChain Blog
A
About on SuperTechFans
S
Schneier on Security
博客园 - 三生石上(FineUI控件)
Stack Overflow Blog
Stack Overflow Blog
The Hacker News
The Hacker News
AWS News Blog
AWS News Blog
博客园 - 司徒正美
Scott Helme
Scott Helme
K
Kaspersky official blog
Cyberwarzone
Cyberwarzone
T
Tenable Blog
腾讯CDC
Recorded Future
Recorded Future
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
G
GRAHAM CLULEY
Security Latest
Security Latest
S
Securelist
D
Darknet – Hacking Tools, Hacker News & Cyber Security
aimingoo的专栏
aimingoo的专栏
Google DeepMind News
Google DeepMind News
V
Vulnerabilities – Threatpost
雷峰网
雷峰网
T
The Exploit Database - CXSecurity.com
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V
V2EX
T
The Blog of Author Tim Ferriss
D
Docker
S
Security Affairs
F
Full Disclosure
Know Your Adversary
Know Your Adversary
N
News and Events Feed by Topic
N
News and Events Feed by Topic
T
Tor Project blog
Hugging Face - Blog
Hugging Face - Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Microsoft Security Blog
Microsoft Security Blog
Simon Willison's Weblog
Simon Willison's Weblog
Recent Announcements
Recent Announcements
博客园_首页
博客园 - 聂微东
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
Security @ Cisco Blogs

博客园 - 无常

ABP点滴:API无权访问资源时,返回 PolicyName 信息 使用MSBUILD 构建时出错 error MSB3086: Task could not find "sgen.exe" using the SdkToolsPath PPTPD默认MTU太大引起一些网站上不了的问题 CentOS 6.0 安装配置rails 2.3.11 + redmine 1.2.1 笔记 MVC3中实现验证提示信息多语言支持 MVC3中使用验证适配器修改默认的验证提示信息 nginx 截断日志一个批处理 在没有安装有mvc3的主机上部署asp.net mvc3网站,需要包含的DLL文件 ASP.NET MVC 2 RTM client side validation一个隐秘的坑 Python:使用ctypes库调用外部DLL NHibernate+Oracle 遇到ORA-01461和ORA-01084及解决方法 ASP.NET MVC中实现多个按钮提交的几种方法 - 无常 - 博客园 为cnblogs定做一个代码插入代码的windows live writer插件 MVC 2.0: ConvertEmptyStringToNull 带来烦恼 Code: jsTree ajax 选择行政区域 送出15个Google Wave邀请,需要的赶快 GeekOS:Project1. Loading Executable Files GeekOS:二、Project0 GeekOS: 一、构建基于Ubuntu9.04的实验环境 动刀EFOracleProvider,使其支持char、timestamp(x)等类型
用 Zig 写了个 MCP Server,让 AI Agent 直接操控你的 Outlook
无常 · 2026-06-19 · via 博客园 - 无常

为什么会有这个东西

我习惯用 Outlook 日历和任务记录事项,可以把日程同步到手机,手机上也装了微软 To Do。

前两天突然想能不能让 OpenClaw 来帮我操作日历记录事项,然后看了一下资料,就让 OpenCode 写了个 Python 版本,半小时不到就弄了个可用版本,确实也可以跑起来了,

为什么是 Zig,不是 Python

Python 版本因为每一次都是要用 uv 启动一个 Python 脚本,冷启动的速度稍微慢一点。
换了 Reasonix + DeepSeek V4 Pro 重新实现个版本,用最原始的方式,没用第三方包,磕磕绊绊,修修补补,终于能跑起来了,整个过程要比用 Python 复杂了挺多,看来各个大模型还是 Python 的训练素材比较多些。
另外一方面,我个人比较喜欢 Zig 语言,成品出来发现响应速度确实有所提高,然后就是那个发布的体积真是小了很多,strip 后只有 750KB 左右。
测试通过之后,就把它发布到GitHub了

以下内容是AI辅助书写:

架构设计

我是先跟DeepSeek以问答的方式商量确定了这个架构,然后再让他写。
整个项目的结构很清晰,分四层:

┌─────────────────────────────┐
│  handlers/ (MCP 接口层)      │  从 JSON-RPC 参数中提取参数,调用 Graph 层
├─────────────────────────────┤
│  graph/ (Graph API 层)       │  构造 REST 请求路径和 JSON body
├─────────────────────────────┤
│  client.zig (HTTP 传输层)    │  统一的 GET/POST/PATCH/DELETE,可 mock
├─────────────────────────────┤
│  tls.zig (HTTPS 底层)        │  OpenSSL + BSD socket,TCP+TLS 全手写
│  auth/ (OAuth 认证)          │  Device Code Flow + Token 持久化
│  mcp.zig (MCP 协议)          │  JSON-RPC 2.0 over stdio
└─────────────────────────────┘

MCP 协议层(mcp.zig)

我查了一下,Zig 也有几个做得比较完善的 MCP 第三方包,但想着反正是让 AI 写,就没有用,选择了让 DeepSeek 自己搓。

MCP 协议本质上就是基于 stdin/stdout 的 JSON-RPC 2.0。每个消息是一行 JSON,末尾换行分隔。

核心就是事件循环:从 stdin 读一行 → 解析 JSON → 路由到对应方法 → 返回 JSON 到 stdout。

消息只分四种:

  • initialize — 握手,返回服务器信息和支持的能力
  • ping — 心跳
  • tools/list — 返回工具清单
  • tools/call — 调用指定的 tool,传参数

我用 Zig 的 std.json 做解析,手动构建 ObjectMap 来拼响应 JSON,没有引入第三方 JSON 库。

认证层(auth/oauth.zig)

第一次接触微软的这个认证,用起来还是挺方便的。

这个应该是最有意思的部分。Python 版靠 azure-identity 一行代码搞定认证,但我得用 Zig 重新实现整个 OAuth Device Code Flow。

流程是这样的:

1. POST /common/oauth2/v2.0/devicecode
   → 返回 user_code, device_code, verification_uri
   
2. 打印到终端让用户去 https://microsoft.com/devicelogin 输验证码

3. 轮询 POSt /common/oauth2/v2.0/token
   → 每隔 5s 查一次,用户授权后拿到 access_token + refresh_token

其中最坑的是 Token 持久化。我不想每次启动都让用户重新登录,所以把 refresh_token 缓存到 ~/.config/outlook-mcp/token.json,启动时先尝试用 refresh_token 静默续期,续期失败才重新走 Device Code。

HTTP 传输层(tls.zig)

这层是直接拿 OpenSSL + BSD socket 手写的 HTTPS 请求。没有用 libcurl 之类的高层库。

为什么自己写?因为 Zig 和 cURL 的集成有点别扭,而且 MCP server 只需要很少的功能:GET、POST、form POST。我自己造个轮子更可控。

还加了 DNS 缓存和重试逻辑——弱网环境下 Graph API 偶尔会抽风,重试 3 次再加 1s 退避能让体验好很多。

分类 Tool 作用
📅 日历 list_events 查未来 N 天日程
query_events 查任意日期范围
search_events 按关键词搜事件
create_event 创建日历事件
📧 邮件 list_emails 列出收件箱
send_email 发邮件
search_emails 搜邮件
get_unread_count 未读数
✅ 待办 list_task_lists 列出任务清单
list_tasks 查看清单中的任务
create_task 创建任务
complete_task 标记完成
delete_task 删除任务

这些 tool 都是通过 Microsoft Graph API 的 REST 接口实现的,每个 tool 对应一个或几个 Graph API 调用。

使用场景

场景 1:Agent 帮你管邮件

在 Claude Code 里注册这个 MCP Server 后,你可以直接说:

"看一下收件箱有没有未读邮件"
"搜索关于 '部署' 的邮件"
"给 team@xxx.com 发个邮件说今晚发版"

Agent 会调用 list_emailssearch_emailssend_email 等工具完成操作。

场景 2:日程管理

"今天有什么会议?"
"下周一有没有空闲时间?"
"下周三下午 3 点加一个评审会议"

一句自然语言,Agent 帮你查日历、建事件。

场景 3:待办任务同步

"我的任务清单里还有哪些没完成?"
"加一个任务说「写完这篇博客」,截止这周五"

场景 4:CI/CD 通知推送

在 CI pipeline 的最后一步,可以直接调这个 MCP server 发邮件通知,不需要额外的 SMTP 配置。

怎么用

# 1. 构建(需要 Zig 0.16+)
git clone https://github.com/wuchang/mcp-server-outlook
cd mcp-server-outlook
zig build -Doptimize=ReleaseSafe

# 2. 配置 Client ID
# 写入 ~/.config/outlook-mcp/config
echo 'CLIENT_ID = "你的-app-client-id"' > ~/.config/outlook-mcp/config

# 3. 运行
./zig-out/bin/mcp-server-outlook

# 首次会触发浏览器登录,之后自动复用 token

Client ID 从哪里来?去 Azure Portal → App registrations 注册一个应用。注意账户类型必须是 "Accounts in any organizational directory AND personal Microsoft accounts",然后平台选 "Mobile and desktop applications"。不需要密钥,个人账号走 Device Code Flow,免费。

然后注册到 OpenClaw:

# 方式一:环境变量(无需配置文件)
openclaw mcp set outlook \
  '{"command":"/path/to/mcp-server-outlook","env":{"AZURE_CLIENT_ID":"your-client-id"}}'

# 方式二:已配好 ~/.config/outlook-mcp/config
openclaw mcp set outlook \
  '{"command":"/path/to/mcp-server-outlook"}'

值得讲的一些细节

Device Code 轮询的超时处理

OAuth Device Code 的有效期默认 15 分钟。如果用户开了链接但迟迟不输入验证码,轮询会一直跑 15 分钟才报 expired_token。我在每个轮询周期检查 elapsed > expires_in 提前退出,不用等微软 API 报错。

Token 缓存的安全考虑

refresh_token 保存在 ~/.config/outlook-mcp/token.json 明文。严格来说应该用系统钥匙串,但为了跨平台简单,先用文件。提供了 --logout 参数一键删除缓存文件。

代码在: https://github.com/wuchang/mcp-server-outlook

欢迎提 Issue 和 PR,一起让 AI Agent 能更好地帮我们处理日常办公事务。