安装与下载
1 ClawHub CLI
从源直接安装技能的最快方式。
npx clawhub@latest install ima-mcp-cos-upload
2 手动安装
将技能文件夹复制到以下位置之一
~/.openclaw/skills/
{'/skills/'}
优先级:工作区 › 全局 › 内置
3 提示词安装
将此提示词复制到 Openclaw 即可自动安装。
请帮我使用 Clawhub 安装 skill-ima-mcp-cos-upload。如果尚未安装 Clawhub,请先安装(npm i -g clawhub)。
更倾向于下载?
获取包含原生技能文件的ZIP压缩包。
基本信息
ima-mcp-cos-upload
安装指南
- ClawHub CLI
从源直接安装技能的最快方式。
npx clawhub@latest install ima-mcp-cos-upload - 手动安装
将技能文件夹复制到以下位置之一
全局模式
~/.openclaw/skills/
工作区
/skills/
优先级:工作区 > 本地 > 内置 - 提示词安装
将此提示词复制到 OpenClaw 即可自动安装。
请帮我使用 Clawhub 安装 ima-mcp-cos-upload。如果尚未安装 Clawhub,请先安装(npm i -g clawhub)。
更倾向于下载?
获取包含原生技能文件的ZIP压缩包。
下载技能 (.zip)
什么是
本技能介绍 ima-mcp 知识库上传流程:使用 create_media 请求临时 COS 凭证,使用 COS PUT 签名并上传文件,然后通过 add_knowledge 注册。重点说明如何诊断 Markdown、PDF 和 PowerPoint 文件的 403 Forbidden 响应,包括 AccessDenied、SignatureDoesNotMatch 和 InvalidAccessKeyId。
不同于单独的 ima OpenAPI 上传路径,此流程使用 MCP 服务器返回的临时凭证,并要求正确构造 HMAC-SHA1 签名。本指南涵盖签名格式陷阱、网络限制、凭证处理、重复项预防和上传后验证,是可靠执行 ima-mcp 导入的针对性参考,也可作为 Openclaw Skills 的实用补充。
应用场景
通过 ima-mcp 将本地
.md
、
.pdf
.pptx
文件上传到个人或共享 ima 知识库。
诊断 COS
403 Forbidden
响应,包括
SignatureDoesNotMatch
、
AccessDenied
InvalidAccessKeyId
。
验证临时凭证并正确重建请求签名,以恢复失败的上传。
批量上传时避免重复知识条目和不必要的重试提交。
已知确切存储标题(包括标点、空格、下划线和扩展名)时替换现有知识项。
验证文件是否已注册并在导入后成功解析。
工作原理
上传前使用 get_knowledge_list 检查目标知识库,尤其是在批量重试或替换时。对比确切标题,跳过已存在且完全解析的项目。
使用文件名、文件大小、内容类型、扩展名和知识库 ID 调用 create_media。保存返回的媒体 ID、COS key、主机和临时凭证。
验证凭证响应。特别是,本技能指出,含连字符的 SecretId 可能表示临时凭证格式错误;应重新请求凭证,而非尝试用其签名。
使用返回的 secret、token、对象 key、主机和内容类型构造 COS HMAC-SHA1 授权。遵循规范化规则:编码后的 key 路径前加 /,URI 中保留 /,使用 safe='' 编码标头值,包含所有已签名标头,签名 key 使用 .hexdigest(),并保留 HttpString 末尾换行符。
使用 HTTPS curl 并附上 authorization、security-token 和 content-type 标头上传文件。文档所述环境要求通过 --noproxy '*' 直接访问 COS;不要使用 --resolve 或自定义 CDN 域名。
使用返回的媒体 ID 和可选文件夹 ID 调用 add_knowledge。替换时提供 ima 标题匹配机制要求的现有确切标题。
使用 get_knowledge_list 验证结果:确认项目存在、检查 parse_progress=100,并查看知识库或文件夹总数。立即删除临时凭证文件。
配置指南
在可使用 ima-mcp 工具 create_media、add_knowledge 和 get_knowledge_list 的环境中执行此流程。本技能未指定安装软件包的命令;向 agent 提供本地文件路径、knowledge_base_id、可选的 folder_id 和正确的 content_type。
为安全起见,将完整的 create_media → sign → COS PUT → add_knowledge 流程委派给通用 agent,使临时 token 保持在同一上下文中。若无法委派,则运行 Python 脚本获取 MCP 响应、签名请求、上传文件并注册,避免在消息间手动复制凭证。请使用本技能的 build_cos_auth 参考实现,不要重写签名逻辑。
上传命令应使用 HTTPS 及 ima 知识库上传返回或指定的 COS 直连主机。例如,生成 authorization 并根据凭证响应填写占位符后:
curl --noproxy '*' -X PUT -T ./document.md \
-H "Authorization: $auth" \
-H "x-cos-security-token: $token" \
-H "Content-Type: text/markdown" \
"https://$host/$cos_key"
批量操作或重试前,查询知识列表,不要再次提交已存在的项目。将临时凭证视为机密:避免在日志中暴露,也尽可能不要手动复制长 token;上传后删除所有临时凭证文件。
ima 知识库 COS 直传 数据架构与分类体系
此流程在三个 ima-mcp 操作与直接 COS 上传之间传递数据:
阶段 输入 相关输出或检查
create_media file_name、file_size、content_type、file_ext、knowledge_base_id media_id、临时 cos_credential 值(如 SecretId、SecretKey、Token、Key)及 COS 主机
COS PUT 本地文件、COS key、主机、内容类型、已签名标头 HTTP 响应状态;请求失败时检查 XML 响应正文
add_knowledge media_id、可选的 folder_id、配置的重名策略 已注册并待解析的知识项
get_knowledge_list 知识库 ID,以及需要时的列表上限 已有标题、解析状态和知识库或文件夹总数
签名元数据包括小写 HTTP 方法、http_uri、排序后的已签名标头、key_time、q-header-list 和 HMAC-SHA1 签名。URI 为 / 加编码后的 COS key,并保留 /。标头值使用 safe='' 进行 URL 编码;此流程规定的已签名标头集合为 content-type;host;x-cos-security-token。规范化的 HttpString 必须以换行符结尾,签名 key 必须是 .hexdigest() 得到的十六进制 HMAC-SHA1 值。
ima 的重复项处理取决于标题:匹配必须完全一致,空格、下划线、文件扩展名和大小写都可能影响结果。按文档中的 SAVE 行为,重复标题可能会添加时间戳后缀。使用 REPLACE 时,先获取实际存储的标题,并逐字符传入。ima-mcp 不提供删除、移动、重新标记或创建文件夹操作;误加或过时条目需要在 ima 界面中手动处理。
高级特性
HMAC-SHA1 故障排查:
说明末尾换行符要求、URI 与标头的编码规则、前导斜线行为、十六进制签名 key 和完整已签名标头列表,帮助定位
SignatureDoesNotMatch
故障。
凭证验证:
指出返回的
SecretId
含连字符是已报告的不良凭证信号;应使用
create_media
重新获取凭证,不要强行尝试签名。
Agent 委派:
建议在同一 agent 上下文中完成获取凭证、签名、上传和注册,以减少复制 token 时出错。无法使用 agent 时,文档建议改用单个 Python 脚本。
批量幂等性:
重试前调用
get_knowledge_list
。跳过
parse_progress=100
的现有项目;仍在解析的条目应等待或通知用户,而不是重复提交。
精确替换:
REPLACE
前必须获取现有完整标题,避免标点、下划线、空格或
.md
不同而意外新增条目。
适应网络环境的上传:
使用 HTTPS、COS 直连主机和
curl --noproxy '*'
;文档所述沙箱的后台 shell 可能无法使用 DNS,而
--resolve
、HTTP 转发和自定义 CDN 域名可能导致失败。
上传后验证与清理:
get_knowledge_list
确认知识项和解析进度,检查实时总数而非静态计数,并删除包含凭证的临时文件。
name: ima-mcp-cos-upload
description: "WorkBuddy ima-mcp 知识库入库的 COS 直传方案:create_media → HMAC-SHA1 签名 → curl PUT → add_knowledge。含两处致命签名坑(尾随\n、header 值 safe='')与'委托子代理避免 token 损坏'稳路。触发:ima 推库/上传 md/pdf/ppt 到知识库报 COS 403。"
version: 1.0.0
homepage: "https://ima.qq.com"
display_name: "ima 知识库 COS 直传"
description_zh: "ima-mcp 入库的 COS 签名上传方案与避坑清单"
description_en: "COS direct-upload recipe for ima-mcp knowledge-base ingestion"
agent_created: true
visibility: "user"
author: 宗宗(戴宗宗)
triggers: [ima 上传报错, COS 403, 知识库入库, ima 推库, ima-mcp 上传, 上传到 ima 知识库]
tags: [ima, 知识库, COS, 上传, 签名, 避坑, mcp]
ima-mcp 知识库 COS 直传方案
本 skill 解决 WorkBuddy 的 mcp__ima-mcp__create_media → 手动 COS PUT → add_knowledge 入库链路中反复出现的 COS 403 问题。与 ima-skills(OpenAPI ima_api.cjs)是不同路径——本链路用 MCP 服务器下发的临时 COS 凭证,需自己算 HMAC-SHA1 签名并 PUT。
何时用
用 ima-mcp 把本地 .md / .pdf / .pptx 等推入「你的 ima 知识库(共享库或个人库均可)」。
现象:curl 返 403 Forbidden(XML 报错 AccessDenied / SignatureDoesNotMatch)。
链路全景
create_media(file_name, file_size, content_type, file_ext, knowledge_base_id) → 返回 cos_credential(含 SecretId/SecretKey/Token/Key、桶 host)。
用凭证把文件 PUT 到 COS(自己算签名)。
add_knowledge(media_id, folder_id?) 入库(media_id 来自 create_media)。
重名策略用 SAVE,新版本带 v1.x 不撞名。ima-mcp 无法删除/移动/改标签/建夹——旧版清理须用户在 ima 界面手动。
⛔ 两处致命签名坑(缺一则 403)
来自 2026-08-13 实战,已验证:
坑 A — HttpString 必须尾随 \n
HttpString = "{method}\n{http_uri}\n\n{http_headers}\n" # 末项后还要一个 \n
缺最后的 \n → COS 403。这是最容易漏的一点。
坑 B — Header 值必须用 safe='' 编码(/→%2F)
http_uri(对象 Key 路径):urllib.parse.quote(key, safe='/') —— 保留 /。
http_headers 的每个 value:urllib.parse.quote(v, safe='') —— 编码 /。 二者编码规则不同,别混。
坑 C — cos_key 不含前导 /,签名 http_uri 必须手动补 /
create_media 返回的 cos_key 不带前导 /(如 5/fGpy...md)。
但 COS 服务端验签的 FormatString 里 http_uri 带前导 /(如 /5/fGpy...md)。
若签名用 5/fGpy...md(无 /)→ COS 返 403 SignatureDoesNotMatch,响应体 XML 可定位根因。
✅ 修复:http_uri = "/" + urllib.parse.quote(cos_key, safe='/'),即先补 / 再编码。
来自 2026-08-27 实战:4 本投资书首传全 403,抓响应体定位根因修复后重传全 200。
签名算法(Python 参考实现)
import hmac, hashlib, time, urllib.parse
def build_cos_auth(secret_id, secret_key, token, method, cos_key, content_type,
host="ima-share-kb-1258344701.cos.ap-shanghai.myqcloud.com"):
method = method.lower()
http_uri = "/" + urllib.parse.quote(cos_key, safe='/') # 坑C: cos_key 无前导/,签名必须补;坑B: 保留 '/'
headers = {
"content-type": content_type,
"host": host,
"x-cos-security-token": token,
}
http_headers = "&".join( # 坑B: value safe=''
f"{k}={urllib.parse.quote(v, safe='')}" for k, v in sorted(headers.items())
)
now = int(time.time()); expire = 600
key_time = f"{now};{now+expire}"
sign_key = hmac.new(secret_key.encode(), key_time.encode(), hashlib.sha1).hexdigest()
http_string = f"{method}\n{http_uri}\n\n{http_headers}\n" # 坑A: 尾随 \n
string_to_sign = f"sha1\n{key_time}\n{hashlib.sha1(http_string.encode()).hexdigest()}\n"
signature = hmac.new(sign_key.encode(), string_to_sign.encode(), hashlib.sha1).hexdigest()
header_list = ";".join(sorted(headers.keys()))
auth = (f"q-sign-algorithm=sha1&q-ak={secret_id}&q-sign-time={key_time}"
f"&q-key-time={key_time}&q-header-list={header_list}"
f"&q-url-param-list=&q-signature={signature}")
return auth, headers
# 用法:
# auth, headers = build_cos_auth(cred["SecretId"], cred["SecretKey"], cred["Token"],
# "put", cred["Key"], "text/markdown")
# curl --noproxy '*' -X PUT -T file \
# -H "Authorization: $auth" \
# -H "x-cos-security-token: $token" \
# -H "Content-Type: text/markdown" \
# "https://{host}/{cos_key}"
⛔ 网络约束(沙箱,2026-08-13 厘清)
后台 Bash 无 DNS(rc=6)→ 上传必须前台执行。
前台 --resolve 钉死 IP 反不可达(rc=60)→ 不能用 --resolve。
用 curl --noproxy '*' -X PUT -T file(带鉴权头,无代理、无 --resolve),curl 自走系统 DNS。
HTTP 正向转发对长签名头硬性 502 → 只用 HTTPS。
域名用直达 ima-share-kb-1258344701.cos.ap-shanghai.myqcloud.com,非 custom_domain CDN(会被 Lego Server 拒 403)。
✅ 稳路:整链委托 Agent 子代理(强烈推荐)
主会话手动把 create_media 返回的 token 抄进凭证 JSON 极易损坏(长字符串复制错位)→ 必 403。 已验证解法:把 create_media → 签名 → COS PUT → add_knowledge 整套交给一个 general-purpose Agent 子代理在它自己的上下文里跑,主会话不手动传 token。子代理首试即 HTTP 200。
调用 Agent 时把文件路径、folder_id、knowledge_base_id、content_type 写清楚,让它独立读 create_media 响应、算签名、上传、注册,最后回报 media_id 与 HTTP 状态。
⚠️ 实测:子代理偶发不可用(报 Tool Agent not found)。此时退回主会话自跑脚本同样可行——把整段 Python(含 build_cos_auth)写进一个 .py 文件,主会话直接 python script.py 跑 create_media→签名→curl PUT→add_knowledge,token 不手动跨消息复制即不损坏。已验证 2026-08-27 用此路 4 本投资书全 200。
⛔ 坑 D — 重试上传必须先查重,否则产生大量重复条目(2026-08-27 实战教训)
现象:同一批书因 COS 403 修正后重试,每轮都执行了完整 create_media→PUT→add_knowledge,导致 4 本书各入 3 份(12 条),其中 8 条为带时间戳后缀的垃圾副本。
根因:脚本缺少「幂等/去重」检查——重试前未查 KB 是否已有同名标题。
ima 的重名行为:add_knowledge 提交同名标题时,ima 自动追加 _YYMMDDHHmmss 后缀(防覆盖机制)。这本身合理,但我们的场景不应触发。
✅ 强制规则:批量上传前必须先调 get_knowledge_list,逐本核对目标标题是否已存在:
已存在且 parse_progress=100 → 跳过,不入
已存在但 parse=0 或 media_state=1 → 等或通知用户,不重复提交
不存在 → 正常走 create_media→PUT→add_knowledge
批量脚本的伪代码逻辑:
existing = get_knowledge_list(kb_id, limit=50)
existing_titles = {item["title"] for item in existing["knowledge_list"]}
for book in books:
if book.title in existing_titles:
print(f"⚠️ 跳过(已存在): {book.title}")
continue
# 正常上传流程...
偶发坏 media_id(invalid media_type 220001)
create_media 偶发下发坏 media_id,add_knowledge 必报且重试无效 → 重 create_media 换 fresh media_id + COS 重传一次即解。
验证清单(每次上传后)
get_knowledge_list 实时核对库 knowledge_total_size 与目标夹 total_size(库项/每夹精确计数以 ima 实时为准,文档写死数字勿信)。
确认 parse_progress=100、目标文件在列。
临时凭证文件(含 token)上传后立即删,避免密钥残留。
⛔ 坑 E — REPLACE 必须精确匹配库内旧项【完整标题】(含下划线/.md 后缀)
现象(2026-09-02 实战):库内旧项标题为「区别方法论方法卡手册_v1.3.md」(带下划线+.md),而 create_media 用了「区别方法论方法卡手册 v1.3」(无下划线、无后缀)→ DUPLICATE_NAME_STRATEGY_REPLACE 按标题精确匹配未命中 → 变成新增副本,KB 总数 +1(从 77 变 78)。
根因:ima 的重名匹配是【精确字符串相等】,不忽略空格/下划线/.md/大小写差异。推测旧标题必然踩坑。
✅ 强制规则:REPLACE 覆盖前,先 get_knowledge_list 取目标项真实 title 全文,create_media 的 file_name 必须与之【逐字符一致】(含 、.md、空格)。不要凭记忆/推测旧标题。
若已误建副本:ima OpenAPI/MCP 无 delete 接口 → 只能用户在 ima 界面手动删多余项;正确的那一份用精确标题二次 create_media+add_knowledge(REPLACE) 即可覆盖,库计数回正。
⛔ 坑 F — 偶发坏凭证(InvalidAccessKeyId)需重取 create_media(2026-09-04 / 08-31 实战)
现象:某次 create_media 返回的 secret_id 含连字符 -(形如 AKID-051xna3... 或中段 - 如 AKID...x_M_-qizG... / AKIDG-uqBd3),用其算签名 PUT → COS 返 403 InvalidAccessKeyId("The Access Key Id you provided does not exist in our records")。
根因:create_media 偶发下发损坏的临时密钥——与「偶发坏 media_id」同源,皆 MCP 服务端偶发异常,非签名算法错。
✅ 强制规则(实测强化版):每次 create_media 后,先肉眼核对 secret_id:
正常凭据:AKID 紧跟随机字符、全串只含字母数字、可含 _、绝不含 -(形如 AKIDt7Oelr... / AKIDluyrGpLLVE6...)。
坏凭据:含任意 - 即坏——不止 AKID 后紧跟 -,中段 - 也实测 100% 触发 403(连续 11 次带 - 的凭据 PUT 全 403)。_ 合法,仅 - 是坏信号。
若含 - → 直接重调 create_media 换 fresh 凭证,不要硬凑签名。
⚠️ 重试次数可能很多:单个文件曾连续 8~12 次返回带 - 的坏凭据才出现干净凭据(非「重取一次即恢复」)。循环重调直到拿到无 - 的全字母数字凭据为止,拿到即用,绝不硬编码坏签名。
与坑 E 区分:坑 E 是「标题匹配错」→ 副本;坑 F 是「凭证本身坏」→ 403。二者独立,可同时发生。
⛔ 坑 G — sign_key 必须用 .hexdigest()(十六进制字符串),误用 .digest() 原始字节必 403(2026-09-10 实战)
现象:上传脚本自写签名逻辑,sign_key = hmac.new(secret_key, key_time, sha1).digest()(原始字节)再 .encode() 当下一轮 HMAC 的 key → COS 返 403 SignatureDoesNotMatch。secret_id 无 -(坑 F 已排除),http_string 与服务器 StringToSign 完全一致,唯签名值错。
根因:COS 的 sign_key 约定是 HMAC-SHA1 的十六进制摘要字符串(hexdigest()),不是原始字节(digest())。用 digest() 字节当 key 重算的 signature 与服务器期望不符。
✅ 强制规则:
sign_key = hmac.new(secret_key.encode(), key_time.encode(), hashlib.sha1).hexdigest()(.hexdigest(),非 .digest())。
签名头列表(q-header-list)必须含实际参与签名的全部 header,本库稳定集 = content-type;host;x-cos-security-token(按字母序排序)。少签/多签任一即 403。
今后补卡上传,直接逐字复制本 skill 的 build_cos_auth 模板(line 56-75),不要凭记忆自写签名函数——模板已含 .hexdigest() + 三签名头,跑通多次。已验证参考:/tmp/up_card_p1.py、/tmp/up_card_p2.py(同构,仅换凭据/cos_key/file)。
ima 知识库仪表板生成器
字帖手写练习助手