ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

无头环境下让AI代理代表你工作:ms-365-mcp-server OBO委托认证完整实战指南

无头环境下让AI代理代表你工作:ms-365-mcp-server OBO委托认证完整实战指南

【免费下载链接】ms-365-mcp-server

A Model Context Protocol (MCP) server for interacting with Microsoft 365 and Microsoft Office services through the Graph API

项目地址:https://gitcode.com/gh_mirrors/ms/ms-365-mcp-server
点击查看免费下载

ms-365-mcp-server是一个让 AI 代理通过 Microsoft Graph API 操作 Microsoft 365 的 MCP(Model Context Protocol)服务器,可驱动邮件、日历、OneDrive、Teams、SharePoint 等 300+ 工具。本文面向新手与运维,讲解如何在无头环境(服务器、容器、CI)中用 OBO(On-Behalf-Of)委托认证,让 AI 代理代表你安全地读写 Office 数据,且服务器不保存任何用户令牌。

太长不看

目标方案关键命令 / 配置
无头环境代表用户办公--obo+--httpnpx @softeria/ms-365-mcp-server --http 3000 --org-mode --obo
必须项机密客户端密钥环境变量MS365_MCP_CLIENT_SECRET
多用户共享无状态,每请求独立身份用户 Bearer Token 随请求携带
权限收紧管理员同意 + 工具过滤--read-only、--allowed-scopes、--preset

💡 一句话理解 OBO:用户在浏览器登录一次,AI 代理之后每次调用都“代表你”用你的身份去访问 Microsoft 365,服务器本身不留存令牌。

无头环境为什么需要 OBO 委托认证

标准登录(设备码 / 浏览器授权)都假设“有人盯着屏幕”。但在一台服务器或容器里:

  • 没有浏览器,无法弹出登录窗口;
  • 无法交互式输入设备码;
  • 你希望服务 7×24 运行,而不是一小时后就因令牌过期而失效。

OBO(On-Behalf-Of,代表用户)正是为这种场景设计的委托模式。它的价值在于无状态:服务器不为每个用户保存令牌,而是“即来即换、用完即弃”——这正是 docs/deployment.md 中“Production Deployment”强调的核心架构:stateless, no token store。

对比一下,无头环境下有三种身份方案,OBO 是多用户部署的首选:

方案适用场景服务器是否存令牌
OBO 委托认证(推荐)多用户、长期运行的 AI 代理❌ 否(每请求现换)
BYOT(自带令牌MS365_MCP_OAUTH_TOKEN)外部系统已管理令牌❌ 否
本地 MSAL 登录 + 缓存命令单账号固定身份✅ 是(可接外部存储)

OBO 委托认证工作原理:一次登录,代理长期工作

整个委托链条分为三步,身份始终“属于用户”,服务器只是中间人。

MCP 客户端(Claude Desktop / claude.ai / Open WebUI) │ ① OAuth 授权码 + PKCE(用户在浏览器登录一次) ▼ ms-365-mcp-server --http --obo (无状态,不存令牌) │ ② 收到 /mcp 请求,携带 Bearer Token ▼ OBO 令牌交换 acquireTokenOnBehalfOf │ ③ 换取 Graph 令牌(graph.microsoft.com/.default) ▼ Microsoft Graph API(以用户身份读写邮件/日历/文件)

拆开看这三步在源码里的落点:

  1. 授权只请求“访问本应用”。OBO 模式下/authorize只请求<clientId>/access_as_user(外加User.Read、offline_access与--extra-scopes),因此工具派生的 Graph 权限根本不会出现在授权同意页,见 src/server.ts#L858-L886。
  2. 令牌交换。收到/mcp请求后,服务器调用 MSAL 的acquireTokenOnBehalfOf,把用户令牌换成本应用的 Graph 令牌,核心实现在 src/obo-client.ts#L31-L48;请求级注入发生在 src/server.ts#L1083-L1089。
  3. 以用户身份访问 Graph。换得的令牌通过AsyncLocalStorage注入每个请求上下文(src/request-context.ts),代理的每次工具调用都继承“你的身份、你的权限、你的数据边界”。

🔑 关键点:最终能干什么,取决于租户已为你授予的管理员同意权限,而不是代理“想要”什么——这是 OBO 天然的安全边界。

无头环境 OBO 部署三步走

第一步:创建 Azure AD 应用注册(机密客户端)

OBO 必须使用机密客户端(confidential client),因此一定要创建客户端密钥:

  1. 新建应用注册,支持账户类型选“仅限本组织目录中的账户”(单租户)。

  2. 重定向 URI(平台类型 Web):填 MCP 客户端的回调地址,例如 Claude 的https://claude.ai/api/mcp/auth_callback。⚠️ 常见坑:填错会报AADSTS50011(redirect URI mismatch),详见 docs/deployment.md。

  3. API 权限:添加 Microsoft Graph 委托权限,用下面的命令打印你当前配置需要的精确清单:

    npx @softeria/ms-365-mcp-server --org-mode --list-permissions
  4. 授予管理员同意,跳过每个用户的重复授权:

    az ad app permission admin-consent --id your-app-client-id
  5. 在“证书和机密”中创建客户端密钥,并记下clientId、tenantId、clientSecret。

第二步:配置环境变量并启动服务

把凭据交给服务器(生产环境建议改用 Azure Key Vault,见下节)。最小启动命令:

MS365_MCP_CLIENT_ID=your-client-id \ MS365_MCP_TENANT_ID=your-tenant-id \ MS365_MCP_CLIENT_SECRET=your-secret \ npx @softeria/ms-365-mcp-server --http 3000 --org-mode --obo

用 Docker 运行(官方镜像,非 root 用户):

docker run -p 3000:3000 \ -e MS365_MCP_CLIENT_ID=your-client-id \ -e MS365_MCP_TENANT_ID=your-tenant-id \ -e MS365_MCP_CLIENT_SECRET=your-secret \ ghcr.io/softeria/ms-365-mcp-server:latest \ --http 3000 --org-mode --obo

⚠️ 启动自检:--obo若缺少--http或缺少MS365_MCP_CLIENT_SECRET会直接报错退出(--obo requires --http、--obo requires MS365_MCP_CLIENT_SECRET),校验逻辑见 src/server.ts#L422-L438。这些“快速失败”能帮你少踩坑。

第三步:连接 MCP 客户端

客户端指向你的 HTTP 端点,首次使用时自动发现 OAuth 端点并打开浏览器完成登录:

{ "mcpServers": { "ms365": { "type": "streamable-http", "url": "https://mcp.example.com/mcp" } } }

Claude Code 则可用:

claude mcp add ms365 --transport http https://mcp.example.com/mcp

若服务器位于反向代理之后,务必设置--public-url https://mcp.example.com,确保返回给浏览器的授权 URL 可从外部访问。

关键启动参数与权限配置

参数 / 环境变量作用何时使用
--obo启用 OBO 令牌交换无头、多用户部署必配
MS365_MCP_CLIENT_SECRET机密客户端密钥OBO 强制要求
--extra-scopes <scopes>向令牌请求追加 Graph 权限默认工具不覆盖、又确需的能力
--allowed-scopes <scopes>收窄暴露的工具面(不改变 OBO)企业按权限边界做工具裁剪
--read-only禁用全部写操作只读审计、降低风险
--preset mail/--preset teams按应用精简工具减少上下文与令牌消耗

几个新手容易混淆的点:

  • --extra-scopes才是“加权限”的正道。OBO 下用户只同意本应用自身作用域,因此想额外让代理读邮件,就在授权时加上,例如--extra-scopes 'Mail.Read',让用户在登录时同意(见 test/obo-authorize-extra-scopes.test.ts)。
  • --allowed-scopes不会“覆盖”OBO,它只收窄工具面,OAuth 元数据与登录流程仍按 OBO 规则运行,说明见 README.md。
  • 个人微软账户(consumers)需要显式作用域才能兑换令牌,服务器已自动在/token携带<clientId>/access_as_user offline_access以规避AADSTS70011,实现见 src/lib/microsoft-auth.ts#L343-L350。

生产环境安全最佳实践

针对无头、多租户部署,建议叠加以下护栏(均见 docs/deployment.md 的“Security Considerations”):

  • 密钥进 Key Vault:MS365_MCP_KEYVAULT_URL=https://your-keyvault.vault.azure.net,配合托管身份读取,避免密钥出现在环境变量。完整的一键部署模板见 examples/azure-container-apps/。
  • 无状态优先:OBO 路径不写入任何 MSAL 令牌缓存,天然规避令牌泄露风险。
  • 只读 + 工具过滤:--read-only叠加--enabled-tools或--preset,把代理能做的事缩到最小。
  • 审计日志:默认开启结构化审计,记录“谁在何时访问了什么”,满足合规留痕需求。
  • 重定向 URI 白名单:共享/生产部署建议用MS365_MCP_ALLOWED_REDIRECT_URIS显式收敛,防止开放重定向。

常见问题快速排查

现象可能原因处理
启动即报错退出--obo缺--http或缺MS365_MCP_CLIENT_SECRET补齐 HTTP 模式与机密客户端密钥
401 on /mcpclientId/tenantId配置错误核对应用注册 ID 与租户 ID
redirect_uri mismatch重定向 URI 与应用注册不一致在应用注册中登记客户端回调地址
Graph 返回403缺作用域 / 未授予管理员同意重跑--list-permissions并补授同意
AADSTS70011个人账户兑换缺scope服务器已自动携带作用域,确认租户为预期值

提示:OBO 令牌交换失败时,日志会打印OBO token exchange failed(来自 src/obo-client.ts),这是定位“换令牌”这一步的最直接线索。

小结

无头环境让 AI 代理长期为你工作的关键,就是选对身份模式:用--obo的 OBO 委托认证,服务器无状态、令牌即来即换,代理永远以“你”的身份和“你的权限”访问 Microsoft 365。掌握“应用注册 → 启动--http --obo→ 连接客户端”三步,再按需叠加只读、工具过滤与 Key Vault,就能安全地把 ms-365-mcp-server 部署成 7×24 的办公代理。

延伸阅读:docs/deployment.md(生产部署全景)、src/obo-client.ts(OBO 客户端)、examples/azure-container-apps/(一键部署示例)。

【免费下载链接】ms-365-mcp-server

A Model Context Protocol (MCP) server for interacting with Microsoft 365 and Microsoft Office services through the Graph API

项目地址:https://gitcode.com/gh_mirrors/ms/ms-365-mcp-server
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进