🚀 模型上下文协议(MCP)服务器 + Microsoft Entra ID OAuth + 待办事项管理
本项目是一个支持远程 MCP 连接的 模型上下文协议(MCP) 服务器,内置 Microsoft Entra ID(前身为 Azure AD)OAuth 功能,并且具备全面的 Microsoft To Do 任务管理能力。
你可以将其部署到自己的 Cloudflare 账户中。创建自己的 Azure AD OAuth 应用程序后,你将拥有一个功能完备的远程 MCP 服务器,可在此基础上进行开发。用户能够使用他们的 Microsoft 账户登录并连接到你的 MCP 服务器,管理待办事项列表、创建任务、设置提醒等。
你可以将此项目作为参考示例,学习如何使用 workers-oauth-provider 库,将其他 OAuth 提供商与部署到 Cloudflare 的 MCP 服务器集成。
MCP 服务器(由 Cloudflare Workers 提供支持):
- 作为 OAuth 服务器 为 MCP 客户端提供服务。
- 作为 OAuth 客户端 连接到真正的 OAuth 服务器(在本例中为 Microsoft Entra ID)。
🚀 快速开始
克隆仓库并安装依赖:
npm install
生产环境部署
创建新的 Azure AD 应用程序
-
访问 Azure 门户 → Azure Active Directory → 应用注册。
-
点击 新建注册。
-
进行如下配置:
- 名称:
MCP Entra OAuth Todo Server
- 支持的账户类型:
- 若要支持 多租户(推荐):选择 “任何组织目录中的账户(任何 Azure AD 目录 - 多租户)和个人 Microsoft 账户”。
- 若仅支持单个组织:选择 “仅此组织目录中的账户”。
- 重定向 URI:
- 类型:
Web
- URI:
https://remote-mcp-entra-oauth-todo.<your-subdomain>.workers.dev/callback
- 同时添加:
http://localhost:8789/callback(开发环境)
-
注册完成后,记录以下信息:
-
创建客户端密钥:
- 访问 证书和密钥 → 新建客户端密钥。
- 立即复制密钥值(之后将无法再次查看)。
-
配置 API 权限:
- 访问 API 权限 → 添加权限 → Microsoft Graph → 委托权限。
- 添加:
User.Read(登录并读取用户个人资料)
Tasks.ReadWrite(读取和写入用户的任务)
- 为你的组织点击 授予管理员同意。
💡 专业提示:代码使用 https://graph.microsoft.com/.default 范围,该范围会动态请求所有预先同意的权限。要添加新工具或权限,只需在 Azure 门户中添加并授予同意,无需更改代码!
-
通过 Wrangler 设置密钥:
wrangler secret put ENTRA_CLIENT_ID
wrangler secret put ENTRA_CLIENT_SECRET
wrangler secret put ENTRA_TENANT_ID
wrangler secret put COOKIE_ENCRYPTION_KEY
wrangler secret put DEFAULT_TIMEZONE
⚠️ 重要提示
多租户配置:设置 ENTRA_TENANT_ID 时:
- 使用
common:允许工作/学校账户和个人 Microsoft 账户(多租户推荐)。
- 使用
organizations:仅允许工作/学校账户(Azure AD),不允许个人账户。
- 使用
consumers:仅允许个人 Microsoft 账户。
- 使用特定租户 ID:仅允许该特定租户的用户。
对于多租户应用,使用 common 可确保在用户的主租户上下文中颁发令牌,即使他们是其他租户的来宾用户,也能访问其个人资源(如待办事项列表)。
⚠️ 重要提示
创建第一个密钥时,Wrangler 会询问是否创建新的 Worker。输入 "Y" 创建新的 Worker 并保存密钥。
设置时区
- 设置
DEFAULT_TIMEZONE 为你首选的时区(例如 Asia/Tokyo、America/New_York、Europe/London)。
- 除非另有指定,否则所有任务的截止日期和提醒都将使用该时区。
- 用户仍可根据需要为每个任务指定不同的时区。
- 如果未设置,默认为
Europe/London。
设置 KV 命名空间
wrangler kv namespace create "OAUTH_KV"
部署和测试
将 MCP 服务器部署到你的 workers.dev 域名:
wrangler deploy
使用 Inspector 测试远程服务器:
npx @modelcontextprotocol/inspector@latest
输入 https://remote-mcp-entra-oauth-todo.<your-subdomain>.workers.dev/mcp 并点击连接。完成身份验证流程后,你将看到工具可用。
现在你已成功部署远程 MCP 服务器!
从 Claude Desktop 访问远程 MCP 服务器
打开 Claude Desktop,导航到设置 -> 开发者 -> 编辑配置。这将打开控制 Claude 可访问的 MCP 服务器的配置文件。
将内容替换为以下配置。重启 Claude Desktop 后,将打开一个浏览器窗口显示 OAuth 登录页面。完成身份验证流程,授予 Claude 访问你的 MCP 服务器的权限。授予访问权限后,工具将可供使用。
{
"mcpServers": {
"entra-todo": {
"command": "npx",
"args": [
"mcp-remote",
"https://remote-mcp-entra-oauth-todo.<your-subdomain>.workers.dev/mcp"
]
}
}
}
当界面中出现工具(在 🔨 下方)时,你可以要求 Claude 使用它们。例如:
- "能否从 Microsoft Graph 获取我的用户个人资料?"
- "显示我所有的待办事项列表"
- "在我的工作列表中创建一个截止日期为下周五的新任务"
- "我本周有哪些任务到期?"
本地开发
如果你想迭代和测试 MCP 服务器,可以在本地开发环境中进行。这需要在 Azure AD 中创建另一个 OAuth 应用程序:
- 主页 URL 指定为
http://localhost:8789。
- 授权回调 URL 指定为
http://localhost:8789/callback。
- 记录客户端 ID 并生成客户端密钥。
- 在项目根目录创建
.dev.vars 文件,内容如下:
ENTRA_CLIENT_ID=your_development_azure_ad_client_id
ENTRA_CLIENT_SECRET=your_development_azure_ad_client_secret
ENTRA_TENANT_ID=common # 多租户使用 'common',或使用特定租户 ID
COOKIE_ENCRYPTION_KEY=any_random_string_here
DEFAULT_TIMEZONE=Europe/London
开发和测试
在本地运行服务器,使其在 http://localhost:8789 可用:
wrangler dev
要测试本地服务器,在 Inspector 中输入 http://localhost:8789/mcp 并点击连接。按照提示操作后,你将能够 “列出工具”。
使用 Claude 和其他 MCP 客户端
使用 Claude 连接到远程 MCP 服务器时,可能会看到一些错误消息。这是因为 Claude Desktop 尚未支持远程 MCP 服务器,所以有时会出现混淆。要验证 MCP 服务器是否已连接,将鼠标悬停在 Claude 界面右下角的 🔨 图标上,你应该会看到可用的工具。
使用 Cursor 和其他 MCP 客户端
要将 Cursor 与 MCP 服务器连接,选择 类型:“命令”,并在 命令 字段中将命令和参数字段合并为一个(例如 npx mcp-remote https://<your-worker-name>.<your-subdomain>.workers.dev/mcp)。
请注意,虽然 Cursor 支持 HTTP+SSE 服务器,但不支持身份验证,因此仍需使用 mcp-remote(并使用 STDIO 服务器,而不是 HTTP 服务器)。
你可以通过打开其他 MCP 客户端(如 Windsurf)的配置文件,添加与 Claude 设置相同的 JSON 内容,然后重启 MCP 客户端,将 MCP 服务器连接到这些客户端。
🔧 工作原理
OAuth 提供商
OAuth 提供商库是 Cloudflare Workers 的完整 OAuth 2.1 服务器实现。它处理 OAuth 流程的复杂性,包括令牌颁发、验证和管理。在本项目中,它扮演以下双重角色:
- 对连接到服务器的 MCP 客户端进行身份验证。
- 管理与 Microsoft Entra ID 的 OAuth 服务的连接。
- 在 KV 存储中安全地存储令牌和身份验证状态。
持久化 MCP
持久化 MCP 通过 Cloudflare 的 Durable Objects 扩展了基本 MCP 功能,提供:
- MCP 服务器的持久状态管理。
- 请求之间身份验证上下文的安全存储。
- 通过
this.props 访问经过身份验证的用户信息。
- 根据用户身份支持有条件的工具可用性。
MCP 远程
MCP 远程库使服务器能够公开可由 Inspector 等 MCP 客户端调用的工具。它:
- 定义客户端与服务器之间的通信协议。
- 提供定义工具的结构化方式。
- 处理请求和响应的序列化和反序列化。
- 支持流式 HTTP(推荐)和服务器发送事件(SSE)协议进行客户端通信。
🚧 传输协议迁移
此示例已更新为支持新的 流式 HTTP 传输协议,该协议取代了已弃用的服务器发送事件(SSE)协议。服务器现在公开两个端点:
/mcp - 推荐:使用新的流式 HTTP 协议。
/sse - 已弃用:旧的 SSE 协议(为向后兼容性保留)。
所有新集成应使用 /mcp 端点。SSE 端点将在未来版本中移除。
🛠️ 可用工具
用户个人资料
getUserProfile - 获取经过身份验证的用户的 Microsoft Graph 个人资料。
待办事项列表管理
listTodoLists - 获取经过身份验证的用户的所有待办事项列表。
createTodoList - 创建一个具有指定名称的新任务列表。
updateTodoList - 更新现有任务列表的名称。
deleteTodoList - 删除一个任务列表。
任务管理
listTasks - 从特定的待办事项列表中获取所有任务。
getTask - 获取特定任务的详细信息。
createTask - 创建一个具有可选属性的新任务:
- 标题(必需)
- 正文/描述
- 截止日期和时间
- 提醒日期和时间
- 重要性级别(低、正常、高)
- 类别/标签
- 日期的时区
updateTask - 更新任务的任何属性:
- 标题
- 正文/描述
- 状态(未开始、进行中、已完成、等待他人、推迟)
- 重要性级别
- 截止日期和时间
- 提醒设置
- 类别
deleteTask - 从列表中删除一个任务。
简单测试工具
add - 相加两个数字(用于测试 MCP 连接)。
💻 使用示例
要求 Claude 帮助你完成以下任务:
- "显示我所有的待办事项列表"
- "创建一个名为 '购物' 的新列表"
- "在我的购物列表中添加一个任务 '购买杂货',截止日期为明天下午 5 点"
- "我的工作列表中有哪些任务?"
- "将任务 '致电客户' 更新为高重要性,截止日期为周五"
- "将 '提交报告' 任务标记为已完成"
- "为我的 '团队会议准备' 任务设置明天上午 9 点的提醒"
- "从我的个人列表中删除所有已完成的任务"
➕ 添加新工具
由于 OAuth 流程中使用了 .default 范围,添加新工具非常简单:
- 在 Azure 门户中添加权限:
- 访问你的应用 → API 权限。
Tasks.ReadWrite 权限已包含在待办事项功能中。
- 如果尚未授予管理员同意,请进行授予。
- 在代码中添加工具():
this.server.tool(
"getTodoTaskList",
"Get details of a specific todo task list",
{
listId: z.string().describe("The ID of the todo list to retrieve"),
},
async ({ listId }) => {
const client = Client.init({
authProvider: (done) => {
done(null, this.props!.accessToken);
},
});
try {
const taskList = await client
.api(`/me/todo/lists/${listId}`)
.get();
return {
content: [{ text: JSON.stringify(taskList, null, 2), type: "text" }],
};
} catch (error) {
return {
content: [{
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
type: "text"
}],
isError: true,
};
}
}
);
- 部署:
npm run deploy
就是这么简单!由于 .default 范围会动态请求所有预先同意的权限,因此无需更改 OAuth 流程中的范围。
🔒 安全说明
- ✅ 客户端密钥存储为 Cloudflare Workers 密钥(不会向客户端公开)。
- ✅ OAuth 状态参数可防止 CSRF 攻击。
- ✅ HMAC 签名的 cookie 用于批准对话框的持久化。
- ✅ 访问令牌在 MCP 会话令牌中加密。
- ✅ 所有通信均通过 HTTPS 进行。
- ✅ 批准对话框在授权前显示客户端信息。
🐞 故障排除
"获取访问令牌失败"
- 检查 Azure 门户中的客户端密钥是否正确且未过期。
- 验证重定向 URI 是否完全匹配(包括协议和端口)。
- 确保
ENTRA_TENANT_ID 正确。
"Tasks.ReadWrite 权限被拒绝"
- 确保在 Azure 门户中授予了管理员同意。
- 检查用户在 Azure AD 中是否具有适当的权限。
- 验证权限是否作为 委托权限 添加,而不是应用程序权限。
"无效的租户"
- 验证密钥中的
ENTRA_TENANT_ID 是否正确。
- 对于多租户应用,使用
common 作为租户 ID 以支持工作/学校和个人账户。
- 仅支持工作/学校账户使用
organizations,仅支持个人账户使用 consumers。
- 如果使用特定租户,请确保租户 ID 与 Azure 门户中显示的一致。
- 来宾用户注意事项:如果用户是租户的来宾用户,但试图访问其个人资源(如待办事项),必须使用
common,以便在其主租户上下文中颁发令牌。
Claude Desktop 连接问题
- 更新配置后重启 Claude Desktop。
- 检查 Worker URL 是否正确且可访问。
- 使用
wrangler secret list 验证所有密钥是否设置正确。
任务时区问题
- 验证密钥中的
DEFAULT_TIMEZONE 是否设置正确。
- 使用标准时区名称(例如
America/New_York,而不是 EST)。
- 可以通过在工具参数中指定时区来覆盖默认时区。
🏗️ 架构
此实现遵循标准的 OAuth 2.0 授权码流程:
- 用户打开 MCP 客户端 → 客户端尝试连接到 MCP 服务器。
- 服务器启动 OAuth → 显示包含客户端信息的批准对话框。
- 用户批准 → 重定向到 Microsoft 登录页面。
- 用户进行身份验证 → Microsoft 使用授权码重定向回服务器。
- 服务器交换代码 → 使用客户端密钥从 Microsoft 获取访问令牌。
- 服务器获取用户信息 → 调用 Microsoft Graph 获取用户个人资料。
- 颁发令牌 → MCP 客户端接收包含用户上下文的加密令牌。
- 工具可用 → 客户端现在可以使用委托权限调用 Microsoft Graph 工具。
Cloudflare Worker 充当 机密客户端(服务器端应用程序),它:
- 安全地存储客户端密钥。
- 处理完整的 OAuth 流程。
- 将授权码交换为访问令牌。
- 代表经过身份验证的用户进行 Microsoft Graph API 调用。
📄 许可证
本项目采用 MIT 许可证。