Files
dingMCP/distribution/agent-install.template.md
T
gitea-admin a08a2c1a96
CI / Client installer (macos-latest) (push) Canceled after 0s
CI / Client installer (ubuntu-latest) (push) Canceled after 0s
CI / Client installer (windows-latest) (push) Canceled after 0s
CI / test (22) (push) Canceled after 0s
CI / test (24) (push) Canceled after 0s
CI / release-smoke (push) Canceled after 0s
fix: harden proxied client installation
2026-08-18 16:01:06 +00:00

16 KiB
Raw Blame History

钉钉审批客户端安装任务

用户把本文件或本文件的链接交给你,即表示授权你为当前用户安装或更新“钉钉审批”客户端、Skill 和名为 dingtalk-approval 的 MCP。该授权不包含同意、拒绝、退回、撤回或发起任何审批。

请从“步骤 1”开始逐项执行并验收,不要跳步,不要让用户手工填写企业凭证,也不要根据经验自行改写安装器返回的路径或 MCP 配置。Windows 是完整支持的平台,必须优先使用下面的 PowerShell 步骤。

固定发布入口

  • 版本:{{VERSION}}
  • 安装器:{{INSTALLER_URL}}
  • 安装器 SHA-256:{{INSTALLER_SHA256}}
  • 发布公钥:{{PUBLIC_KEY_URL}}
  • 公钥 SHA-256:{{PUBLIC_KEY_SHA256}}
  • 公钥编号:{{RELEASE_KEY_ID}}
  • 签名清单:{{MANIFEST_URL}}
  • 清单签名:{{MANIFEST_SIGNATURE_URL}}
  • 国内备用发布源: {{DOWNLOAD_MIRROR_BASE_URLS_MARKDOWN}}
  • 统一网关:{{GATEWAY_URL}}
  • Windows 安装引导:{{BOOTSTRAP_WINDOWS_URL}}
  • Windows 安装引导备用地址: {{BOOTSTRAP_WINDOWS_MIRROR_URLS_MARKDOWN}}
  • Windows 安装引导 SHA-256:{{BOOTSTRAP_WINDOWS_SHA256}}
  • Linux/macOS 安装引导:{{BOOTSTRAP_POSIX_URL}}
  • Linux/macOS 安装引导备用地址: {{BOOTSTRAP_POSIX_MIRROR_URLS_MARKDOWN}}
  • Linux/macOS 安装引导 SHA-256:{{BOOTSTRAP_POSIX_SHA256}}
  • 私有 Node.js:{{NODE_VERSION}}(最低兼容版本 {{NODE_MINIMUM_VERSION}})

首次安装通过上述 HTTPS 地址和固定 SHA-256 建立信任;安装器随后必须使用固定公钥验证 Ed25519 清单签名和全部发布物哈希。URL、TLS、签名或哈希任一不匹配都必须停止。不得索取 AppKey、AppSecret、AuthoritySecret、CorpId、userId、员工号、Cookie 或 Token。

完成标准

只有以下条件全部成立,才能告诉用户“安装完成,可以使用”:

  1. 对应平台安装引导的 SHA-256 正确,并已选用兼容的系统 Node 或经过官方哈希校验的私有 Node;
  2. 安装器 JSON 返回 ok: true;
  3. 已按当前 Agent 的官方方式安装返回的 skillPath;
  4. 已原样使用返回的 mcpConfig 注册并信任本地 stdio MCP;
  5. approval_login 确认已登录;
  6. approval_list_todos 的双来源验证中,钉钉 OA 与薪福通都为 ok;
  7. 未执行任何审批写操作。

步骤 1:确认操作系统与架构

支持以下当前用户环境:

  • Windows 10/11:x64 或 ARM64;
  • Linux:x64 或 ARM64;
  • macOS:Intel x64 或 Apple Silicon ARM64。

系统无需预装 Node.js。安装引导会优先复用版本不低于 {{NODE_MINIMUM_VERSION}} 且 npm 可用的系统 Node;否则自动准备只属于本插件的 Node {{NODE_VERSION}}。不要让用户安装全局 Node,不要使用管理员权限、sudo、全局 npm 安装、DWS 或浏览器自动化。

步骤 2:下载、校验并执行平台安装引导

不要在浏览器中复制脚本内容,不要对 URL 解码、重新编码或手工拼接。必须先校验安装引导 SHA-256,再执行它。

为执行平台安装引导的 Agent 工具调用设置至少 10 分钟超时。引导和安装器会把 [dingtalk-approval] 开头的阶段进度写入 stderr,把唯一的最终结果 JSON 写入 stdout;进度文本不是失败,也不能混入 JSON 解析。进程仍在运行时不得并发启动第二次安装。

如果当前环境通过 HTTPS_PROXY、HTTP_PROXY 或 ALL_PROXY 出网,安装引导会在兼容 Node 上自动为下载、登录和 Bridge 启用环境代理,并在离线 npm 展开前隔离 Node 的代理开关。不要设置全局 NODE_OPTIONS=--use-env-proxy,也不要手工预装 node_modules;这会让 npm 与 Node 的代理机制叠加,并破坏安装器的原子安装与故障恢复。

Windows(PowerShell)

无论当前 Agent 默认使用 PowerShell、CMD 还是 Git Bash,Windows 都必须调用普通 PowerShell 执行下面的完整流程。不得从 Git Bash 直接运行内部的 node dingtalk-approval-installer.mjs ... 命令;内部安装器不是用户安装入口。

在普通 PowerShell 中逐行运行:

$dingBootstrapDir = Join-Path ([System.IO.Path]::GetTempPath()) ("dingmcp-bootstrap-" + [guid]::NewGuid().ToString("N"))
New-Item -ItemType Directory -Path $dingBootstrapDir -Force | Out-Null
$dingBootstrap = Join-Path $dingBootstrapDir "dingtalk-approval-bootstrap.ps1"
$dingBootstrapUrls = @({{BOOTSTRAP_WINDOWS_URLS_POWERSHELL}})
$dingBootstrapDownloaded = $false
foreach ($dingBootstrapUrl in $dingBootstrapUrls) {
  try {
    Invoke-WebRequest -UseBasicParsing -Uri $dingBootstrapUrl -OutFile $dingBootstrap -TimeoutSec 300
  } catch {
    continue
  }
  $dingBootstrapHash = (Get-FileHash -Algorithm SHA256 $dingBootstrap).Hash.ToLowerInvariant()
  if ($dingBootstrapHash -ne "{{BOOTSTRAP_WINDOWS_SHA256}}") { throw "Windows 安装引导 SHA-256 不匹配,停止安装:$dingBootstrapUrl" }
  $dingBootstrapDownloaded = $true
  break
}
if (-not $dingBootstrapDownloaded) { throw "所有 Windows 安装引导下载源均不可用" }
$dingInstallJson = & powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File $dingBootstrap
if ($LASTEXITCODE -ne 0) { throw "钉钉审批安装引导执行失败:$dingInstallJson" }
$dingInstall = $dingInstallJson | ConvertFrom-Json
if ($dingInstall.ok -ne $true) { throw "钉钉审批安装失败:$($dingInstall.error)" }
$dingInstall | ConvertTo-Json -Depth 20

完成后可删除 $dingBootstrapDir。任一下载或哈希检查失败都不能忽略。

Linux / macOS(POSIX shell)

ding_bootstrap_dir="$(mktemp -d)"
ding_bootstrap="$ding_bootstrap_dir/dingtalk-approval-bootstrap.sh"
ding_bootstrap_downloaded=0
for ding_bootstrap_url in {{BOOTSTRAP_POSIX_URLS_POSIX}}; do
  rm -f "$ding_bootstrap"
  if command -v curl >/dev/null 2>&1; then
    curl --fail --location --connect-timeout 10 --max-time 300 --output "$ding_bootstrap" "$ding_bootstrap_url" || continue
  elif command -v wget >/dev/null 2>&1; then
    wget --https-only --timeout=300 --output-document="$ding_bootstrap" "$ding_bootstrap_url" || continue
  else
    echo '缺少 curl 或 wget,无法下载安装引导' >&2
    exit 1
  fi
  if command -v sha256sum >/dev/null 2>&1; then
    ding_bootstrap_hash="$(sha256sum "$ding_bootstrap" | awk '{print $1}')"
  else
    ding_bootstrap_hash="$(shasum -a 256 "$ding_bootstrap" | awk '{print $1}')"
  fi
  if [ "$ding_bootstrap_hash" != '{{BOOTSTRAP_POSIX_SHA256}}' ]; then
    echo "Linux/macOS 安装引导 SHA-256 不匹配,停止安装:$ding_bootstrap_url" >&2
    exit 1
  fi
  ding_bootstrap_downloaded=1
  break
done
if [ "$ding_bootstrap_downloaded" -ne 1 ]; then
  echo '所有 Linux/macOS 安装引导下载源均不可用' >&2
  exit 1
fi
ding_install_json="$(sh "$ding_bootstrap")"
printf '%s\n' "$ding_install_json"

完成后可删除 $ding_bootstrap_dir。如果 sha256sum 与 shasum 都不存在,必须停止,不能跳过校验。

步骤 3:验收安装结果

步骤 2 的平台引导是唯一通用安装入口。它会:

  1. 检查系统 Node;缺失或版本不兼容时,根据当前操作系统和 CPU 架构选择私有 Node;
  2. 按“阿里云精确版本 → npmmirror 精确版本 → Node 官方精确版本”的顺序下载 Node;项目安装引导和发布物则按“主发布源 → 国内 Gitea 备用源 → 其他已配置镜像”回退。网络或 HTTP 下载失败才切换来源,任一已下载文件的签名或 SHA-256 不匹配都会立即终止;
  3. 把私有 Node 放在插件自己的当前用户数据目录,不修改系统 PATH,不要求管理员权限;
  4. 下载并校验首次安装器和发布公钥,再由安装器验证 Ed25519 清单签名与全部客户端发布物;下载源不是信任根,备用源不能绕过签名或哈希;
  5. 返回一份 JSON 安装结果。

安装器会在稳定的当前用户数据目录安装客户端与 Skill,不会全局安装 npm 包,也不会修改 Agent 私有配置。保留完整 JSON 结果,后续只使用其中的真实字段,不要猜路径。

安装结果至少必须包含:

  • ok: true、status: "installed" 和 version;
  • cliPath、bridgePath、skillPath;
  • loginCommand;
  • mcpConfig.mcpServers.dingtalk-approval;
  • postInstall。
  • nodeRuntime,其中 managed: true 表示正在使用插件私有 Node。

Windows 的 bridgePath 和 mcpConfig...command 正常应以 dingtalk-approval-bridge.cmd 结尾。路径中可能包含空格;保留完整字符串,不要拆分,不要去掉 .cmd,不要改为 node、npx 或远程 URL。

步骤 4:安装 Skill 并注册 MCP

  1. 按当前 Agent 的官方方式安装 skillPath 指向的整个目录,而不是只复制 SKILL.md。确认目录中同时存在 SKILL.md 和 references/create-approval.md。
  2. 使用 mcpConfig 只新增或替换名称精确为 dingtalk-approval 的连接器。安装器本身不会猜测或修改 Agent 的私有配置。
  3. 如果 Agent 接受完整 MCP JSON,原样使用整个 mcpConfig;如果界面只接受单个服务器配置,原样使用 mcpConfig.mcpServers.dingtalk-approval。
  4. 该连接器必须是本地 stdio,command 必须是返回的本地 bridgePath,args 必须为空数组。Windows 中必须保留 JSON 已正确转义的反斜杠。
  5. 不要把 {{GATEWAY_URL}} 或 https://approval.justconn.top/mcp 作为 MCP URL、command 或参数;Bridge 会从已签名安装状态取得网关地址。
  6. 不要添加 --url、企业凭证、用户 ID、额外环境变量或 shell 包装器。

正确配置的形态由安装器返回,语义如下;示例路径不能代替真实返回值:

{
  "mcpServers": {
    "dingtalk-approval": {
      "type": "stdio",
      "command": "<安装器返回的本地 bridgePath;Windows 为 .cmd>",
      "args": []
    }
  }
}

步骤 5:处理首次登录状态

安装器已经主动尝试准备登录。读取返回的 postInstall 及其 status,不得等到用户第一次查询审批:

  • authorization_required:在完成本地 Skill/MCP 配置的同一轮回复中,把 postInstall.authChallenge.directUrl 作为完整、可点击的 URL 原样发给用户;不得只说“已生成”或“已推送”。同时说明链接有有效期,需由用户本人核对授权页面并确认。
  • authenticated:已有登录可复用,不需要再次让用户授权,继续步骤 6 和步骤 7。
  • unavailable:客户端安装仍然有效。先完成步骤 4;连接器加载后调用 approval_login 重试。不要删除会话、不要重装。

保存 loginCommand.command 和 loginCommand.args。如果首次链接过期且 MCP 尚未加载,按该对象原样执行命令;Windows PowerShell 的通用执行方式是:

$dingLoginJson = & $dingInstall.loginCommand.command @($dingInstall.loginCommand.args)
$dingLogin = $dingLoginJson | ConvertFrom-Json
$dingLogin | ConvertTo-Json -Depth 20

把新结果中的 authChallenge.directUrl 原样展示。该命令只检查登录或生成新链接,不下载发布物、不修改 Agent 配置。MCP 已加载时则直接重新调用 approval_login。登录链接过期时绝不能重新安装。

步骤 6:信任并加载连接器

  1. 如果当前 Agent 要求信任本地连接器,按其官方界面或命令确认名称为 dingtalk-approval 的连接器。
  2. 如果不能热加载,完整退出并重新启动 Agent,或新建一个确定会重新读取 MCP 配置的会话;只刷新聊天内容通常不够。
  3. 重启后确认能发现 approval_login、approval_list_todos 等钉钉审批工具。当前版本应发现 13 个工具。
  4. 若连接器进程退出、显示 302 或无法启动,先执行步骤 9 的故障排查,不要把连接器改成远程 HTTP MCP。

步骤 7:确认登录并验证两个审批来源

用户完成网页授权后:

  1. 调用 approval_login。工具不会通过其他消息通道自动推送链接;如果响应仍给出 URL,必须把 content.text 中的完整登录 URL 原样写入当前回复。
  2. 登录成功后,按 postInstall.verifyTool 调用一次只读的 approval_list_todos,即 source="all"、空搜索、limit=1。
  3. 检查结果中的 sourceStatus:dingtalk.status 和 xft.status 都必须是 ok。disabled、auth_required、unavailable 或缺少任一来源都不算安装验证完成。
  4. 验证期间只读取最多一条待办,不调用任何写工具。
  5. 成功响应包含 onboarding.firstRun=true 时,把其中的简短示例和安全提示向用户展示一次,不要自动执行示例。

步骤 8:向用户报告结果

最终只需清楚报告:已安装的版本、Skill 与 MCP 已加载、登录是否成功、钉钉 OA 与薪福通是否都通过只读验证。可以给出一次性使用示例。不要向用户倾倒安装 JSON、内部路径、Token、审批引用或诊断细节,除非用户正在排障。

安装阶段不得处理审批,也不得在登录和双来源验证完成前声称“已可使用”。

步骤 9:常见故障排查

按顺序排查,不要跳到重装:

  1. 显示 302 或启动后立即退出:检查连接器是否被错误配置成 {{GATEWAY_URL}} 或其他 HTTP URL。正确配置必须是 type: "stdio",command 为本机 dingtalk-approval-bridge.cmd,args: []。重新复制安装结果中的 mcpConfig。
  2. 路径不存在或 Node 升级后失效:不要引用 Node/NVM 的版本目录。执行安装结果中的 cliPath,或运行 dingtalk-approval print-config --format mcp-json 重新取得稳定配置。
  3. Bridge 仍无法启动:执行 <cliPath> doctor --json。只有所有 checks 都为 ok: true 才继续;把失败检查和错误原文报告给维护者,不要提供 Token 或会话文件。
  4. 提示找不到 npm-cli.js 或 Node 运行时损坏:重新执行步骤 2 中已经过哈希校验的平台引导,让它修复插件私有 Node;不要安装全局 npm。
  5. 路径包含空格:不要手写命令行字符串。把安装器返回的整个 mcpConfig 作为 JSON 对象交给 Agent;在 PowerShell 中执行 CLI 时用调用运算符 & 和独立参数。
  6. 连接器一直未出现:确认已信任本地连接器并完整重启 Agent。不要通过反复重装刷新连接器。
  7. 授权链接过期:MCP 已加载就再次调用 approval_login;否则执行保存的 loginCommand。不要重装。
  8. Linux/macOS 缺少下载或校验命令:必须先具备 curl 或 wget,以及 sha256sum 或 shasum;不能绕过 SHA-256 校验。系统 tar 必须支持 gzip 归档。
  9. 安装长时间无最终 JSON或被宿主终止:先确认工具调用超时不少于 10 分钟,并查看 stderr 中最后一条 [dingtalk-approval] 阶段信息。不要改用内部安装器,也不要并发重试。原进程确认已经退出后,可重新执行同一平台引导;它会识别已经死亡的安装进程、清理残留 staging 并安全续装。若明确提示另一个安装仍在运行,应等待该进程结束。

更新

更新不需要重新下载首次安装器。使用上次安装结果中的 cliPath:

Windows PowerShell:

$dingUpdateJson = & $dingInstall.cliPath update --json
$dingUpdate = $dingUpdateJson | ConvertFrom-Json
$dingUpdate | ConvertTo-Json -Depth 20

Linux / macOS:

<cliPath> update --json

更新会复用已固定的签名清单地址和公钥并保留 OAuth 会话。更新成功后,重新使用返回的 mcpConfig 核对同名连接器,并重新连接 MCP;必要时完整重启 Agent。然后重复步骤 7 的登录确认和双来源只读验证。

卸载

  1. 按当前 Agent 的官方方式删除名称精确为 dingtalk-approval 的 MCP/连接器条目。
  2. 执行安装结果中的 cliPath uninstall --yes --json;Windows PowerShell 可运行:
& $dingInstall.cliPath uninstall --yes --json
  1. 确认返回 uninstalled 或 cleanup_scheduled。后者表示当前 CLI 退出后完成自清理。

卸载默认清除客户端运行时、Skill、安装记录和 OAuth 会话。不要手工递归删除未知目录。

授权页面会展示请求客户端、回调域名、权限范围或设备授权码。必须由用户本人核对并确认,不得替用户自动提交 consent。网关短暂不可用时保留现有登录状态并稍后重试,不要删除会话文件或主动要求用户重新授权。