MWE审批MCP
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MWE审批MCP列出我的待审批任务"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MWE审批MCP
MWE审批MCP 是部署在 https://dingtalk.mwexk.com/mcp 的自托管钉钉 OA 审批 MCP Server。
当前版本:0.14.0。
当前架构
WorkBuddy / Codex
-> 本服务 OAuth 2.1 + PKCE
-> 钉钉 OAuth 验证真实企业用户
-> 本服务签发限 audience/scope 的短期 MCP token
-> Streamable HTTP /mcp
-> MWE审批MCP 企业内部应用 access token
-> 钉钉 OA OpenAPI
钉钉 bpms_task_change
-> 官方 Stream 长连接(仅上游事件摄取)
-> 本地待审批/已处理索引只提供自托管 Streamable HTTP;不提供 stdio。
已删除 AIHub 版本,不使用
mcp-gw.dingtalk.com。不提供或兼容
/platform/tools/*旧路由。钉钉
userAccessToken只用于登录身份验证,不作为 MCP Bearer、不持久化。OA OpenAPI 仍使用
MWE审批MCP企业内部应用的 App ID/App Secret。MCP token 中的
corpId + unionId + userId按请求绑定审批调用者,模型输入不能覆盖身份。钉钉 Stream 是服务端使用应用凭证建立的出站事件通道,不是 MCP 传输,不新增公网工具端点。
Related MCP server: DingTalk MCP Server V2
公共工具
正常 tools/list 只有三个按业务角色/主对象聚合的工具:
approval_inbox # 当前审批人:批量发现待审批或已处理任务
approval_task # 审批参与者:查看、同意、拒绝、评论
approval_request # 申请人:准备附件、提交、评论、撤销三个工具按业务角色和生命周期划分:approval_task 负责审批参与者对已知实例的查看、同意、拒绝和评论;approval_request 负责申请人准备/创建审批,并允许对本人发起的实例评论或撤销;approval_inbox 只读批量发现待审批/已处理记录并把 processInstanceId 交给 approval_task。评论是同一个内部动作,仅角色 scope 与实例关系校验不同;未实现的退回能力不会被公开宣称。
发现当前 OAuth 用户的待审批(recordStatus 省略时默认为 pending;limit=1 为单条,最多 20 条):
{
"recordStatus": "pending",
"page": 1,
"limit": 20
}发现当前 OAuth 用户已经处理的审批任务:
{
"recordStatus": "completed",
"page": 1,
"limit": 20
}事件索引覆盖不足时,可显式调用普通 OA 实例 ID 列表接口做最近 1–30 天的有限刷新;服务端只扫描 APPROVAL_INBOX_PROCESS_CODES 中的精确模板,单次最多检查 40 个候选实例,并逐实例验证当前 OAuth 用户的任务:
{
"recordStatus": "completed",
"refreshWindowDays": 7,
"page": 1,
"limit": 20
}若响应中的 refresh.truncated=true,继续把同一响应的 refresh.nextCursor 原样传回,并保持 recordStatus 与 refreshWindowDays 不变;循环到 truncated=false。cursor 由服务端 HMAC 认证,最多有效 24 小时,绑定当前用户、原时间窗口、状态和模板集合;篡改会失败关闭,且不包含用户、实例或模板明文:
{
"recordStatus": "completed",
"refreshWindowDays": 7,
"refreshCursor": "上一次响应的 refresh.nextCursor",
"page": 1,
"limit": 20
}approval_inbox 从 bpms_task_change 事件索引取候选项,然后逐项调用审批详情确认任务属于登录用户并与请求状态一致,才返回唯一 processInstanceId 和可用的 taskId。同一实例的多个任务事件合并成一条;taskCount/verifiedTaskCount 保留完整计数,taskIds 最多返回 20 个并用 taskIdsTruncated=true 声明截断,decisionResults 仅从当前详情仍有效的任务重建。若源事件缺少任务 ID,则仅返回实例 ID,并标记 taskIdUnavailable=true。刷新统计中的 indexedRecordCount 按唯一实例计数,indexedTaskCount 按写入的任务证据计数。候选详情失败时不会越过该页,而是返回可重试 cursor。completed 保存最近 30 天的 finish 事件并返回 decisionResult=agree|refuse|redirect,取消事件不会被当作已审批。普通 OA 没有免费的全量回填 API,因此两类响应都固定声明 coverage=partial 和 resyncRequired=true:它们只覆盖事件连接激活及保留窗口内的任务;若 5000 条容量边界截断更早记录,还会返回 capacityTruncated=true 并推进 coverageSince。该工具不冒充钉钉官方 DWS 的全历史收件箱。
刷新适配器同时接受钉钉详情中的毫秒时间戳和 ISO-8601 时间字符串;createdAt/completedAt/updatedAt 使用真实业务时间,不以本次扫描时刻替代。
读取审批:
{
"action": "view",
"processInstanceId": "审批实例ID"
}换取选定附件的临时下载链接:
{
"action": "view",
"processInstanceId": "审批实例ID",
"attachmentAction": "download",
"attachmentIds": ["详情中的fileId"],
"maxAttachments": 3
}服务端不下载、解析或 OCR 附件。Agent 客户端必须立即下载临时链接,并自行执行大小限制、重定向 Host 校验、文件识别、解析和 OCR。
同意审批:
{
"action": "approve",
"processInstanceId": "审批实例ID",
"taskId": "view返回的当前任务ID",
"requestId": "每次业务决定稳定复用的UUID",
"confirm": true,
"remark": "符合要求"
}拒绝时把 action 改为 reject,并提供非空 remark。写操作会重新读取当前任务,确认任务仍属于 OAuth 登录用户,并使用持久幂等账本阻止重复决定。
发起审批
approval_request 使用“默认拒绝 + 精确允许列表”。首版只接受:
expense_reimbursement:费用报销,固定processCode=PROC-2DB91B79-3CDD-421D-A223-0489A7BAB2C0。payment_request:付款申请,固定processCode=PROC-5E238117-7121-4CB3-8219-9F11A2E42BE4。
加班审批及所有其他模板均拒绝。公开 Schema 不接受 processCode、申请人、审批人、抄送人或流程节点;申请人来自 OAuth 绑定的钉钉用户,审批流完全沿用 OA 后台模板。提交前服务端调用官方 forecast 接口,按实时模板解析必需的发起人自选节点,并仅把 forecast 返回的 actorKey/userId 注入 targetSelectActioners;客户端不能选择或覆盖。必填自选节点无法解析时,在附件 commit 前失败关闭。
先用 dryRun 验证付款申请:
{
"action": "submit",
"template": "payment_request",
"fields": {
"documentNumber": "FK-20260817-001",
"payee": "收款单位",
"currency": "CNY",
"applicationDate": "2026-08-17",
"lines": [{
"purpose": "项目采购",
"amount": 880,
"reason": "合同付款",
"expenseDepartment": "研发部"
}]
},
"confirm": false,
"dryRun": true,
"requestId": "稳定复用的UUID"
}deptId 为可选部门提示,不是客户端提供的身份或权限依据。服务端始终查询 OAuth 申请人的实时通讯录:账号只属于一个部门时自动使用该部门,并规范化客户端遗留的根部门 1;账号属于多个部门且无法唯一确定时返回 DEPARTMENT_SELECTION_REQUIRED 及安全的部门 ID/名称候选,Agent 再用候选中的 deptId 重试。
评论审批实例
approval_task action=comment 可由当前 OAuth 用户对其实际参与的审批实例添加评论;approval_request action=comment 允许申请人对本人发起的精确允许列表实例补充说明或附件。两者调用相同内部动作。纯文本评论直接使用 phase=submit;附件评论先用 phase=prepare 获取审批钉盘直传信息,由 Agent 客户端完成 PUT,再用同一工具的 phase=submit 提交匹配的 fileName/fileSize/uploadKey/spaceId。服务端重新校验审批空间、commit 文件并要求钉钉完整返回 fileId/fileName/fileSize/fileType/spaceId 后才构造评论附件。评论正文为 1–1024 字符,附件最多 20 个、单文件最大 20 MiB、合计不超过 50 MiB;commentUserId 始终由服务端注入。真实写入要求 confirm=true 和稳定 UUID requestId。
{
"action": "comment",
"phase": "prepare",
"processInstanceId": "审批实例ID",
"text": "请查看补充材料",
"attachments": [{ "fileName": "ROI说明.pdf", "fileSize": 4096 }],
"confirm": true
}Agent 完成返回地址的直传后提交评论:
{
"action": "comment",
"phase": "submit",
"processInstanceId": "审批实例ID",
"text": "请查看补充材料",
"uploads": [{
"fileName": "ROI说明.pdf",
"fileSize": 4096,
"uploadKey": "prepare返回值",
"spaceId": "prepare返回值"
}],
"requestId": "稳定复用的UUID",
"confirm": true
}发起人补充材料时,把示例中的工具名从 approval_task 改为 approval_request,参数完全相同。审批写入仅依据 OAuth scope 与实时业务归属校验:approval_task 决策要求 approval:decide 且任务属于当前用户,approval_request 写操作要求 approval:create 且申请人身份由服务端绑定;不再维护部署级用户白名单。
钉钉当前公开的官方 OA 服务端 API 没有“保存到钉钉草稿箱”接口,发起审批接口也没有草稿标志。prepare 与 submit + dryRun=true 会读取实时模板、校验完整表单并构建最终请求,但不会创建审批实例,也不会在钉钉客户端草稿箱生成条目;项目不会用本地记录冒充钉钉草稿。
费用报销字段为 date、reason、counterparty 和至少一条 items;每条明细包含 amount、category(仅 AI费用 或 其它)、expenseDepartment、remark。
附件采用两阶段直传:
Agent 调用
action=prepare,传文件名、大小和模板允许的附件字段。MCP 返回钉钉签名的 HTTPS
PUT地址和请求头;Agent 直接把文件上传到钉钉,文件字节不经过 MCP。Agent 调用
action=submit,提交uploadKey、spaceId、文件名和大小;MCP 提交文件元数据并发起审批。带附件的最终创建请求由服务端注入与审批钉盘空间一致的
microappAgentId,并将附件表单值标记为componentType=DDAttachment;客户端不能覆盖这两个字段。
单文件最大 20 MiB、每单最多 10 个、合计最大 50 MiB。费用报销仅允许附件字段 invoice/other,付款申请仅允许 attachment。实际提交和撤销必须 confirm=true 且提供稳定 UUID requestId;幂等命名空间绑定 OAuth 申请人。附件提交、审批创建或撤销结果不确定时会失败关闭,禁止自动换 UUID 重试。
IDEMPOTENCY_OUTCOME_UNKNOWN 会返回安全诊断字段:failureStage、已 commit/总附件数、当前附件序号、原始安全错误码、HTTP 状态、上游错误码和 upstreamRequestId。这些诊断会与 uncertain 幂等项一起持久化,同 UUID 回读结果一致;账本回读只重建这组允许字段,不保存表单、文件名、uploadKey、用户 ID 或临时 URL。失败阶段仅限 attachment_context、attachment_commit、form_build 和 approval_create。若审批已返回实例 ID,仅随后的幂等账本写入失败,服务保留成功结果并标记 idempotencyPersistence=failed,同时尽力持久化最小实例恢复记录,不再吞掉实例 ID。
OAuth 端点
端点 | 用途 |
| MCP Protected Resource Metadata |
| 本站 Authorization Server Metadata |
| MCP 客户端授权入口 |
| 钉钉 OAuth 回调 |
| 授权码或 refresh token 换 MCP token |
| 受限公共客户端动态注册 |
| 撤销 refresh token family |
| OAuth 保护的 Streamable HTTP MCP |
| 存活检查 |
Access token 默认 60 分钟;refresh token 默认 7 天、每次使用都在 Store 内原子轮换,并从本次刷新重新计算 7 天窗口。服务端仅保留当前 token 与最近一代重放墓碑:重放最近一代会撤销当前 family,更早 token 直接按无效凭证拒绝,因此持续刷新时每个 family 状态保持 O(1)。授权事务、客户端注册和 refresh 哈希保存在 MCP_AUTH_STORE_PATH,原始 token 不落盘;成功签发 token 后动态客户端注册会滑动续期,停止使用 30 天后自动清理。升级到本版本时,仍未过期的旧 8 小时 refresh token 会在启动阶段一次性迁移到新窗口,已过期 token 不复活。
动态客户端注册采用服务端幂等复用:经过校验且语义相同的公共客户端元数据(包括回调地址、客户端名称和协议能力)返回已有 client_id,并优先复用仍绑定有效 refresh family 的旧注册;不同元数据保持隔离。/register 重复请求本身不会延长注册寿命,只有成功签发或刷新 token 才滑动续期。既有重复记录不批量删除,停止使用后按 30 天 TTL 自然清理。安全审计只记录“新建/复用”结果,不记录 client ID、元数据、授权 URL 或凭据。
服务端在 OAuth scope 不变时更新,不要求用户重新登录钉钉:客户端应沿用现有 refresh token 静默换取 access token,重新执行 initialize 与 tools/list。Codex 的 URL-only 配置使用 startup_timeout_sec = 30;codex mcp list/get 只读配置,不会为已启动任务热回填缺失工具,Codex Desktop 需在 MCP servers 设置执行 Restart 或重启应用后创建新任务。initialize.serverInfo.version、/healthz 的 version/toolsRevision 以及 /mcp 的 x-mcp-server-version/x-mcp-tools-revision 可用于检测工具版本;MCP 响应要求重新验证缓存。升级到 0.14.0 仅需用原持久卷与原签名密钥重建服务端,不变更 issuer、audience、scope 或 /app/data/auth,已授权客户端无需重新授权。只有新增 scope、refresh token 超过 7 天滚动窗口、用户主动撤销或检测到 token 重放时,才需要交互式重新授权。服务端的 DCR 幂等复用可减少客户端注册漂移,但不能修复客户端本地凭据丢失或工具注册表缓存故障,也不能强制不支持刷新机制的客户端主动清除其本地工具缓存。
开发者后台
在 MWE审批MCP 企业内部应用中配置精确 OAuth 回调:
https://dingtalk.mwexk.com/oauth/dingtalk/callback并确认应用具备:
登录用户身份/个人信息权限。
根据 unionId 映射企业 userId 的通讯录权限
qyapi_get_member。审批实例读写和审批表单读取权限。
附件直传所需的
Storage.UploadInfo.Read与Storage.File.Write权限。H5 微应用能力及其 AgentId;将正整数配置为
DINGTALK_AGENT_ID。未配置时,无附件审批仍可使用,附件prepare会明确失败。事件订阅的推送方式选择
Stream模式推送,并订阅“审批任务开始、结束、取消/转交”(bpms_task_change)。生产配置DINGTALK_APPROVAL_EVENTS_ENABLED=true,索引保存到APPROVAL_INBOX_PATH。
Premium.Workflow.ReadWrite.All 及 OA 高级版待审批/已处理列表不是生产依赖。Todo.Todo.Read 只在 2026-08-17 做过可行性探测:当前企业的未完成和已完成企业待办都返回 0,不能用它冒充 OA 收件箱;服务代码不调用该接口。
附件上传 URL 必须经过 HTTPS 主机白名单校验。2026-08-17 的企业实测返回
sh-dualstack.trans.dingtalk.com,因此默认精确允许 .trans.dingtalk.com;同时保留
钉钉可能返回的 .aliyuncs.com 存储域。不要把白名单放宽为任意 .dingtalk.com。
OAuth 授权范围包含 approval:read、approval:decide 与 approval:create。未认证请求的 HTTP 401 challenge 只声明 resource_metadata,由客户端从 metadata 的 scopes_supported 选择授权范围;服务端不再用 scope=approval:read 覆盖 metadata。本站 /authorize 只校验并保存 MCP 授权事务,然后立即跳转到钉钉官方 OAuth 页面,不展示自建权限确认页。客户端以较小 scope 连接后,调用发起审批或审批决定动作时,服务端仍会按 MCP Authorization 规范返回 HTTP 403 insufficient_scope challenge;不要把缺 scope 仅包装成 HTTP 200 的工具业务错误。所有实际写操作仍要求工具层 confirm=true。
无效、过期、签名错误或已被替换的 MCP access token 统一返回 HTTP 401 invalid_token 及 canonical resource_metadata challenge,不得因底层 JWT 异常返回 500。这样客户端可以进入标准 refresh/login 恢复链路,而不会把 MCP 标记为服务端故障。
本地验证
cd "D:\codex项目\金蝶领星钉钉三端数据同步开发\approval-mcp"
npm ci
npm test
npm run typecheck
npm run build生成 Ed25519 PKCS#8 签名私钥:
mkdir -p secrets
openssl genpkey -algorithm Ed25519 -out secrets/mcp-signing-private.pem
openssl rand -base64 32 > secrets/mcp-audit-hmac.key
chmod 600 secrets/mcp-signing-private.pem secrets/mcp-audit-hmac.key复制 .env.example 配置真实环境变量。服务不会自动读取 .env;Compose、systemd 或密钥管理器必须显式注入。
启动:
npm run build
node .\dist\transports\http.js客户端
WorkBuddy 与 Codex 的无密钥 OAuth 配置模板和测试顺序见:
客户端配置中只出现公开 MCP URL,不填写 App Secret、Bearer token 或钉钉 userAccessToken。
部署
使用
compose.example.yaml部署应用。MCP 签名私钥和独立审计 HMAC key 均以只读 Secret 文件挂载。
deploy/cvm/edge/dingtalk.conf只转发/mcp、OAuth/metadata 端点和/healthz。当前 CVM 入口以
/public/cvm-web-edge/README.md为准:应用只发布一个唯一的 loopback 后端端口,由edge-nginx转发;不得绑定0.0.0.0。127.0.0.1:3000已登记给唯一的正式 DingTalk 服务。后续并行灰度须通过APPROVAL_HOST_PORT选择并登记另一个经ss -lntp验证为空闲的临时端口;临时实例不得继续占用正式端口。容器 Router 与共享外部 Docker 网络是后续全站入口迁移目标,不在本次 MCP 鉴权升级中单点切换。
OAuth/审批状态、事件驱动的待审批及最近 30 天已处理索引、幂等账本和最多 30 天审计日志位于持久卷
/app/data。同一应用 Client ID 同时只能运行一个生产 Stream 消费者。灰度容器不得在旧生产容器仍运行时开启
DINGTALK_APPROVAL_EVENTS_ENABLED。
详细安全与模块设计见:
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
MCP server providing attendance data queries via the CloudTime API.
MCP server for stocksense-ai documentation, generated by doc2mcp.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceA Model Control Protocol server that provides access to DingDing (Chinese workplace collaboration platform) API features, including retrieving access tokens, department lists, user information, and searching users by name.2
- AlicenseNot gradedqualityDmaintenanceA Model Control Protocol server for integrating with DingTalk, enabling users to send messages, retrieve conversation/user information, and query calendar events through Claude.6MIT
- FlicenseCqualityCmaintenanceMCP server that enables AI agents to control all DingTalk features (messaging, calendar, tasks, approvals, etc.) via natural language using the DingTalk Workspace CLI.831
- AlicenseNot gradedqualityBmaintenanceMCP server for Feishu/Lark API integration, enabling AI agents to send messages, manage groups, create and edit documents and spreadsheets, and search knowledge bases.MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/mwe-support/DingTalkMCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server