feat: 初始化黄小瓜AI助手记忆仓库

- 核心配置: IDENTITY, USER, SOUL, AGENTS, TOOLS, HEARTBEAT, MEMORY
- memory/: 每日总结和临时记录
- skills/: 所有已安装技能
- notes/: 语音配置笔记
This commit is contained in:
root
2026-04-04 02:42:48 +08:00
parent 2d24fe9b50
commit 691b8cdd0c
115 changed files with 18198 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
{
"version": 1,
"registry": "https://clawhub.ai",
"slug": "tencent-cos-skill",
"installedVersion": "1.0.6",
"installedAt": 1774109349847
}

View File

@@ -0,0 +1,357 @@
---
name: tencent-cloud-cos
description: >
腾讯云对象存储(COS)和数据万象(CI)集成技能。当用户需要上传、下载、管理云存储文件,
或需要进行图片处理(质量评估、超分辨率、抠图、二维码识别、水印)、智能图片搜索、
文档转PDF、视频智能封面生成等操作时使用此技能。
metadata:
{
"openclaw":
{
"emoji": "☁️",
"requires": {},
"install":
[
{
"id": "node-mcporter",
"kind": "node",
"package": "mcporter",
"bins": ["mcporter"],
"label": "Install mcporter (MCP CLI)",
},
{
"id": "node-cos-mcp",
"kind": "node",
"package": "cos-mcp",
"bins": ["cos-mcp"],
"label": "Install cos-mcp (COS MCP Server)",
},
{
"id": "node-cos-sdk",
"kind": "node",
"package": "cos-nodejs-sdk-v5",
"label": "Install COS Node.js SDK",
},
],
},
}
---
# 腾讯云 COS 技能
通过 cos-mcp MCP 工具 + Node.js SDK 脚本 + COSCMD 管理腾讯云对象存储和数据万象。
## 首次使用 — 自动设置
当用户首次要求操作 COS 时,按以下流程操作:
### 步骤 1检查当前状态
```bash
{baseDir}/scripts/setup.sh --check-only
```
如果输出显示一切 OKcos-mcp 已安装、凭证已配置),跳到「执行策略」。
### 步骤 2如果未配置引导用户提供凭证
告诉用户:
> 我需要你的腾讯云凭证来连接 COS 存储服务。请提供:
> 1. **SecretId** — 腾讯云 API 密钥 ID
> 2. **SecretKey** — 腾讯云 API 密钥 Key
> 3. **Region** — 存储桶区域(如 ap-guangzhou
> 4. **Bucket** — 存储桶名称(格式 name-appid如 mybucket-1250000000
> 5. **DatasetName**(可选) — 数据万象数据集名称(仅智能搜索需要)
> 6. **Domain**(可选) — 自定义域名,用于替换默认的 COS 访问域名(如 cdn.example.com
> 7. **ServiceDomain**(可选) — 自定义服务域名,用于自定义 COS API 请求域名
> 8. **Protocol**(可选) — 协议,如 https 或 http
>
> 你可以在 [腾讯云控制台 > 访问管理 > API密钥管理](https://console.cloud.tencent.com/cam/capi) 获取密钥,
> 在 [COS 控制台](https://console.cloud.tencent.com/cos/bucket) 查看存储桶信息。
### 步骤 3用户提供凭证后运行自动设置
```bash
{baseDir}/scripts/setup.sh --secret-id "<SecretId>" --secret-key "<SecretKey>" --region "<Region>" --bucket "<Bucket>"
```
如有 DatasetName
```bash
{baseDir}/scripts/setup.sh --secret-id "<SecretId>" --secret-key "<SecretKey>" --region "<Region>" --bucket "<Bucket>" --dataset "<DatasetName>"
```
如需自定义域名(可选参数按需添加):
```bash
{baseDir}/scripts/setup.sh --secret-id "<SecretId>" --secret-key "<SecretKey>" --region "<Region>" --bucket "<Bucket>" --domain "<Domain>" --service-domain "<ServiceDomain>" --protocol "<Protocol>"
```
脚本会自动:
- 检查并安装 mcporterMCP 命令行工具)
- 检查并安装 cos-mcp 和 cos-nodejs-sdk-v5
- 创建/更新 `~/.mcporter/mcporter.json`,写入 cos-mcp 服务器配置
- 将凭证写入 shell 配置文件(`~/.zshrc``~/.bashrc`),重启后仍可用
- 配置 coscmd如有 Python 环境)
- 验证 COS 连接
设置完成后即可开始使用。
## 执行策略
三种方式按优先级降级,确保操作始终可完成:
1. **方式一cos-mcp MCP 工具**(优先) — 功能最全,支持存储 + 图片处理 + 智能搜索 + 文档媒体处理
2. **方式二Node.js SDK 脚本** — 通过 `scripts/cos_node.mjs` 执行存储操作
3. **方式三COSCMD 命令行** — 通过 shell 命令执行存储操作
```
mcporter + cos-mcp 可用which mcporter && 配置存在)
├─ 是 → 使用方式一 mcporter 调用(全部功能)
└─ 否 → cos-mcp MCP 工具可直接调用getCosConfig 返回结果)
├─ 是 → 使用方式一直接调用(全部功能)
└─ 否 → Node.js + cos-nodejs-sdk-v5 可用?
├─ 是 → 使用方式二(存储操作)
└─ 否 → coscmd 可用which coscmd
├─ 是 → 使用方式三(存储操作)
└─ 否 → 运行 setup.sh 安装
```
**判断方式一(mcporter)**`which mcporter``cat ~/.mcporter/mcporter.json | grep cos-mcp` 有输出。
**判断方式一(直接)**:尝试调用 `getCosConfig` MCP 工具,若返回结果则可用。
**判断方式二**`node -e "require('cos-nodejs-sdk-v5')"` 成功则可用。
**判断方式三**`which coscmd` 有输出则可用。
---
## 方式一cos-mcp MCP 工具(优先)
> GitHub: https://github.com/Tencent/cos-mcp
MCP 配置模板见 `references/config_template.json`
### 调用格式
通过 mcporter 命令行调用 cos-mcp MCP 工具:
```
mcporter call cos-mcp.<tool_name> --config ~/.mcporter/mcporter.json --output json [--args '<JSON>']
```
列出所有可用工具:
```
mcporter list cos-mcp --config ~/.mcporter/mcporter.json --schema
```
**判断 mcporter 是否可用**`which mcporter``~/.mcporter/mcporter.json` 包含 cos-mcp 配置。
如果 mcporter 不可用,可回退到客户端直接调用 MCP 工具(`getCosConfig` 等)。
### 工具总览
| 类别 | 说明 |
|------|------|
| 存储操作 | 上传、下载、列出、获取签名URL |
| 图片处理 | 质量评估、超分辨率、抠图、二维码识别、水印 |
| 智能搜索 | 以图搜图、文本搜图(需预建数据集) |
| 文档媒体 | 文档转PDF、视频智能封面异步任务 |
### 常用操作
> 以下示例同时展示两种调用格式。mcporter 格式省略公共前缀 `mcporter call cos-mcp.` 和 `--config ~/.mcporter/mcporter.json --output json`。
> 完整 mcporter 命令:`mcporter call cos-mcp.<tool> --config ~/.mcporter/mcporter.json --output json --args '<JSON>'`
#### 存储
```bash
# 上传本地文件mcporter 格式)
mcporter call cos-mcp.putObject --config ~/.mcporter/mcporter.json --output json --args '{"filePath":"/path/to/file.jpg","targetDir":"images"}'
# 上传本地文件(客户端直接调用格式)
putObject filePath="/path/to/file.jpg" targetDir="images"
# 上传字符串内容
putString content="hello world" fileName="test.txt" targetDir="docs"
# 通过 URL 上传
putObjectSourceUrl sourceUrl="https://example.com/image.png" targetDir="images"
# 列出文件
getBucket Prefix="images/"
# 下载文件
getObject objectKey="images/photo.jpg"
# 获取签名下载链接
getObjectUrl objectKey="images/photo.jpg"
```
#### 图片处理
```
# 图片质量评估
assessQuality objectKey="images/photo.jpg"
# AI 超分辨率
aiSuperResolution objectKey="images/photo.jpg"
# AI 智能抠图
aiPicMatting objectKey="images/photo.jpg"
# 二维码识别
aiQrcode objectKey="images/qrcode.jpg"
# 添加文字水印
waterMarkFont objectKey="images/photo.jpg" text="版权所有"
# 获取图片元信息
imageInfo objectKey="images/photo.jpg"
```
#### 智能搜索(需预建数据集)
```
# 以图搜图
imageSearchPic uri="https://example.com/query.jpg"
# 文本搜图
imageSearchText text="蓝天白云"
```
#### 文档与媒体处理(异步任务)
```
# 文档转 PDF
createDocToPdfJob objectKey="docs/report.docx"
# 查询任务结果
describeDocProcessJob jobId="<jobId>"
# 视频智能封面
createMediaSmartCoverJob objectKey="videos/demo.mp4"
# 查询任务结果
describeMediaJob jobId="<jobId>"
```
工具详细参数定义见 `references/api_reference.md`
---
## 方式二Node.js SDK 脚本
> 官方文档: https://www.tencentcloud.com/zh/document/product/436/8629
当 cos-mcp 不可用时,通过 `scripts/cos_node.mjs` 执行存储操作。凭证从环境变量读取。
支持的环境变量:
- `TENCENT_COS_SECRET_ID` / `TENCENT_COS_SECRET_KEY` / `TENCENT_COS_REGION` / `TENCENT_COS_BUCKET`(必需)
- `TENCENT_COS_DOMAIN` / `TENCENT_COS_SERVICE_DOMAIN` / `TENCENT_COS_PROTOCOL`(可选,自定义域名)
### 常用命令
> 以下省略 `node {baseDir}/scripts/cos_node.mjs` 前缀。完整格式:`node {baseDir}/scripts/cos_node.mjs <action> [options]`
```bash
# 上传文件
upload --file /path/to/file.jpg --key remote/path/file.jpg
# 上传字符串
put-string --content "文本内容" --key remote/file.txt --content-type "text/plain"
# 下载文件
download --key remote/path/file.jpg --output /path/to/save/file.jpg
# 列出文件
list --prefix "images/"
# 获取签名 URL
sign-url --key remote/path/file.jpg --expires 3600
# 查看文件信息
head --key remote/path/file.jpg
# 删除文件
delete --key remote/path/file.jpg
```
所有命令输出 JSON 格式,`success: true` 表示成功,退出码 0。
### 限制
仅支持存储操作,**不支持**图片处理、智能搜索、文档转换。
---
## 方式三COSCMD 命令行
> 官方文档: https://www.tencentcloud.com/zh/document/product/436/10976
当方式一和方式二均不可用时使用。配置持久化在 `~/.cos.conf`
自定义域名支持(有限):
- **ServiceDomain** — 对应 coscmd 的 `-e ENDPOINT` 参数,设置后 Region 失效
- **Protocol** — 若为 `http`,对应 coscmd 的 `--do-not-use-ssl` 参数
- **Domain** — COSCMD 不支持 CDN 自定义域名
### 常用命令
```bash
# 上传
coscmd upload /path/to/file.jpg remote/path/file.jpg
coscmd upload -r /path/to/folder/ remote/folder/
# 下载
coscmd download remote/path/file.jpg /path/to/save/file.jpg
coscmd download -r remote/folder/ /path/to/save/
# 列出文件
coscmd list images/
# 删除
coscmd delete remote/path/file.jpg
coscmd delete -r remote/folder/ -f
# 签名 URL
coscmd signurl remote/path/file.jpg -t 3600
# 文件信息
coscmd info remote/path/file.jpg
# 复制/移动
coscmd copy <BucketName-APPID>.cos.<Region>.myqcloud.com/source.jpg dest.jpg
coscmd move <BucketName-APPID>.cos.<Region>.myqcloud.com/source.jpg dest.jpg
```
### 限制
仅支持存储操作,**不支持**图片处理、智能搜索、文档转换。
---
## 功能对照表
| 功能 | 方式一 cos-mcp | 方式二 Node SDK | 方式三 COSCMD |
|------|:-:|:-:|:-:|
| 上传文件 | ✅ | ✅ | ✅ |
| 上传字符串/Base64 | ✅ | ✅ | ❌ |
| 通过 URL 上传 | ✅ | ❌ | ❌ |
| 下载文件 | ✅ | ✅ | ✅ |
| 列出文件 | ✅ | ✅ | ✅ |
| 获取签名 URL | ✅ | ✅ | ✅ |
| 删除文件 | ❌ | ✅ | ✅ |
| 查看文件信息 | ❌ | ✅ | ✅ |
| 递归上传/下载目录 | ❌ | ❌ | ✅ |
| 图片处理CI | ✅ | ❌ | ❌ |
| 智能搜索 | ✅ | ❌ | ❌ |
| 文档转 PDF | ✅ | ❌ | ❌ |
| 视频智能封面 | ✅ | ❌ | ❌ |
## 使用规范
1. **首次使用先运行** `{baseDir}/scripts/setup.sh --check-only` 检查环境
2. **mcporter 调用必须带** `--config ~/.mcporter/mcporter.json``--output json`
3. **凭证不明文展示**:引导用户自行通过 setup.sh 或编辑配置文件设置
4. **所有文件路径**`objectKey`/`cospath`/`--key`)为存储桶内的相对路径,如 `images/photo.jpg`
5. **图片处理/智能搜索/文档转换仅方式一可用**,不可用时明确告知用户
6. **异步任务**(文档转换、视频封面)需通过 `jobId` 轮询结果
7. **上传后主动获取链接**:上传完成后调用 `getObjectUrl``sign-url` 返回访问链接
8. **错误处理**:调用失败时先用 `setup.sh --check-only` 诊断环境问题
9. **方式二脚本源码**见 `scripts/cos_node.mjs`
10. **MCP 工具详细参数**见 `references/api_reference.md`
11. **MCP 配置模板**见 `references/config_template.json`

View File

@@ -0,0 +1,6 @@
{
"ownerId": "kn75r0rammt45k8qe5we0sh63580c5y0",
"slug": "tencent-cos-skill",
"version": "1.0.6",
"publishedAt": 1772789580071
}

View File

@@ -0,0 +1,180 @@
# 腾讯云 COS 操作参考
本文档记录三种操作方式的详细参数定义,供执行操作时查阅。
**环境设置**:首次使用请运行 `scripts/setup.sh`,详见 `SKILL.md` 首次使用章节。
**官方文档链接:**
- cos-mcp GitHub: https://github.com/Tencent/cos-mcp
- COS Node.js SDK: https://www.tencentcloud.com/zh/document/product/436/8629
- COSCMD 工具: https://www.tencentcloud.com/zh/document/product/436/10976
---
## 方式一cos-mcp MCP 工具参数参考
## 存储操作工具
### getCosConfig
获取当前 COS 配置信息。
- 参数:无
### putObject
上传本地文件到存储桶。
- `filePath` (string, **必需**): 本地文件路径(包含文件名)
- `fileName` (string, 可选): 存储桶中的文件名
- `targetDir` (string, 可选): 存储桶中的目标目录
### putString
上传字符串内容到存储桶。
- `content` (string, **必需**): 要上传的字符串内容
- `fileName` (string, **必需**): 存储桶中的文件名
- `targetDir` (string, 可选): 目标目录
- `contentType` (string, 可选): MIME 类型,默认 `text/plain`
### putBase64
上传 base64 编码内容到存储桶。
- `base64Content` (string, **必需**): base64 编码的内容
- `fileName` (string, **必需**): 存储桶中的文件名
- `targetDir` (string, 可选): 目标目录
- `contentType` (string, 可选): MIME 类型,如 `image/png``application/pdf`
### putBuffer
上传 buffer 内容到存储桶。
- `content` (string, **必需**): buffer 内容字符串
- `fileName` (string, **必需**): 存储桶中的文件名
- `targetDir` (string, 可选): 目标目录
- `contentType` (string, 可选): MIME 类型,默认 `application/octet-stream`
- `encoding` (string, 可选): 编码格式,枚举值: `hex` | `base64` | `utf8` | `ascii` | `binary`,默认 `utf8`
### putObjectSourceUrl
通过 URL 下载文件并上传到存储桶。
- `sourceUrl` (string, **必需**): 可下载的文件 URL
- `fileName` (string, 可选): 存储桶中的文件名
- `targetDir` (string, 可选): 目标目录
### getObject
下载存储桶内的文件。
- `objectKey` (string, **必需**): 文件在存储桶中的路径
### getBucket
查询存储桶内的文件列表。
- `Prefix` (string, 可选): 路径前缀过滤,默认根路径
### getObjectUrl
获取文件的带签名下载链接。
- `objectKey` (string, **必需**): 文件在存储桶中的路径
## 图片处理工具
### imageInfo
获取图片元数据信息。
- `objectKey` (string, **必需**): 图片在存储桶中的路径
### assessQuality
评估图片质量分数。
- `objectKey` (string, **必需**): 图片在存储桶中的路径
### aiSuperResolution
AI 超分辨率,提升图片分辨率。
- `objectKey` (string, **必需**): 图片在存储桶中的路径
### aiPicMatting
AI 智能抠图,去除图片背景。
- `objectKey` (string, **必需**): 图片在存储桶中的路径
- `width` (string, 可选): 输出宽度
- `height` (string, 可选): 输出高度
### aiQrcode
识别存储桶内图片中的二维码内容。
- `objectKey` (string, **必需**): COS 对象键完整路径,如 `images/qrcode.jpg`
### waterMarkFont
生成带文字水印的图片。
- `objectKey` (string, **必需**): COS 对象键完整路径,如 `images/photo.jpg`
- `text` (string, 可选): 水印文字内容(支持中文),默认 `test`
## 智能搜索工具
### imageSearchPic
以图搜图,从数据集中检索相似图片。
- `uri` (string, **必需**): 图片地址
### imageSearchText
文本搜图,根据文字描述检索匹配图片。
- `text` (string, **必需**): 检索文本
## 文档与媒体处理工具
### createDocToPdfJob
创建文档转 PDF 处理任务。
- `objectKey` (string, **必需**): 文档在存储桶中的路径
### describeDocProcessJob
查询文档转码任务结果。
- `jobId` (string, **必需**): 任务 ID通过提交文档任务的响应获取
### createMediaSmartCoverJob
创建视频智能封面任务。
- `objectKey` (string, **必需**): 视频在存储桶中的路径
### describeMediaJob
查询智能封面任务结果。
- `jobId` (string, **必需**): 任务 ID通过提交智能封面任务的响应获取
---
## 方式二scripts/cos_node.mjs 命令参考
脚本位于 `scripts/cos_node.mjs`,依赖 `cos-nodejs-sdk-v5``npm install cos-nodejs-sdk-v5`)。
所有凭证通过环境变量读取。输出 JSON 格式。
### 可用操作
| 操作 | 命令 | 说明 |
|------|------|------|
| upload | `node scripts/cos_node.mjs upload --file <path> --key <key>` | 上传本地文件 |
| put-string | `node scripts/cos_node.mjs put-string --content <text> --key <key> [--content-type <mime>]` | 上传字符串内容 |
| download | `node scripts/cos_node.mjs download --key <key> --output <path>` | 下载文件到本地 |
| list | `node scripts/cos_node.mjs list [--prefix <prefix>] [--max-keys <n>]` | 列出文件 |
| sign-url | `node scripts/cos_node.mjs sign-url --key <key> [--expires <seconds>]` | 获取签名下载链接 |
| delete | `node scripts/cos_node.mjs delete --key <key>` | 删除文件 |
| head | `node scripts/cos_node.mjs head --key <key>` | 查看文件元信息 |
### 返回格式
成功时 `success: true`,退出码 0失败时 `success: false`,退出码 1。
---
## 方式三COSCMD 命令参考
依赖 Python通过 `pip install coscmd` 安装。首次使用需配置(写入 `~/.cos.conf`,后续无需重复):
```bash
coscmd config -a $TENCENT_COS_SECRET_ID -s $TENCENT_COS_SECRET_KEY -b $TENCENT_COS_BUCKET -r $TENCENT_COS_REGION
```
### 常用命令
| 操作 | 命令 | 说明 |
|------|------|------|
| 上传文件 | `coscmd upload <localpath> <cospath>` | 上传单个文件 |
| 递归上传目录 | `coscmd upload -r <localdir> <cosdir>` | 上传整个目录 |
| 下载文件 | `coscmd download <cospath> <localpath>` | 下载单个文件 |
| 递归下载目录 | `coscmd download -r <cosdir> <localdir>` | 下载整个目录 |
| 列出文件 | `coscmd list [cospath]` | 列出文件,加 `-r` 递归 |
| 删除文件 | `coscmd delete <cospath>` | 删除单个文件 |
| 递归删除 | `coscmd delete -r <cosdir> -f` | 强制递归删除 |
| 签名 URL | `coscmd signurl <cospath> [-t <seconds>]` | 获取带签名的下载链接 |
| 文件信息 | `coscmd info <cospath>` | 查看文件元信息 |
| 复制 | `coscmd copy <source> <dest>` | 桶内/跨桶复制 |
| 移动 | `coscmd move <source> <dest>` | 移动文件(复制+删除源) |
### 全局参数
- `-c <CONFIG_PATH>`:指定配置文件路径(默认 `~/.cos.conf`
- `-b <BucketName-APPID>`:指定存储桶(覆盖配置文件)
- `-r <Region>`:指定区域
- `-d`:调试模式,输出详细日志

View File

@@ -0,0 +1,73 @@
{
"_description": "cos-mcp MCP 服务器配置模板,添加到客户端的 MCP 配置文件中",
"mcpServers": {
"cos-mcp": {
"_comment": "方式一:参数直接传入 args",
"command": "npx",
"args": [
"cos-mcp",
"--Region=<替换为存储桶区域,如 ap-guangzhou>",
"--Bucket=<替换为存储桶名称,格式 name-appid>",
"--SecretId=<替换为腾讯云 API 密钥 ID>",
"--SecretKey=<替换为腾讯云 API 密钥 Key>",
"--DatasetName=<替换为数据万象数据集名称,无则删除此行>",
"--Domain=<替换为自定义域名,无则删除此行>",
"--ServiceDomain=<替换为自定义服务域名,无则删除此行>",
"--Protocol=<替换为协议,如 https无则删除此行>",
"--connectType=stdio"
]
},
"cos-mcp-env": {
"_comment": "方式二:通过 env 传递敏感参数(推荐)",
"command": "npx",
"args": [
"cos-mcp",
"--connectType=stdio"
],
"env": {
"TENCENT_COS_SECRET_ID": "<替换为腾讯云 API 密钥 ID>",
"TENCENT_COS_SECRET_KEY": "<替换为腾讯云 API 密钥 Key>",
"TENCENT_COS_REGION": "<替换为存储桶区域,如 ap-guangzhou>",
"TENCENT_COS_BUCKET": "<替换为存储桶名称,格式 name-appid>",
"TENCENT_COS_DATASET_NAME": "<替换为数据万象数据集名称,无则删除此行>",
"TENCENT_COS_DOMAIN": "<替换为自定义域名,无则删除此行>",
"TENCENT_COS_SERVICE_DOMAIN": "<替换为自定义服务域名,无则删除此行>",
"TENCENT_COS_PROTOCOL": "<替换为协议,如 https无则删除此行>"
}
},
"cos-mcp-sse": {
"_comment": "方式三SSE 模式(适合高频调用场景)",
"command": "npx",
"args": [
"cos-mcp",
"--connectType=sse",
"--port=3001"
],
"env": {
"TENCENT_COS_SECRET_ID": "<替换为腾讯云 API 密钥 ID>",
"TENCENT_COS_SECRET_KEY": "<替换为腾讯云 API 密钥 Key>",
"TENCENT_COS_REGION": "<替换为存储桶区域,如 ap-guangzhou>",
"TENCENT_COS_BUCKET": "<替换为存储桶名称,格式 name-appid>",
"TENCENT_COS_DOMAIN": "<替换为自定义域名,无则删除此行>",
"TENCENT_COS_SERVICE_DOMAIN": "<替换为自定义服务域名,无则删除此行>",
"TENCENT_COS_PROTOCOL": "<替换为协议,如 https无则删除此行>"
}
}
},
"_参数说明": {
"Region": "存储桶区域,如 ap-guangzhou、ap-shanghai、ap-beijing 等",
"Bucket": "存储桶名称,格式为 name-appid如 mybucket-1250000000",
"SecretId": "腾讯云 API 密钥 ID在 访问管理 > API密钥管理 中创建",
"SecretKey": "腾讯云 API 密钥 Key与 SecretId 配对使用",
"DatasetName": "数据万象数据集名称(仅图片搜索等智能功能需要,无则不填)",
"Domain": "自定义域名(可选),用于替换默认的 COS 访问域名,如 cdn.example.com",
"ServiceDomain": "自定义服务域名(可选),用于自定义 COS API 请求域名",
"Protocol": "协议(可选),如 https 或 http默认根据浏览器环境自动判断",
"connectType": "连接模式stdio默认推荐或 sse",
"port": "SSE 模式下的监听端口(默认 3001"
}
}

View File

@@ -0,0 +1,323 @@
#!/usr/bin/env node
/**
* 腾讯云 COS Node.js SDK 操作脚本
* 作为 cos-mcp MCP 工具不可用时的降级方案
*
* 依赖npm install cos-nodejs-sdk-v5
* 凭证通过环境变量读取:
* TENCENT_COS_SECRET_ID / TENCENT_COS_SECRET_KEY / TENCENT_COS_REGION / TENCENT_COS_BUCKET
*
* 用法node cos_node.mjs <action> [options]
*/
import { createRequire } from 'module';
import { createReadStream, createWriteStream, existsSync } from 'fs';
import { basename, resolve } from 'path';
import { pipeline } from 'stream/promises';
const require = createRequire(import.meta.url);
const COS = require('cos-nodejs-sdk-v5');
// 读取环境变量
const SecretId = process.env.TENCENT_COS_SECRET_ID;
const SecretKey = process.env.TENCENT_COS_SECRET_KEY;
const Region = process.env.TENCENT_COS_REGION;
const Bucket = process.env.TENCENT_COS_BUCKET;
// 可选的自定义域名配置
const Domain = process.env.TENCENT_COS_DOMAIN;
const ServiceDomain = process.env.TENCENT_COS_SERVICE_DOMAIN;
const Protocol = process.env.TENCENT_COS_PROTOCOL;
if (!SecretId || !SecretKey || !Region || !Bucket) {
console.error(JSON.stringify({
success: false,
error: '缺少环境变量需要TENCENT_COS_SECRET_ID, TENCENT_COS_SECRET_KEY, TENCENT_COS_REGION, TENCENT_COS_BUCKET',
}));
process.exit(1);
}
const cosOptions = { SecretId, SecretKey };
if (Domain) {
cosOptions.Domain = Domain;
}
if (ServiceDomain) {
cosOptions.ServiceDomain = ServiceDomain;
}
if (Protocol) {
cosOptions.Protocol = Protocol;
}
const cos = new COS(cosOptions);
// 解析命令行参数
function parseArgs(args) {
const result = {};
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg.startsWith('--')) {
const key = arg.slice(2);
const next = args[i + 1];
if (next && !next.startsWith('--')) {
result[key] = next;
i++;
} else {
result[key] = true;
}
}
}
return result;
}
// 输出 JSON 结果
function output(data) {
console.log(JSON.stringify(data, null, 2));
}
// 封装 COS SDK 回调为 Promise
function cosPromise(method, params) {
return new Promise((resolve, reject) => {
cos[method]({ Bucket, Region, ...params }, (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
// ========== 操作实现 ==========
async function upload(opts) {
const filePath = opts.file;
const key = opts.key || basename(filePath);
if (!filePath) {
throw new Error('缺少 --file 参数');
}
if (!existsSync(filePath)) {
throw new Error(`文件不存在:${filePath}`);
}
const data = await cosPromise('putObject', {
Key: key,
Body: createReadStream(filePath),
});
output({
success: true,
action: 'upload',
key,
etag: data.ETag,
location: data.Location,
statusCode: data.statusCode,
});
}
async function putString(opts) {
const content = opts.content;
const key = opts.key;
const contentType = opts['content-type'] || 'text/plain';
if (!content) {
throw new Error('缺少 --content 参数');
}
if (!key) {
throw new Error('缺少 --key 参数');
}
const data = await cosPromise('putObject', {
Key: key,
Body: content,
ContentType: contentType,
});
output({
success: true,
action: 'put-string',
key,
etag: data.ETag,
location: data.Location,
statusCode: data.statusCode,
});
}
async function download(opts) {
const key = opts.key;
const outputPath = opts.output || basename(key);
if (!key) {
throw new Error('缺少 --key 参数');
}
const data = await cosPromise('getObject', {
Key: key,
});
const resolvedPath = resolve(outputPath);
const ws = createWriteStream(resolvedPath);
if (data.Body instanceof Buffer) {
ws.write(data.Body);
ws.end();
} else if (data.Body && typeof data.Body.pipe === 'function') {
await pipeline(data.Body, ws);
} else {
ws.write(String(data.Body));
ws.end();
}
output({
success: true,
action: 'download',
key,
savedTo: resolvedPath,
contentLength: data.headers?.['content-length'],
statusCode: data.statusCode,
});
}
async function list(opts) {
const prefix = opts.prefix || '';
const maxKeys = parseInt(opts['max-keys'], 10) || 100;
const data = await cosPromise('getBucket', {
Prefix: prefix,
MaxKeys: maxKeys,
});
const files = (data.Contents || []).map(item => ({
key: item.Key,
size: parseInt(item.Size, 10),
lastModified: item.LastModified,
etag: item.ETag,
storageClass: item.StorageClass,
}));
output({
success: true,
action: 'list',
prefix,
count: files.length,
isTruncated: data.IsTruncated === 'true',
files,
});
}
async function signUrl(opts) {
const key = opts.key;
const expires = parseInt(opts.expires, 10) || 3600;
if (!key) {
throw new Error('缺少 --key 参数');
}
const url = await new Promise((resolve, reject) => {
cos.getObjectUrl({
Bucket,
Region,
Key: key,
Expires: expires,
Sign: true,
}, (err, data) => {
if (err) {
reject(err);
} else {
resolve(data.Url);
}
});
});
output({
success: true,
action: 'sign-url',
key,
expires,
url,
});
}
async function deleteObject(opts) {
const key = opts.key;
if (!key) {
throw new Error('缺少 --key 参数');
}
const data = await cosPromise('deleteObject', {
Key: key,
});
output({
success: true,
action: 'delete',
key,
statusCode: data.statusCode,
});
}
async function head(opts) {
const key = opts.key;
if (!key) {
throw new Error('缺少 --key 参数');
}
const data = await cosPromise('headObject', {
Key: key,
});
output({
success: true,
action: 'head',
key,
contentLength: parseInt(data.headers?.['content-length'], 10),
contentType: data.headers?.['content-type'],
etag: data.headers?.etag,
lastModified: data.headers?.['last-modified'],
storageClass: data.headers?.['x-cos-storage-class'] || 'STANDARD',
statusCode: data.statusCode,
});
}
// ========== 主入口 ==========
const args = process.argv.slice(2);
const action = args[0];
const opts = parseArgs(args.slice(1));
const actions = {
upload,
'put-string': putString,
download,
list,
'sign-url': signUrl,
delete: deleteObject,
head,
};
if (!action || !actions[action]) {
output({
success: false,
error: `未知操作:${action || '(空)'}`,
availableActions: Object.keys(actions),
usage: 'node cos_node.mjs <action> [--option value ...]',
});
process.exit(1);
}
try {
await actions[action](opts);
} catch (err) {
output({
success: false,
action,
error: err.message || String(err),
code: err.code,
});
process.exit(1);
}

View File

@@ -0,0 +1,417 @@
#!/bin/bash
# 腾讯云 COS Skill 自动设置脚本
# 用法:
# setup.sh --check-only 仅检查环境状态
# setup.sh --secret-id <ID> --secret-key <KEY> --region <REGION> --bucket <BUCKET> [--dataset <NAME>]
set -e
# 颜色
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'
ok() { echo -e "${GREEN}${NC} $1"; }
fail() { echo -e "${RED}${NC} $1"; }
warn() { echo -e "${YELLOW}!${NC} $1"; }
# 获取脚本所在目录skill baseDir
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
BASE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
# ========== 检查函数 ==========
check_node() {
if command -v node &>/dev/null; then
ok "Node.js $(node --version)"
return 0
else
fail "Node.js 未安装"
return 1
fi
}
check_npm() {
if command -v npm &>/dev/null; then
ok "npm $(npm --version)"
return 0
else
fail "npm 未安装"
return 1
fi
}
check_mcporter() {
if command -v mcporter &>/dev/null; then
ok "mcporter $(mcporter --version 2>/dev/null || echo '已安装')"
return 0
else
fail "mcporter 未安装"
return 1
fi
}
check_mcporter_config() {
if [ -f ~/.mcporter/mcporter.json ]; then
if grep -q '"cos-mcp"' ~/.mcporter/mcporter.json 2>/dev/null; then
ok "mcporter 已配置 cos-mcp 服务器"
return 0
else
warn "mcporter.json 存在但未配置 cos-mcp"
return 1
fi
else
fail "~/.mcporter/mcporter.json 不存在"
return 1
fi
}
check_cos_mcp() {
if command -v npx &>/dev/null && npx cos-mcp --help &>/dev/null 2>&1; then
ok "cos-mcp 可用"
return 0
else
fail "cos-mcp 未安装或不可用"
return 1
fi
}
check_cos_sdk() {
if node -e "require('cos-nodejs-sdk-v5')" &>/dev/null 2>&1; then
ok "cos-nodejs-sdk-v5 已安装"
return 0
else
fail "cos-nodejs-sdk-v5 未安装"
return 1
fi
}
check_coscmd() {
if command -v coscmd &>/dev/null; then
ok "coscmd 可用"
return 0
else
warn "coscmd 未安装(可选)"
return 1
fi
}
check_env_vars() {
local all_set=true
for var in TENCENT_COS_SECRET_ID TENCENT_COS_SECRET_KEY TENCENT_COS_REGION TENCENT_COS_BUCKET; do
if [ -n "${!var}" ]; then
ok "$var 已设置"
else
fail "$var 未设置"
all_set=false
fi
done
$all_set
}
check_cos_conf() {
if [ -f ~/.cos.conf ]; then
ok "~/.cos.conf 已存在"
return 0
else
warn "~/.cos.conf 不存在"
return 1
fi
}
# ========== 检查模式 ==========
do_check() {
echo "=== 腾讯云 COS Skill 环境检查 ==="
echo ""
echo "--- 基础环境 ---"
check_node || true
check_npm || true
echo ""
echo "--- 方式一: cos-mcp MCP ---"
check_mcporter || true
check_mcporter_config || true
check_cos_mcp || true
echo ""
echo "--- 方式二: Node.js SDK ---"
check_cos_sdk || true
check_env_vars || true
echo ""
echo "--- 方式三: COSCMD ---"
check_coscmd || true
check_cos_conf || true
echo ""
echo "--- Skill 文件 ---"
[ -f "$BASE_DIR/SKILL.md" ] && ok "SKILL.md" || fail "SKILL.md 不存在"
[ -f "$BASE_DIR/scripts/cos_node.mjs" ] && ok "scripts/cos_node.mjs" || fail "scripts/cos_node.mjs 不存在"
[ -f "$BASE_DIR/references/config_template.json" ] && ok "references/config_template.json" || fail "references/config_template.json 不存在"
echo ""
}
# ========== 设置模式 ==========
do_setup() {
local SECRET_ID=""
local SECRET_KEY=""
local REGION=""
local BUCKET=""
local DATASET=""
local DOMAIN=""
local SERVICE_DOMAIN=""
local PROTOCOL=""
while [[ $# -gt 0 ]]; do
case "$1" in
--secret-id) SECRET_ID="$2"; shift 2;;
--secret-key) SECRET_KEY="$2"; shift 2;;
--region) REGION="$2"; shift 2;;
--bucket) BUCKET="$2"; shift 2;;
--dataset) DATASET="$2"; shift 2;;
--domain) DOMAIN="$2"; shift 2;;
--service-domain) SERVICE_DOMAIN="$2"; shift 2;;
--protocol) PROTOCOL="$2"; shift 2;;
*) shift;;
esac
done
if [ -z "$SECRET_ID" ] || [ -z "$SECRET_KEY" ] || [ -z "$REGION" ] || [ -z "$BUCKET" ]; then
echo "错误: 缺少必需参数"
echo "用法: setup.sh --secret-id <ID> --secret-key <KEY> --region <REGION> --bucket <BUCKET> [--dataset <NAME>]"
exit 1
fi
echo "=== 腾讯云 COS Skill 自动设置 ==="
echo ""
# 1. 检查 Node.js
echo "--- 步骤 1: 检查 Node.js ---"
if ! check_node; then
fail "请先安装 Node.js: https://nodejs.org/"
exit 1
fi
# 2. 确保 package.json 存在
echo ""
echo "--- 步骤 2: 初始化项目 ---"
if [ ! -f "$BASE_DIR/package.json" ]; then
(cd "$BASE_DIR" && npm init -y &>/dev/null)
ok "已创建 package.json"
else
ok "package.json 已存在"
fi
# 3. 安装 cos-mcp、cos-nodejs-sdk-v5 和 mcporter
echo ""
echo "--- 步骤 3: 安装依赖 ---"
(cd "$BASE_DIR" && npm install cos-mcp cos-nodejs-sdk-v5 --no-progress 2>&1 | tail -3)
ok "cos-mcp + cos-nodejs-sdk-v5 安装完成"
# 安装 mcporter全局
if ! command -v mcporter &>/dev/null; then
echo "正在安装 mcporter..."
npm install -g mcporter --no-progress 2>&1 | tail -3
if command -v mcporter &>/dev/null; then
ok "mcporter 全局安装完成"
else
warn "mcporter 全局安装失败,尝试本地安装..."
(cd "$BASE_DIR" && npm install mcporter --no-progress 2>&1 | tail -3)
ok "mcporter 本地安装完成(使用 npx mcporter 调用)"
fi
else
ok "mcporter 已安装"
fi
# 4. 写入环境变量到 shell 配置
echo ""
echo "--- 步骤 4: 持久化凭证 ---"
# 判断 shell 配置文件
local SHELL_RC=""
if [ -n "$ZSH_VERSION" ] || [ "$SHELL" = "/bin/zsh" ]; then
SHELL_RC="$HOME/.zshrc"
else
SHELL_RC="$HOME/.bashrc"
fi
# 先清理旧的 COS 配置
if [ -f "$SHELL_RC" ]; then
sed -i.bak '/^# --- Tencent COS Skill ---$/,/^# --- End Tencent COS Skill ---$/d' "$SHELL_RC"
rm -f "${SHELL_RC}.bak"
fi
# 写入新配置
cat >> "$SHELL_RC" << EOF
# --- Tencent COS Skill ---
export TENCENT_COS_SECRET_ID="$SECRET_ID"
export TENCENT_COS_SECRET_KEY="$SECRET_KEY"
export TENCENT_COS_REGION="$REGION"
export TENCENT_COS_BUCKET="$BUCKET"
EOF
if [ -n "$DATASET" ]; then
sed -i.bak '/^# --- End Tencent COS Skill ---$/d' "$SHELL_RC"
rm -f "${SHELL_RC}.bak"
cat >> "$SHELL_RC" << EOF
export TENCENT_COS_DATASET_NAME="$DATASET"
EOF
fi
if [ -n "$DOMAIN" ]; then
sed -i.bak '/^# --- End Tencent COS Skill ---$/d' "$SHELL_RC"
rm -f "${SHELL_RC}.bak"
cat >> "$SHELL_RC" << EOF
export TENCENT_COS_DOMAIN="$DOMAIN"
EOF
fi
if [ -n "$SERVICE_DOMAIN" ]; then
sed -i.bak '/^# --- End Tencent COS Skill ---$/d' "$SHELL_RC"
rm -f "${SHELL_RC}.bak"
cat >> "$SHELL_RC" << EOF
export TENCENT_COS_SERVICE_DOMAIN="$SERVICE_DOMAIN"
EOF
fi
if [ -n "$PROTOCOL" ]; then
sed -i.bak '/^# --- End Tencent COS Skill ---$/d' "$SHELL_RC"
rm -f "${SHELL_RC}.bak"
cat >> "$SHELL_RC" << EOF
export TENCENT_COS_PROTOCOL="$PROTOCOL"
EOF
fi
echo "# --- End Tencent COS Skill ---" >> "$SHELL_RC"
ok "凭证已写入 $SHELL_RC"
# 同时导出到当前 session
export TENCENT_COS_SECRET_ID="$SECRET_ID"
export TENCENT_COS_SECRET_KEY="$SECRET_KEY"
export TENCENT_COS_REGION="$REGION"
export TENCENT_COS_BUCKET="$BUCKET"
[ -n "$DATASET" ] && export TENCENT_COS_DATASET_NAME="$DATASET"
[ -n "$DOMAIN" ] && export TENCENT_COS_DOMAIN="$DOMAIN"
[ -n "$SERVICE_DOMAIN" ] && export TENCENT_COS_SERVICE_DOMAIN="$SERVICE_DOMAIN"
[ -n "$PROTOCOL" ] && export TENCENT_COS_PROTOCOL="$PROTOCOL"
# 5. 配置 mcporter
echo ""
echo "--- 步骤 5: 配置 mcporter ---"
local MCPORTER_DIR="$HOME/.mcporter"
local MCPORTER_CONFIG="$MCPORTER_DIR/mcporter.json"
mkdir -p "$MCPORTER_DIR"
# 构建 cos-mcp 的 args 列表
local COS_MCP_ARGS="\"cos-mcp\", \"--Region=$REGION\", \"--Bucket=$BUCKET\", \"--SecretId=$SECRET_ID\", \"--SecretKey=$SECRET_KEY\""
if [ -n "$DATASET" ]; then
COS_MCP_ARGS="$COS_MCP_ARGS, \"--DatasetName=$DATASET\""
fi
if [ -n "$DOMAIN" ]; then
COS_MCP_ARGS="$COS_MCP_ARGS, \"--Domain=$DOMAIN\""
fi
if [ -n "$SERVICE_DOMAIN" ]; then
COS_MCP_ARGS="$COS_MCP_ARGS, \"--ServiceDomain=$SERVICE_DOMAIN\""
fi
if [ -n "$PROTOCOL" ]; then
COS_MCP_ARGS="$COS_MCP_ARGS, \"--Protocol=$PROTOCOL\""
fi
COS_MCP_ARGS="$COS_MCP_ARGS, \"--connectType=stdio\""
if [ -f "$MCPORTER_CONFIG" ]; then
# 已有配置文件,检查是否已配置 cos-mcp
if grep -q '"cos-mcp"' "$MCPORTER_CONFIG" 2>/dev/null; then
warn "mcporter.json 中已存在 cos-mcp 配置,将更新"
fi
# 使用 node 合并配置(保留其他 MCP 服务器配置)
node -e "
const fs = require('fs');
const configPath = '$MCPORTER_CONFIG';
let config = {};
try { config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); } catch(e) {}
if (!config.mcpServers) config.mcpServers = {};
config.mcpServers['cos-mcp'] = {
command: 'npx',
args: [$COS_MCP_ARGS]
};
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
" 2>/dev/null
ok "mcporter.json 已更新 cos-mcp 配置"
else
# 创建全新的配置文件
cat > "$MCPORTER_CONFIG" << MCPEOF
{
"mcpServers": {
"cos-mcp": {
"command": "npx",
"args": [$COS_MCP_ARGS]
}
}
}
MCPEOF
ok "mcporter.json 已创建"
fi
# 6. 配置 COSCMD如果有 Python
echo ""
echo "--- 步骤 6: 配置 COSCMD可选 ---"
if command -v pip3 &>/dev/null || command -v pip &>/dev/null; then
local PIP_CMD
PIP_CMD=$(command -v pip3 || command -v pip)
$PIP_CMD install coscmd -q 2>/dev/null
# 构建 coscmd config 命令
local COSCMD_ARGS="-a $SECRET_ID -s $SECRET_KEY -b $BUCKET -r $REGION"
if [ -n "$SERVICE_DOMAIN" ]; then
COSCMD_ARGS="$COSCMD_ARGS -e $SERVICE_DOMAIN"
fi
if [ -n "$PROTOCOL" ] && [ "$PROTOCOL" = "http" ]; then
COSCMD_ARGS="$COSCMD_ARGS --do-not-use-ssl"
fi
eval coscmd config $COSCMD_ARGS 2>/dev/null && \
ok "coscmd 已配置" || \
warn "coscmd 安装/配置失败(非关键)"
else
warn "Python/pip 未安装,跳过 coscmd"
fi
# 7. 验证
echo ""
echo "--- 步骤 7: 验证连接 ---"
if (cd "$BASE_DIR" && node scripts/cos_node.mjs list --max-keys 1 2>/dev/null | grep -q '"success": true'); then
ok "COS 连接验证成功"
else
warn "COS 连接验证失败,请检查凭证和网络"
fi
echo ""
echo "=== 设置完成 ==="
echo "现在可以使用以下方式操作 COS"
echo " 方式一: mcporter call cos-mcp.<tool> --config ~/.mcporter/mcporter.json --output json"
echo " 方式一(备选): cos-mcp MCP 工具(通过客户端直接调用)"
echo " 方式二: node $BASE_DIR/scripts/cos_node.mjs <action>"
echo " 方式三: coscmd <command>"
}
# ========== 主入口 ==========
case "$1" in
--check-only)
do_check
;;
--secret-id|--secret-key|--region|--bucket)
do_setup "$@"
;;
*)
echo "腾讯云 COS Skill 设置工具"
echo ""
echo "用法:"
echo " $0 --check-only"
echo " 仅检查环境状态"
echo ""
echo " $0 --secret-id <ID> --secret-key <KEY> --region <REGION> --bucket <BUCKET> [--dataset <NAME>] [--domain <DOMAIN>] [--service-domain <DOMAIN>] [--protocol <PROTOCOL>]"
echo " 自动设置环境(安装依赖 + 配置凭证 + 验证连接)"
;;
esac