mcpField
W
wecom

wecom

github.com/acedatacloud生产力1777 次安装今天更新
代码仓库

关于 wecom

通过 curl 和 jq 调用 WeCom 自建应用服务端 API 的技能,面向需要管理企业通讯录、消息、文档、日程和会议的工作流。它提供令牌处理与操作示例,并要求发送消息或创建日程、会议前取得明确确认。

主要功能

  1. 01获取并缓存访问令牌
  2. 02读取部门与成员资料
  3. 03发送应用消息和群聊消息
  4. 04创建及读取 WeDoc 文档
  5. 05管理日程与会议

适用场景

  1. 01查找成员并解析 userid
  2. 02向指定同事发送通知
  3. 03创建项目文档或智能表格
  4. 04安排日程或会议

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/acedatacloud/skills --skill wecom

安装后在 Claude Code 中输入/wecom确认已加载。

详细介绍

我们使用 curl + jq 作为自建应用来调用企业微信服务端 API (https://qyapi.weixin.qq.com)。

设置: 请参阅企业微信身份验证,了解如何创建自建应用、 收集 CorpID / Secret / AgentId,并授予通讯录 / 文档 / 日历 / 会议 权限。此技能会从环境中读取 WECOM_CORP_ID、WECOM_CORP_SECRET 和 WECOM_AGENT_ID;在 AceDataCloud 上,这些变量由企业微信连接器自动注入。

企业微信采用两步令牌流程(形式与微信公众号 API 相同):

  1. 使用 CorpID + Secret 换取 access_token(有效期 7200s)。
  2. 在其他每次调用中,将此 access_token 作为查询字符串参数传入。

绝不要记录或回显 $WECOM_CORP_SECRET——请将其视为密码。

响应以 JSON 格式返回,且 HTTP 状态码为 200;errcode == 0 表示成功。若 errcode 非零, 请将原始 errmsg 原样显示给用户(参见设置文档中的错误表)。

操作示例

步骤 0 — 获取 access_token(首先执行,并缓存结果)

以下每个操作示例都假定 $AT 中保存了此步骤获取的有效令牌。

# Fail loudly if credentials are missing/blank. WECOM_AGENT_ID must be a plain
# integer because message/meeting recipes pass it to jq via --argjson (numeric JSON).
: "${WECOM_CORP_ID:?WECOM_CORP_ID not set}" "${WECOM_CORP_SECRET:?WECOM_CORP_SECRET not set}"
case "${WECOM_AGENT_ID:?WECOM_AGENT_ID not set}" in *[!0-9]*|"") echo "WECOM_AGENT_ID must be an integer" >&2; exit 1;; esac

# Cache to $TMPDIR so subsequent calls in the same session reuse it (WeCom
# rate-limits gettoken). Refresh 5 minutes early to avoid edge-of-window failures.
TOKEN_CACHE="${TMPDIR:-/tmp}/wecom-token-${WECOM_CORP_ID}-${WECOM_AGENT_ID}.json"
NOW=$(date +%s)
if [ -f "$TOKEN_CACHE" ] && [ "$(jq -r '.exp_at // 0' "$TOKEN_CACHE")" -gt "$((NOW + 300))" ]; then
  AT=$(jq -r '.access_token' "$TOKEN_CACHE")
else
  RESP=$(curl -sS "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${WECOM_CORP_ID}&corpsecret=${WECOM_CORP_SECRET}")
  AT=$(echo "$RESP" | jq -r 'if .errcode == 0 then .access_token else empty end')
  if [ -z "$AT" ]; then
    echo "Failed to fetch access_token: $RESP" >&2
    exit 1
  fi
  EXPIRES=$(echo "$RESP" | jq -r '.expires_in // 7200')
  echo "$RESP" | jq --argjson now "$NOW" --argjson ttl "$EXPIRES" \
    '{access_token, exp_at: ($now + $ttl)}' > "$TOKEN_CACHE"
  chmod 600 "$TOKEN_CACHE"
fi

使用一个小型辅助函数可以让操作示例更简洁——附加令牌并执行 GET 请求,若 errcode 非零则报错:

wc_get()  { curl -sS "https://qyapi.weixin.qq.com/cgi-bin/$1&access_token=${AT}" \
              | jq 'if .errcode == 0 then . else error("WeCom \(.errcode): \(.errmsg)") end'; }
wc_post() { curl -sS -X POST "https://qyapi.weixin.qq.com/cgi-bin/$1?access_token=${AT}" \
              -H 'Content-Type: application/json' -d "$2" \
              | jq 'if .errcode == 0 then . else error("WeCom \(.errcode): \(.errmsg)") end'; }
通讯录 Contacts(读取)

读取真实姓名 / 手机号需要应用具有通讯录读取权限;否则姓名 会被屏蔽。应用可见范围外的成员会返回 errcode 60011 / 81013。

列出部门树(根部门 id 为 1):

wc_get "department/list?id=1" | jq '[.department[] | {id, name, parentid}]'

首选枚举方式——user/list_id(游标)。 这是列出成员的稳健方式: 仅持有自建应用自身 Secret 时也能使用。user/simplelist / user/list 在应用的可见范围内仍然 可用,但企业微信一直在收紧这些接口的限制(2022‑08‑15 的变更禁止 新添加的通讯录同步 IP 调用这些接口),因此应优先使用 user/list_id,只有在需要一次性获取姓名时才回退到 simplelist。

wc_post "user/list_id" '{"cursor":"","limit":10000}' \
  | jq '{next_cursor, userids: [.dept_user[] | .userid] | unique}'

获取某位成员的完整资料——可用于将姓名 → userid,以便发送消息:

wc_get "user/get?userid=USERID" \
  | jq '{userid, name, department, position, mobile, email, status}'

一次调用列出某部门的成员(便捷方式;需要拥有该部门的通讯录查看权限—— 若返回 60011,请改用上文的 user/list_id + user/get):

wc_get "user/simplelist?department_id=1&fetch_child=1" \
  | jq '[.userlist[] | {userid, name, department}]'

按姓名搜索——稳健方式(枚举 id,然后读取每份资料并筛选):

for uid in $(wc_post "user/list_id" '{"cursor":"","limit":10000}' | jq -r '.dept_user[].userid' | sort -u); do
  wc_get "user/get?userid=${uid}" | jq -c '{userid, name}'
done | jq -s --arg q "张三" '[.[] | select(.name | contains($q))]'

快捷方式:当应用可以使用 simplelist 时:wc_get "user/simplelist?department_id=1&fetch_child=1" | jq --arg q "张三" '[.userlist[] | select(.name | contains($q)) | {userid, name}]'。

应用消息 App messages(发送)— 受控操作

message/send 会从你的应用向成员推送通知。必须提供 agentid,其值来自 $WECOM_AGENT_ID。touser 是以 | 连接的 userid 列表(使用 @all 表示范围内的所有人); toparty / totag 用于指定部门 / 标签。

发送消息会将内容推送给真实用户。运行 message/send / appchat/send 之前,务必向用户展示确切的收件人和内容,并取得明确确认,即使指令说 “直接发送”也不例外。

向一位或多位成员发送文本消息:

wc_post "message/send" "$(jq -nc --arg to "USERID1|USERID2" --argjson agent "${WECOM_AGENT_ID}" \
  --arg content "构建已通过,请查看。" \
  '{touser:$to, msgtype:"text", agentid:$agent, text:{content:$content}, safe:0}')" \
  | jq '{msgid, invaliduser}'

发送 Markdown 卡片(格式更丰富,仅限成员):

wc_post "message/send" "$(jq -nc --arg to "@all" --argjson agent "${WECOM_AGENT_ID}" \
  --arg md "**发布通知**\n>版本:v1.2.0\n>状态:<font color=\"info\">成功</font>" \
  '{touser:$to, msgtype:"markdown", agentid:$agent, markdown:{content:$md}}')" \
  | jq '{msgid}'

发送可点击的文本卡片:

wc_post "message/send" "$(jq -nc --arg to "USERID1" --argjson agent "${WECOM_AGENT_ID}" \
  '{touser:$to, msgtype:"textcard", agentid:$agent,
    textcard:{title:"周报已生成", description:"点击查看本周汇总", url:"https://example.com/report", btntxt:"详情"}}')" \
  | jq '{msgid}'
应用群聊 App group chat

创建一个归应用所有的群聊,然后向其中推送消息。chatid 是你选择的自定义 id(之后可重复使用)。

# Create (owner + members are userids). Omit chatid to let WeCom assign one.
wc_post "appchat/create" '{"name":"项目组","owner":"USERID1","userlist":["USERID1","USERID2","USERID3"],"chatid":"proj_alpha"}' \
  | jq '{chatid}'

# Send into it (same GATED confirmation rule as app messages).
wc_post "appchat/send" '{"chatid":"proj_alpha","msgtype":"text","text":{"content":"今晚 8 点线上同步。"}}' \
  | jq '{errcode, errmsg}'

# Inspect a group the app created.
wc_get "appchat/get?chatid=proj_alpha" | jq '.chat_info | {name, owner, userlist}'
企业微信文档 WeDoc(文档与智能表格)

需要应用拥有 文档 (WeDoc) 权限。doc_type:3 = 文档,4 = 表格, 10 = 智能表格。

创建文档并获取编辑 URL:

wc_post "wedoc/create_doc" "$(jq -nc --arg name "项目周报 2026-07" \
  '{doc_type:3, doc_name:$name}')" \
  | jq '{docid, url}'

获取现有文档的可分享链接:

wc_post "wedoc/doc_share" '{"docid":"DOCID"}' | jq '{share_url: .share_url}'

读取文档的结构化内容。WeCom 返回一个 document 对象(以 document_id 而非 doc_id 为键),其正文是由类型化区块组成的树,不是 Markdown — 请先检查实际结构,再依赖内部字段名称:

wc_post "wedoc/document/get" '{"docid":"DOCID"}' \
  | jq '{document_id: .document.document_id, top_level_keys: (.document | keys)}'

智能表格的子表、字段和记录使用 wedoc/smartsheet/* 端点 (get_sheet、get_fields、get_records、add_records 等)— 使用相同的 wc_post 模式,以 docid + sheet_id 为键。用户要求读取或写入智能表格的行时,请使用这些端点。

日程 Schedule(日程)

需要应用拥有 日历/日程 权限。时间是 epoch 秒;使用 GNU date 转换:

START=$(date -d "2026-07-10 15:00" +%s); END=$(date -d "2026-07-10 16:00" +%s)

创建日程(组织者和参会者均为 userid):

wc_post "oa/schedule/add" "$(jq -nc --arg org "USERID1" --argjson s "$START" --argjson e "$END" \
  '{schedule:{organizer:$org, start_time:$s, end_time:$e, summary:"项目评审",
    description:"评审 v1.2 需求", location:"会议室 A",
    attendees:[{userid:"USERID2"},{userid:"USERID3"}],
    reminders:{is_remind:1, remind_before_event_secs:900}}}')" \
  | jq '{schedule_id}'

按 ID 读取日程并取消日程:

wc_post "oa/schedule/get" '{"schedule_id_list":["SCHEDULE_ID"]}' \
  | jq '[.schedule_list[] | {schedule_id, summary, start_time, end_time, organizer}]'

wc_post "oa/schedule/del" '{"schedule_id":"SCHEDULE_ID"}' | jq '{errcode, errmsg}'

若要列出某位成员即将参加的日程,需要其日历 ID(cal_id)以及 oa/schedule/get_by_calendar — 请先通过 oa/calendar/* 端点创建或查询日历。

会议 Meeting(会议)

需要应用拥有 会议 权限。meeting_start 是 epoch 秒,meeting_duration 是秒。

创建已安排的会议:

wc_post "meeting/create" "$(jq -nc --arg admin "USERID1" --argjson start "$(date -d '2026-07-11 10:00' +%s)" \
  '{admin_userid:$admin, title:"周例会", meeting_start:$start, meeting_duration:3600,
    description:"同步本周进展", invitees:{userid:["USERID2","USERID3"]}}')" \
  | jq '{meetingid}'

列出某位成员的会议、读取详情并取消会议(get_user_meetingid 是一个带游标请求体的 POST, 与 WeCom 的其他 get_user_*_id 列表端点相同):

wc_post "meeting/get_user_meetingid" '{"userid":"USERID1","cursor":"","limit":100}' \
  | jq '{meetingid_list, next_cursor}'

wc_post "meeting/get_info" '{"meetingid":"MEETINGID"}' \
  | jq '.meeting_info | {title, meeting_start, meeting_duration, state}'

wc_post "meeting/cancel" '{"meetingid":"MEETINGID"}' | jq '{errcode, errmsg}'

安全规则

  • 绝不输出 $WECOM_CORP_SECRET。 它等同于完整的应用访问权限。
  • 执行任何对外操作前都要确认 — message/send、appchat/send、oa/schedule/add 和 meeting/create 都会通知真实同事。请展示确切的收件人/参会者和内容,获得明确批准,然后再调用。绝不能从含糊措辞中推断用户同意。
  • 消息、日程和会议操作使用的是 userids,而非显示名称 — 请先使用联系人查询方式将姓名解析为 userid;如果姓名有歧义,还要确认具体对象。
  • 遇到 errcode 48002(API 禁止)或 60011/301002(无权限)时,表示应用缺少某项权限,或目标位于其可见范围之外 — 请告知用户需要授予哪项能力,不要盲目重试。

此处不支持的功能

  • 读取收到的聊天记录(会话内容存档 / msgaudit)— 这是单独收费的功能,需要专用 Secret、RSA 密钥 和原生 WeCom Finance SDK,无法在此沙盒中运行。此技能可以发送消息,但无法读取成员的私人对话。
  • 通用待办 CRUD — WeCom 开放 API 未向自建应用提供此功能;请改用 日程创建有时间限制的提醒。

评论

支持 Markdown