@avclabs.ai/media-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +333 -0
- package/README_EN.md +332 -0
- package/config.json +4 -0
- package/dist/sam3.d.ts +3 -0
- package/dist/sam3.d.ts.map +1 -0
- package/dist/sam3.js +154 -0
- package/dist/sam3.js.map +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +92 -0
- package/dist/server.js.map +1 -0
- package/dist/video-enhancement.d.ts +3 -0
- package/dist/video-enhancement.d.ts.map +1 -0
- package/dist/video-enhancement.js +225 -0
- package/dist/video-enhancement.js.map +1 -0
- package/package.json +73 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 http-mcp-client-server
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
# media-mcp (Node.js)
|
|
2
|
+
|
|
3
|
+
中文 | [English](https://github.com/avclabs/media-mcp/blob/main/README_EN.md)
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@avclabs.ai/media-mcp)
|
|
6
|
+
[](https://nodejs.org/)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
基于 MCP 协议的视频增强与图像分割服务,作为 MCP Client-Server 与后端 HTTP Server 交互。
|
|
10
|
+
|
|
11
|
+
## 功能
|
|
12
|
+
|
|
13
|
+
提供以下 MCP Tools:
|
|
14
|
+
- `create_task` - 创建视频增强任务(支持 URL 或本地文件上传)
|
|
15
|
+
- `get_task_status` - 查询任务状态
|
|
16
|
+
- `enhance_video_sync` - 同步增强视频(阻塞等待完成)
|
|
17
|
+
- `sam3_predict` - SAM3 图像分割(支持本地路径、URL 或 Base64 图片)
|
|
18
|
+
|
|
19
|
+
## 前置要求
|
|
20
|
+
|
|
21
|
+
- **Node.js >= 18**(检查:`node --version`)
|
|
22
|
+
- **API Key**(用于身份认证,请联系服务提供方获取)
|
|
23
|
+
|
|
24
|
+
## 懒人安装(推荐)
|
|
25
|
+
|
|
26
|
+
如果你使用的 AI Agent 有确定的 MCP 配置路径,直接复制下面这句发给 AI:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
帮我安装 npm 包 @avclabs.ai/media-mcp 作为 MCP server。我的 API Key 是:sk-xxxxxxxx。
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
AI 会自动完成:
|
|
33
|
+
1. 检测你使用的 MCP 客户端
|
|
34
|
+
2. 找到配置文件路径
|
|
35
|
+
3. 写入正确的配置
|
|
36
|
+
4. 提示你重启客户端
|
|
37
|
+
|
|
38
|
+
## 手动安装
|
|
39
|
+
|
|
40
|
+
无需安装,直接在 MCP 客户端配置中使用 `npx` 运行。
|
|
41
|
+
|
|
42
|
+
### 1. Claude Code(CLI)
|
|
43
|
+
|
|
44
|
+
在 Claude Code 中运行:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
/mcp
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
查看输出中 **"User MCPs"** 对应的配置文件路径,然后编辑该文件。
|
|
51
|
+
|
|
52
|
+
常见路径(如果 `/mcp` 不可用):
|
|
53
|
+
- **Windows**: `%USERPROFILE%\.claude.json`
|
|
54
|
+
- **macOS**: `~/.claude.json`
|
|
55
|
+
- **Linux**: `~/.claude.json`
|
|
56
|
+
- **旧版/备用**: `~/.claude/mcp.json`
|
|
57
|
+
|
|
58
|
+
粘贴以下内容(将 `your-api-key` 替换为实际 API Key):
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"mcpServers": {
|
|
63
|
+
"video-enhancement": {
|
|
64
|
+
"command": "npx",
|
|
65
|
+
"args": ["-y", "@avclabs.ai/media-mcp@latest"],
|
|
66
|
+
"env": {
|
|
67
|
+
"API_KEY": "your-api-key"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
保存后运行 `/mcp` 验证是否加载成功。
|
|
75
|
+
|
|
76
|
+
### 2. Cursor
|
|
77
|
+
|
|
78
|
+
进入 **设置 > Tools & MCPs > Add New MCP Server**:
|
|
79
|
+
|
|
80
|
+
- **Name**:`video-enhancement`
|
|
81
|
+
- **Type**:`command`
|
|
82
|
+
- **Command**:
|
|
83
|
+
```bash
|
|
84
|
+
env HTTP_API_KEY=your-api-key npx -y @avclabs.ai/media-mcp@latest
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
或编辑 `~/.cursor/mcp.json`:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"mcpServers": {
|
|
92
|
+
"video-enhancement": {
|
|
93
|
+
"command": "npx",
|
|
94
|
+
"args": ["-y", "@avclabs.ai/media-mcp@latest"],
|
|
95
|
+
"env": {
|
|
96
|
+
"API_KEY": "your-api-key"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## 验证安装
|
|
104
|
+
|
|
105
|
+
重启客户端后,确认工具是否加载成功:
|
|
106
|
+
|
|
107
|
+
1. 或直接问 AI:"你有哪些可用的工具?"
|
|
108
|
+
2. 应看到:`create_task`、`get_task_status`、`enhance_video_sync`、`sam3_predict`
|
|
109
|
+
|
|
110
|
+
## 配置项
|
|
111
|
+
|
|
112
|
+
| 变量名 | 必填 | 默认值 | 说明 |
|
|
113
|
+
|---|---|---|---|
|
|
114
|
+
| `API_KEY` | **是** | - | API 认证密钥(视频增强和 SAM3 共用) |
|
|
115
|
+
| `HTTP_API_BASE_URL` | 否 | `https://mcp.avc.ai/enhance` | 视频增强服务接口地址 |
|
|
116
|
+
| `SAM3_API_BASE_URL` | 否 | `https://mcp.avc.ai/sam` | SAM3 服务接口地址 |
|
|
117
|
+
| `SAM3_POLL_INTERVAL` | 否 | `2000` | 轮询间隔(毫秒) |
|
|
118
|
+
| `SAM3_POLL_MAX_ATTEMPTS` | 否 | `60` | 最大轮询次数 |
|
|
119
|
+
|
|
120
|
+
### 自定义服务地址
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"env": {
|
|
125
|
+
"HTTP_API_BASE_URL": "https://your-endpoint.com",
|
|
126
|
+
"API_KEY": "your-api-key",
|
|
127
|
+
"SAM3_API_BASE_URL": "http://localhost:8001"
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
或通过命令行参数:
|
|
133
|
+
```bash
|
|
134
|
+
npx -y @avclabs.ai/media-mcp@latest --base-url https://your-endpoint.com --api-key your-api-key --sam3-base-url http://localhost:8001
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## 使用示例
|
|
138
|
+
|
|
139
|
+
配置完成后,用自然语言对 AI 说:
|
|
140
|
+
|
|
141
|
+
> "帮我把这个视频增强到 1080p:https://example.com/video.mp4"
|
|
142
|
+
|
|
143
|
+
> "把我桌面的 video.mp4 提升到 2k 画质"
|
|
144
|
+
|
|
145
|
+
AI 会自动调用相应工具完成任务。
|
|
146
|
+
|
|
147
|
+
> "帮我分析一下这张图片,找出里面的所有物体:C:\\Users\\xxx\\photo.png"
|
|
148
|
+
>
|
|
149
|
+
> "用 SAM3 分割这张图片,prompt 是 'find all cars'"
|
|
150
|
+
|
|
151
|
+
## 提供的 Tools
|
|
152
|
+
|
|
153
|
+
### create_task
|
|
154
|
+
|
|
155
|
+
创建视频增强任务(异步)。
|
|
156
|
+
|
|
157
|
+
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
158
|
+
|---|---|---|---|---|
|
|
159
|
+
| `video_source` | string | 是 | - | 视频 URL 或本地文件路径(URL 必须公网可访问,不支持需要登录或签名的链接) |
|
|
160
|
+
| `type` | string | 否 | `url` | `url` 或 `local` |
|
|
161
|
+
| `resolution` | string | 否 | `720p` | `480p`、`540p`、`720p`、`1080p`、`2k` |
|
|
162
|
+
|
|
163
|
+
**返回值:**
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"success": true,
|
|
167
|
+
"task_id": "xxx",
|
|
168
|
+
"status": "wait"
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### get_task_status
|
|
173
|
+
|
|
174
|
+
查询任务状态。
|
|
175
|
+
|
|
176
|
+
| 参数 | 类型 | 必填 |
|
|
177
|
+
|---|---|---|
|
|
178
|
+
| `task_id` | string | 是 |
|
|
179
|
+
|
|
180
|
+
**返回值:**
|
|
181
|
+
```json
|
|
182
|
+
{
|
|
183
|
+
"success": true,
|
|
184
|
+
"task_id": "xxx",
|
|
185
|
+
"status": "completed",
|
|
186
|
+
"progress": 100,
|
|
187
|
+
"video_url": "https://..."
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### enhance_video_sync
|
|
192
|
+
|
|
193
|
+
同步增强视频(阻塞等待完成)。
|
|
194
|
+
|
|
195
|
+
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
196
|
+
|---|---|---|---|---|
|
|
197
|
+
| `video_source` | string | 是 | - | 视频 URL 或本地文件路径(URL 必须公网可访问,不支持需要登录或签名的链接) |
|
|
198
|
+
| `type` | string | 否 | `url` | `url` 或 `local` |
|
|
199
|
+
| `resolution` | string | 否 | `720p` | 目标分辨率 |
|
|
200
|
+
| `poll_interval` | number | 否 | `5` | 轮询间隔(秒) |
|
|
201
|
+
| `timeout` | number | 否 | `600` | 超时时间(秒) |
|
|
202
|
+
|
|
203
|
+
### sam3_predict
|
|
204
|
+
|
|
205
|
+
使用 SAM3 分割 API 分析图片,生成推理结果(masks、boxes、scores)。
|
|
206
|
+
|
|
207
|
+
**参数:**
|
|
208
|
+
|
|
209
|
+
图片输入(三选一,必须提供其中一种):
|
|
210
|
+
|
|
211
|
+
- `imagePath` (string): 本地图片的绝对路径。支持常见图片格式(如 PNG、JPG、JPEG)。
|
|
212
|
+
- 示例:`"C:\\Users\\xxx\\photo.png"`、`"/home/user/images/cat.jpg"`
|
|
213
|
+
- 适用场景:用户明确提供了本地文件路径
|
|
214
|
+
|
|
215
|
+
- `imageUrl` (string): 公开可访问的图片 URL。
|
|
216
|
+
- 示例:`"https://example.com/photo.jpg"`
|
|
217
|
+
- 适用场景:图片已在网上,用户提供了链接
|
|
218
|
+
- 注意:URL 必须公开可访问,不支持需要登录或签名的链接
|
|
219
|
+
|
|
220
|
+
- `imageBase64` (string): Base64 编码的图片数据。
|
|
221
|
+
- 示例:`"iVBORw0KGgoAAAANSUhEUgAA..."`
|
|
222
|
+
- 适用场景:用户拖拽或上传了图片附件,Agent 将图片编码为 base64 后传入
|
|
223
|
+
- 注意:大图片的 base64 数据会比较大,传输时间可能稍长
|
|
224
|
+
|
|
225
|
+
其他参数:
|
|
226
|
+
|
|
227
|
+
- `prompt` (string, required): 英文文本提示,用于指定要在图片中分割的目标物体。例如 `"person"`、`"car"`、`"a cat sitting on a sofa"`。由于 SAM3 模型仅接受英文 prompt,建议传入英文描述。如果用户提供中文或其他非英文文本,Agent 会自动翻译为英文后调用。
|
|
228
|
+
|
|
229
|
+
**返回:**
|
|
230
|
+
|
|
231
|
+
推理完成后,直接返回 JSON 字符串。该 JSON 包含以下三个字段:
|
|
232
|
+
|
|
233
|
+
- **`masks`**:二维数组。每个元素是一个与输入图片尺寸相同的二值掩码(取值为 0 或 1),用于标记检测到的物体在图片中的像素级位置。数组中的第 i 个掩码对应第 i 个检测到的物体实例。
|
|
234
|
+
- **`boxes`**:二维数组。每个元素是 `[x1, y1, x2, y2]` 格式的边界框坐标,表示检测到的物体在图片中的矩形区域。`x1`、`y1` 为左上角坐标,`x2`、`y2` 为右下角坐标。
|
|
235
|
+
|
|
236
|
+
坐标系说明:以图片左上角为原点 `(0, 0)`,`x` 轴向右增长,`y` 轴向下增长,单位为像素。例如 `[120, 80, 300, 450]` 表示该物体区域从图片左边缘向右 120px、上边缘向下 80px 处开始,延伸至左边缘向右 300px、上边缘向下 450px 处结束,区域宽度为 `x2 - x1 = 180px`,高度为 `y2 - y1 = 370px`。
|
|
237
|
+
- **`scores`**:一维数组。每个元素是对应检测结果的置信度分数,取值范围为 0 到 1。分数越高,表示模型对该检测结果的把握越大。
|
|
238
|
+
|
|
239
|
+
结果 JSON 内容示例:
|
|
240
|
+
|
|
241
|
+
```json
|
|
242
|
+
{
|
|
243
|
+
"masks": [
|
|
244
|
+
[[0, 0, 1, ...], [0, 1, 1, ...], ...],
|
|
245
|
+
[[0, 0, 0, ...], [0, 0, 1, ...], ...]
|
|
246
|
+
],
|
|
247
|
+
"boxes": [
|
|
248
|
+
[120, 80, 300, 450],
|
|
249
|
+
[400, 200, 600, 500]
|
|
250
|
+
],
|
|
251
|
+
"scores": [0.95, 0.87]
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## 常见问题
|
|
256
|
+
|
|
257
|
+
### 拖拽附件后提示找不到文件?
|
|
258
|
+
|
|
259
|
+
这是 stdio MCP 的已知限制。当通过 Agent 界面拖拽或上传附件时,文件路径通常不会自动传给 MCP Server。
|
|
260
|
+
|
|
261
|
+
**解决方法:**
|
|
262
|
+
|
|
263
|
+
1. **同时提供路径**(推荐):拖拽图片后,在文字中补充说明图片的本地绝对路径:
|
|
264
|
+
> "请处理这张图片 `D:\\photos\\cat.jpg`,找出里面的猫"
|
|
265
|
+
|
|
266
|
+
2. **等待自动编码**:Claude 可能会自动将图片编码为 base64 传入。如果成功,无需额外操作。
|
|
267
|
+
|
|
268
|
+
3. **回答路径询问**:如果 Claude 询问图片路径,直接回复本地绝对路径即可。
|
|
269
|
+
|
|
270
|
+
### 三种输入方式有优先级吗?
|
|
271
|
+
|
|
272
|
+
没有严格优先级。Claude 会根据对话上下文自动选择最合适的方式:
|
|
273
|
+
|
|
274
|
+
- 你提供了本地路径 → 使用 `imagePath`
|
|
275
|
+
- 你提供了网络链接 → 使用 `imageUrl`
|
|
276
|
+
- 你拖拽了附件且没有路径 → 尝试 `imageBase64`
|
|
277
|
+
|
|
278
|
+
### 支持哪些图片格式?
|
|
279
|
+
|
|
280
|
+
支持常见格式:PNG、JPG、JPEG、BMP、WebP 等。建议优先使用 PNG 或 JPG。
|
|
281
|
+
|
|
282
|
+
### URL 图片下载失败怎么办?
|
|
283
|
+
|
|
284
|
+
确保 URL 是**公开可访问**的,不需要登录、Cookie 或签名。如果图片在需要身份验证的服务上(如私有 S3 Bucket、需要登录的图床),请先下载到本地再使用 `imagePath`。
|
|
285
|
+
|
|
286
|
+
### Base64 图片太大怎么办?
|
|
287
|
+
|
|
288
|
+
如果图片很大(如 4K 分辨率),base64 编码后的数据会非常大,可能导致传输变慢。建议:
|
|
289
|
+
|
|
290
|
+
1. 使用 `imagePath` 代替
|
|
291
|
+
2. 或先将图片压缩后再编码
|
|
292
|
+
|
|
293
|
+
## 文件上传说明
|
|
294
|
+
|
|
295
|
+
当 `type` 为 `"local"` 时,MCP Server 会:
|
|
296
|
+
1. 读取本地文件
|
|
297
|
+
2. 通过预签名 URL 直传到 TOS 对象存储
|
|
298
|
+
3. **最大文件大小:100MB**
|
|
299
|
+
|
|
300
|
+
## 故障排查
|
|
301
|
+
|
|
302
|
+
### "command not found: npx"
|
|
303
|
+
|
|
304
|
+
安装 Node.js >= 18:https://nodejs.org/
|
|
305
|
+
|
|
306
|
+
### "错误: 需要提供 --api-key 或设置 API_KEY"
|
|
307
|
+
|
|
308
|
+
API Key 缺失,请检查配置中的 `env.API_KEY`。
|
|
309
|
+
|
|
310
|
+
### MCP Server 在客户端显示红色/错误
|
|
311
|
+
|
|
312
|
+
查看日志:
|
|
313
|
+
- **Claude Desktop macOS**:`~/Library/Logs/Claude/mcp*.log`
|
|
314
|
+
- **Claude Desktop Windows**:`%APPDATA%\Claude\logs\mcp*.log`
|
|
315
|
+
- **Cursor**:Output 面板 > MCP
|
|
316
|
+
|
|
317
|
+
### "TOS 上传失败"
|
|
318
|
+
|
|
319
|
+
通常是签名不匹配,请确认 `HTTP_API_BASE_URL` 和 `HTTP_API_KEY` 正确且有效。
|
|
320
|
+
|
|
321
|
+
## 全局安装(可选)
|
|
322
|
+
|
|
323
|
+
如果你不想每次都用 `npx`:
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
npm install -g @avclabs.ai/media-mcp
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
然后在配置中使用 `"command": "media-mcp"` 配合 `"args": ["--api-key", "your-api-key"]` 。
|
|
330
|
+
|
|
331
|
+
## License
|
|
332
|
+
|
|
333
|
+
MIT License - 详见 [LICENSE](LICENSE) 文件
|
package/README_EN.md
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
# media-mcp (Node.js)
|
|
2
|
+
|
|
3
|
+
[中文](https://github.com/avclabs/media-mcp/blob/main/README.md) | English
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@avclabs.ai/media-mcp)
|
|
6
|
+
[](https://nodejs.org/)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
A video enhancement and image segmentation service based on the MCP protocol, acting as an MCP Client-Server to interact with backend HTTP Servers.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
Provides the following MCP Tools:
|
|
14
|
+
- `create_task` - Create a video enhancement task (supports URL or local file upload)
|
|
15
|
+
- `get_task_status` - Query task status
|
|
16
|
+
- `enhance_video_sync` - Synchronously enhance video (blocking wait)
|
|
17
|
+
- `sam3_predict` - SAM3 image segmentation (supports local path, URL, or Base64 image)
|
|
18
|
+
|
|
19
|
+
## Prerequisites
|
|
20
|
+
|
|
21
|
+
- **Node.js >= 18** (check: `node --version`)
|
|
22
|
+
- **API Key** (required for authentication)
|
|
23
|
+
|
|
24
|
+
## Lazy Install (Recommended)
|
|
25
|
+
|
|
26
|
+
If your AI Agent has a known MCP config path, just copy the line below and send it to your AI:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
Install the npm package @avclabs.ai/media-mcp as an MCP server. My API Key is: sk-xxxxxxxx.
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The AI will automatically:
|
|
33
|
+
1. Detect your MCP client
|
|
34
|
+
2. Find the config file path
|
|
35
|
+
3. Write the correct configuration
|
|
36
|
+
4. Prompt you to restart the client
|
|
37
|
+
|
|
38
|
+
## Manual Install
|
|
39
|
+
|
|
40
|
+
No installation needed. Use `npx` directly in your MCP client config.
|
|
41
|
+
|
|
42
|
+
### 1. Claude Code (CLI)
|
|
43
|
+
|
|
44
|
+
Run in Claude Code:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
/mcp
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Check the output for the **"User MCPs"** section to find the config file path, then edit that file.
|
|
51
|
+
|
|
52
|
+
Common paths (if `/mcp` is unavailable):
|
|
53
|
+
- **Windows**: `%USERPROFILE%\.claude.json`
|
|
54
|
+
- **macOS**: `~/.claude.json`
|
|
55
|
+
- **Linux**: `~/.claude.json`
|
|
56
|
+
- **Legacy/Alternative**: `~/.claude/mcp.json`
|
|
57
|
+
|
|
58
|
+
Paste this (replace `your-api-key`):
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"mcpServers": {
|
|
63
|
+
"video-enhancement": {
|
|
64
|
+
"command": "npx",
|
|
65
|
+
"args": ["-y", "@avclabs.ai/media-mcp@latest"],
|
|
66
|
+
"env": {
|
|
67
|
+
"API_KEY": "your-api-key"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Save and run `/mcp` to verify it's loaded.
|
|
75
|
+
|
|
76
|
+
### 2. Cursor
|
|
77
|
+
|
|
78
|
+
Go to **Settings > Tools & MCPs > Add New MCP Server**:
|
|
79
|
+
|
|
80
|
+
- **Name**: `video-enhancement`
|
|
81
|
+
- **Type**: `command`
|
|
82
|
+
- **Command**:
|
|
83
|
+
```bash
|
|
84
|
+
env HTTP_API_KEY=your-api-key npx -y @avclabs.ai/media-mcp@latest
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Or edit `~/.cursor/mcp.json`:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"mcpServers": {
|
|
92
|
+
"video-enhancement": {
|
|
93
|
+
"command": "npx",
|
|
94
|
+
"args": ["-y", "@avclabs.ai/media-mcp@latest"],
|
|
95
|
+
"env": {
|
|
96
|
+
"API_KEY": "your-api-key"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Verify Installation
|
|
104
|
+
|
|
105
|
+
After restarting your client, check if the tools are available:
|
|
106
|
+
|
|
107
|
+
1. Or ask: "What tools do you have available?"
|
|
108
|
+
2. You should see: `create_task`, `get_task_status`, `enhance_video_sync`, `sam3_predict`
|
|
109
|
+
|
|
110
|
+
## Configuration Options
|
|
111
|
+
|
|
112
|
+
| Variable | Required | Default | Description |
|
|
113
|
+
|---|---|---|---|
|
|
114
|
+
| `API_KEY` | **Yes** | - | API authentication key (shared by video enhancement and SAM3) |
|
|
115
|
+
| `HTTP_API_BASE_URL` | No | `https://mcp.avc.ai/enhance` | Video enhancement service endpoint |
|
|
116
|
+
| `SAM3_API_BASE_URL` | No | `https://mcp.avc.ai/sam` | SAM3 service endpoint |
|
|
117
|
+
| `SAM3_POLL_INTERVAL` | No | `2000` | Polling interval (milliseconds) |
|
|
118
|
+
| `SAM3_POLL_MAX_ATTEMPTS` | No | `60` | Maximum polling attempts |
|
|
119
|
+
|
|
120
|
+
### Custom Endpoint
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"env": {
|
|
125
|
+
"HTTP_API_BASE_URL": "https://your-endpoint.com",
|
|
126
|
+
"HTTP_API_KEY": "your-api-key"
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Or via CLI args:
|
|
132
|
+
```bash
|
|
133
|
+
npx -y @avclabs.ai/media-mcp@latest --base-url https://your-endpoint.com --api-key your-api-key --sam3-base-url http://localhost:8001 --sam3-api-key your-sam3-key
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Usage Examples
|
|
137
|
+
|
|
138
|
+
Once configured, ask your AI agent naturally:
|
|
139
|
+
|
|
140
|
+
> "Enhance this video to 1080p: https://example.com/video.mp4"
|
|
141
|
+
|
|
142
|
+
> "Improve the quality of /Users/me/Desktop/video.mp4 to 2k"
|
|
143
|
+
|
|
144
|
+
The agent will automatically call the appropriate tools.
|
|
145
|
+
|
|
146
|
+
> "Analyze this image and find all objects: C:\Users\xxx\photo.png"
|
|
147
|
+
>
|
|
148
|
+
> "Use SAM3 to segment this image, prompt: 'find all cars'"
|
|
149
|
+
|
|
150
|
+
## Provided Tools
|
|
151
|
+
|
|
152
|
+
### create_task
|
|
153
|
+
|
|
154
|
+
Create an asynchronous video enhancement task.
|
|
155
|
+
|
|
156
|
+
| Parameter | Type | Required | Default | Description |
|
|
157
|
+
|---|---|---|---|---|
|
|
158
|
+
| `video_source` | string | Yes | - | Video URL or local file path (URL must be publicly accessible, links requiring login or signatures are not supported) |
|
|
159
|
+
| `type` | string | No | `url` | `url` or `local` |
|
|
160
|
+
| `resolution` | string | No | `720p` | `480p`, `540p`, `720p`, `1080p`, `2k` |
|
|
161
|
+
|
|
162
|
+
**Returns:**
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"success": true,
|
|
166
|
+
"task_id": "xxx",
|
|
167
|
+
"status": "wait"
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### get_task_status
|
|
172
|
+
|
|
173
|
+
Query task status.
|
|
174
|
+
|
|
175
|
+
| Parameter | Type | Required |
|
|
176
|
+
|---|---|---|
|
|
177
|
+
| `task_id` | string | Yes |
|
|
178
|
+
|
|
179
|
+
**Returns:**
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"success": true,
|
|
183
|
+
"task_id": "xxx",
|
|
184
|
+
"status": "completed",
|
|
185
|
+
"progress": 100,
|
|
186
|
+
"video_url": "https://..."
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### enhance_video_sync
|
|
191
|
+
|
|
192
|
+
Synchronously enhance video (blocks until completion).
|
|
193
|
+
|
|
194
|
+
| Parameter | Type | Required | Default | Description |
|
|
195
|
+
|---|---|---|---|---|
|
|
196
|
+
| `video_source` | string | Yes | - | Video URL or local file path (URL must be publicly accessible, links requiring login or signatures are not supported) |
|
|
197
|
+
| `type` | string | No | `url` | `url` or `local` |
|
|
198
|
+
| `resolution` | string | No | `720p` | Target resolution |
|
|
199
|
+
| `poll_interval` | number | No | `5` | Poll interval (seconds) |
|
|
200
|
+
| `timeout` | number | No | `600` | Timeout (seconds) |
|
|
201
|
+
|
|
202
|
+
### sam3_predict
|
|
203
|
+
|
|
204
|
+
Analyze an image using the SAM3 segmentation API to generate inference results (masks, boxes, scores).
|
|
205
|
+
|
|
206
|
+
**Parameters:**
|
|
207
|
+
|
|
208
|
+
Image input (choose one, must provide exactly one):
|
|
209
|
+
|
|
210
|
+
- `imagePath` (string): Absolute path of a local image file. Supports common formats (PNG, JPG, JPEG, BMP, WebP).
|
|
211
|
+
- Example: `"C:\\Users\\xxx\\photo.png"`, `"/home/user/images/cat.jpg"`
|
|
212
|
+
- Use when: The user explicitly provides a local file path
|
|
213
|
+
|
|
214
|
+
- `imageUrl` (string): Publicly accessible URL of the image.
|
|
215
|
+
- Example: `"https://example.com/photo.jpg"`
|
|
216
|
+
- Use when: The image is already online and the user provides a link
|
|
217
|
+
- Note: The URL must be publicly accessible. Links requiring login or signatures are not supported
|
|
218
|
+
|
|
219
|
+
- `imageBase64` (string): Base64-encoded image data.
|
|
220
|
+
- Example: `"iVBORw0KGgoAAAANSUhEUgAA..."`
|
|
221
|
+
- Use when: The user drags or uploads an image attachment, and the Agent encodes it as base64
|
|
222
|
+
- Note: Large images will produce very large base64 strings, which may slow transmission
|
|
223
|
+
|
|
224
|
+
Other parameters:
|
|
225
|
+
|
|
226
|
+
- `prompt` (string, required): English text prompt specifying the target object to segment. Examples: `"person"`, `"car"`, `"a cat sitting on a sofa"`. Since the SAM3 model only accepts English prompts, provide an English description. If the user provides Chinese or other non-English text, the Agent will automatically translate it before calling the tool.
|
|
227
|
+
|
|
228
|
+
**Returns:**
|
|
229
|
+
|
|
230
|
+
After inference completes, returns a JSON string containing three fields:
|
|
231
|
+
|
|
232
|
+
- **`masks`**: 2D array. Each element is a binary mask (values 0 or 1) with the same dimensions as the input image, marking the pixel-level location of detected objects. The i-th mask corresponds to the i-th detected object instance.
|
|
233
|
+
- **`boxes`**: 2D array. Each element is a bounding box in `[x1, y1, x2, y2]` format, representing the rectangular region of the detected object. `x1`, `y1` are the top-left coordinates; `x2`, `y2` are the bottom-right coordinates.
|
|
234
|
+
|
|
235
|
+
Coordinate system: The top-left corner of the image is the origin `(0, 0)`. The x-axis increases to the right, and the y-axis increases downward, in pixels. For example, `[120, 80, 300, 450]` means the region starts 120px from the left edge and 80px from the top edge, extending to 300px from the left and 450px from the top. Width = `x2 - x1 = 180px`, Height = `y2 - y1 = 370px`.
|
|
236
|
+
- **`scores`**: 1D array. Each element is a confidence score for the corresponding detection result, ranging from 0 to 1. Higher scores indicate greater model confidence.
|
|
237
|
+
|
|
238
|
+
Example result JSON:
|
|
239
|
+
|
|
240
|
+
```json
|
|
241
|
+
{
|
|
242
|
+
"masks": [
|
|
243
|
+
[[0, 0, 1, ...], [0, 1, 1, ...], ...],
|
|
244
|
+
[[0, 0, 0, ...], [0, 0, 1, ...], ...]
|
|
245
|
+
],
|
|
246
|
+
"boxes": [
|
|
247
|
+
[120, 80, 300, 450],
|
|
248
|
+
[400, 200, 600, 500]
|
|
249
|
+
],
|
|
250
|
+
"scores": [0.95, 0.87]
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## FAQ
|
|
255
|
+
|
|
256
|
+
### Drag-and-drop attachment says file not found?
|
|
257
|
+
|
|
258
|
+
This is a known limitation of stdio MCP. When dragging or uploading an attachment through the Agent interface, the file path is usually not automatically passed to the MCP Server.
|
|
259
|
+
|
|
260
|
+
**Solutions:**
|
|
261
|
+
|
|
262
|
+
1. **Provide the path simultaneously** (recommended): After dragging the image,补充 the local absolute path in your message:
|
|
263
|
+
> "Please analyze this image `D:\\photos\\cat.jpg` and find the cat"
|
|
264
|
+
|
|
265
|
+
2. **Wait for auto-encoding**: Claude may automatically encode the image as base64. If successful, no extra action is needed.
|
|
266
|
+
|
|
267
|
+
3. **Reply to path inquiry**: If Claude asks for the image path, simply reply with the local absolute path.
|
|
268
|
+
|
|
269
|
+
### Is there a priority among the three input methods?
|
|
270
|
+
|
|
271
|
+
There is no strict priority. Claude will automatically choose the most appropriate method based on conversation context:
|
|
272
|
+
|
|
273
|
+
- You provided a local path → uses `imagePath`
|
|
274
|
+
- You provided a web link → uses `imageUrl`
|
|
275
|
+
- You dragged an attachment without a path → tries `imageBase64`
|
|
276
|
+
|
|
277
|
+
### What image formats are supported?
|
|
278
|
+
|
|
279
|
+
Common formats: PNG, JPG, JPEG, BMP, WebP, etc. PNG or JPG is recommended.
|
|
280
|
+
|
|
281
|
+
### What if URL image download fails?
|
|
282
|
+
|
|
283
|
+
Ensure the URL is **publicly accessible**, requiring no login, cookies, or signatures. If the image is on a service requiring authentication (e.g., private S3 Bucket, login-required image host), download it locally first and use `imagePath`.
|
|
284
|
+
|
|
285
|
+
### What if the base64 image is too large?
|
|
286
|
+
|
|
287
|
+
If the image is very large (e.g., 4K resolution), the base64-encoded data will be very large and may slow transmission. Suggestions:
|
|
288
|
+
|
|
289
|
+
1. Use `imagePath` instead
|
|
290
|
+
2. Or compress the image before encoding
|
|
291
|
+
|
|
292
|
+
## File Upload Notes
|
|
293
|
+
|
|
294
|
+
When `type` is `"local"`:
|
|
295
|
+
1. File is read locally by the MCP Server
|
|
296
|
+
2. Uploaded directly to TOS object storage via pre-signed URL
|
|
297
|
+
3. **Max file size: 100MB**
|
|
298
|
+
|
|
299
|
+
## Troubleshooting
|
|
300
|
+
|
|
301
|
+
### "command not found: npx"
|
|
302
|
+
|
|
303
|
+
Install Node.js >= 18: https://nodejs.org/
|
|
304
|
+
|
|
305
|
+
### "Error:需要提供 --api-key 或设置 HTTP_API_KEY"
|
|
306
|
+
|
|
307
|
+
Your API Key is missing. Double-check the `env.HTTP_API_KEY` in your config.
|
|
308
|
+
|
|
309
|
+
### MCP Server shows red/error in client
|
|
310
|
+
|
|
311
|
+
Check logs:
|
|
312
|
+
- **Claude Desktop macOS**: `~/Library/Logs/Claude/mcp*.log`
|
|
313
|
+
- **Claude Desktop Windows**: `%APPDATA%\Claude\logs\mcp*.log`
|
|
314
|
+
- **Cursor**: Output panel > MCP
|
|
315
|
+
|
|
316
|
+
### "TOS 上传失败"
|
|
317
|
+
|
|
318
|
+
Usually a signature mismatch. Ensure your `HTTP_API_BASE_URL` and `HTTP_API_KEY` are correct and active.
|
|
319
|
+
|
|
320
|
+
## Global Install (Alternative)
|
|
321
|
+
|
|
322
|
+
If you prefer not using `npx` every time:
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
npm install -g @avclabs.ai/media-mcp
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Then use `"command": "media-mcp"` with `"args": ["--api-key", "your-api-key"]` in your config.
|
|
329
|
+
|
|
330
|
+
## License
|
|
331
|
+
|
|
332
|
+
MIT License - See [LICENSE](LICENSE) file for details
|
package/config.json
ADDED
package/dist/sam3.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sam3.d.ts","sourceRoot":"","sources":["../src/sam3.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAcpE,wBAAgB,cAAc,CAC5B,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,MAAM,GACtB,IAAI,CAsCN"}
|
package/dist/sam3.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import FormData from 'form-data';
|
|
6
|
+
const Sam3PredictSchema = z.object({
|
|
7
|
+
imagePath: z.string().optional().describe('Absolute path of a local image file (e.g. C:\\\\Users\\\\xxx\\\\photo.png)'),
|
|
8
|
+
imageUrl: z.string().url().optional().describe('Publicly accessible URL of the image to process'),
|
|
9
|
+
imageBase64: z.string().optional().describe('Base64-encoded image data. Use this when the image is provided as an attachment without a local path'),
|
|
10
|
+
prompt: z.string().describe('Text prompt for mask generation. Must be in English. If the user provides Chinese or other non-English text, translate it to English before calling this tool'),
|
|
11
|
+
});
|
|
12
|
+
export function setupSam3Tools(server, baseUrl, apiKey, pollInterval, pollMaxAttempts) {
|
|
13
|
+
const client = axios.create({
|
|
14
|
+
baseURL: baseUrl.replace(/\/$/, ''),
|
|
15
|
+
headers: {
|
|
16
|
+
'X-API-Key': apiKey,
|
|
17
|
+
'Content-Type': 'application/json',
|
|
18
|
+
},
|
|
19
|
+
timeout: 60000,
|
|
20
|
+
});
|
|
21
|
+
server.tool('sam3_predict', `Analyze an image using the SAM3 segmentation API to generate inference results (masks, boxes, scores).
|
|
22
|
+
The image can be provided in one of three ways:
|
|
23
|
+
1. imagePath: Absolute path of a local image file (e.g. C:\\Users\\xxx\\photo.png). Use this when the user provides a local file path.
|
|
24
|
+
2. imageUrl: Publicly accessible URL of the image (e.g. https://example.com/photo.jpg). Use this when the user provides a web link.
|
|
25
|
+
3. imageBase64: Base64-encoded image data. Use this when the user uploads or drags-and-drops an image as an attachment and no local path is available.
|
|
26
|
+
In this case, encode the image content as base64 and pass it via this parameter.
|
|
27
|
+
If the user mentions an uploaded image but does not provide a path, URL, or base64 data, ask the user for the local absolute path.
|
|
28
|
+
Prompt must be in English. If the user provides Chinese or other non-English text, translate it to English before calling this tool.`, Sam3PredictSchema.shape, async (args) => {
|
|
29
|
+
try {
|
|
30
|
+
if (!apiKey) {
|
|
31
|
+
throw new Error('SAM3 API Key not configured. Please set API_KEY environment variable or --api-key argument.');
|
|
32
|
+
}
|
|
33
|
+
const result = await sam3PredictTool(client, pollInterval, pollMaxAttempts, args);
|
|
34
|
+
return {
|
|
35
|
+
content: [{ type: 'text', text: result }],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
40
|
+
return {
|
|
41
|
+
content: [{ type: 'text', text: JSON.stringify({ success: false, error: errorMessage }, null, 2) }],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
async function getSam3PostSignature(client, fileName) {
|
|
47
|
+
const response = await client.post('/get_postsignature_url', {
|
|
48
|
+
file_type: 'image',
|
|
49
|
+
file_name: fileName,
|
|
50
|
+
});
|
|
51
|
+
const data = response.data;
|
|
52
|
+
if (data.code !== 0) {
|
|
53
|
+
throw new Error(`get_postsignature_url error: ${data.message || 'unknown error'}`);
|
|
54
|
+
}
|
|
55
|
+
return data.data;
|
|
56
|
+
}
|
|
57
|
+
async function uploadImageToTos(url, sigData, tosKey, buffer, fileName) {
|
|
58
|
+
const formData = new FormData();
|
|
59
|
+
formData.append('key', tosKey);
|
|
60
|
+
formData.append('policy', sigData.policy);
|
|
61
|
+
formData.append('x-tos-algorithm', sigData.algorithm);
|
|
62
|
+
formData.append('x-tos-credential', sigData.credential);
|
|
63
|
+
formData.append('x-tos-date', sigData.date);
|
|
64
|
+
formData.append('x-tos-signature', sigData.signature);
|
|
65
|
+
formData.append('file', buffer, fileName);
|
|
66
|
+
const response = await axios.post(url, formData, {
|
|
67
|
+
headers: formData.getHeaders(),
|
|
68
|
+
maxBodyLength: Infinity,
|
|
69
|
+
maxContentLength: Infinity,
|
|
70
|
+
});
|
|
71
|
+
if (response.status >= 400) {
|
|
72
|
+
throw new Error(`TOS upload failed: ${response.status} ${response.statusText}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function sam3Predict(client, fileId, prompt) {
|
|
76
|
+
const response = await client.post('/predict', { file_id: fileId, prompt });
|
|
77
|
+
return response.data.task_id;
|
|
78
|
+
}
|
|
79
|
+
async function getSam3PredictResult(client, taskId, pollInterval, pollMaxAttempts) {
|
|
80
|
+
for (let attempt = 0; attempt < pollMaxAttempts; attempt++) {
|
|
81
|
+
const response = await client.get(`/predict/result/${encodeURIComponent(taskId)}`);
|
|
82
|
+
const data = response.data;
|
|
83
|
+
if (data.status === 'completed') {
|
|
84
|
+
return data;
|
|
85
|
+
}
|
|
86
|
+
if (data.status === 'failed') {
|
|
87
|
+
throw new Error(`Task failed: ${data.error_message || 'unknown error'}`);
|
|
88
|
+
}
|
|
89
|
+
await sleep(pollInterval);
|
|
90
|
+
}
|
|
91
|
+
throw new Error('Polling timeout: task did not complete in time');
|
|
92
|
+
}
|
|
93
|
+
async function downloadSam3Result(url) {
|
|
94
|
+
const response = await axios.get(url);
|
|
95
|
+
return response.data;
|
|
96
|
+
}
|
|
97
|
+
async function sam3PredictTool(client, pollInterval, pollMaxAttempts, args) {
|
|
98
|
+
const { imagePath, imageUrl, imageBase64, prompt } = args;
|
|
99
|
+
if (!imagePath && !imageUrl && !imageBase64) {
|
|
100
|
+
throw new Error('Missing image input: must provide one of imagePath, imageUrl, or imageBase64');
|
|
101
|
+
}
|
|
102
|
+
if (!prompt) {
|
|
103
|
+
throw new Error('Missing argument: prompt');
|
|
104
|
+
}
|
|
105
|
+
let buffer;
|
|
106
|
+
let fileName;
|
|
107
|
+
if (imagePath) {
|
|
108
|
+
if (!fs.existsSync(imagePath)) {
|
|
109
|
+
throw new Error(`Local file does not exist: ${imagePath}`);
|
|
110
|
+
}
|
|
111
|
+
fileName = path.basename(imagePath);
|
|
112
|
+
buffer = fs.readFileSync(imagePath);
|
|
113
|
+
}
|
|
114
|
+
else if (imageUrl) {
|
|
115
|
+
const response = await axios.get(imageUrl, { responseType: 'arraybuffer' });
|
|
116
|
+
buffer = Buffer.from(response.data);
|
|
117
|
+
fileName = path.basename(new URL(imageUrl).pathname) || 'image.png';
|
|
118
|
+
}
|
|
119
|
+
else if (imageBase64) {
|
|
120
|
+
buffer = Buffer.from(imageBase64, 'base64');
|
|
121
|
+
fileName = 'image.png';
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
throw new Error('Missing image input: must provide one of imagePath, imageUrl, or imageBase64');
|
|
125
|
+
}
|
|
126
|
+
// Step 1: Get post signature
|
|
127
|
+
const signatureData = await getSam3PostSignature(client, fileName);
|
|
128
|
+
const { url, origin_policy } = signatureData;
|
|
129
|
+
if (!url) {
|
|
130
|
+
throw new Error('Missing upload URL in post signature response');
|
|
131
|
+
}
|
|
132
|
+
// Parse key from origin_policy
|
|
133
|
+
const keyObj = JSON.parse(origin_policy).conditions.find((c) => 'key' in c);
|
|
134
|
+
const tosKey = keyObj ? keyObj.key : new URL(url).pathname.slice(1);
|
|
135
|
+
// Parse file_id from url path
|
|
136
|
+
const fileId = new URL(url).pathname.split('/').pop();
|
|
137
|
+
if (!fileId) {
|
|
138
|
+
throw new Error('Could not extract file_id from upload URL');
|
|
139
|
+
}
|
|
140
|
+
// Step 2: Upload to TOS
|
|
141
|
+
await uploadImageToTos(url, signatureData, tosKey, buffer, fileName);
|
|
142
|
+
// Step 3: Create predict task
|
|
143
|
+
const taskId = await sam3Predict(client, fileId, prompt);
|
|
144
|
+
// Step 4: Poll for result
|
|
145
|
+
const taskResult = await getSam3PredictResult(client, taskId, pollInterval, pollMaxAttempts);
|
|
146
|
+
// Step 5: Download result JSON and return as string
|
|
147
|
+
const resultUrl = taskResult.result;
|
|
148
|
+
const resultJson = await downloadSam3Result(resultUrl);
|
|
149
|
+
return JSON.stringify(resultJson, null, 2);
|
|
150
|
+
}
|
|
151
|
+
function sleep(ms) {
|
|
152
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=sam3.js.map
|
package/dist/sam3.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sam3.js","sourceRoot":"","sources":["../src/sam3.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA;;GAEG"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MCP Server - 提供视频增强和 SAM3 图像分割功能
|
|
4
|
+
*/
|
|
5
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
6
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import { setupVideoEnhancementTools } from './video-enhancement.js';
|
|
11
|
+
import { setupSam3Tools } from './sam3.js';
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = path.dirname(__filename);
|
|
14
|
+
function loadConfig() {
|
|
15
|
+
const configPaths = [
|
|
16
|
+
path.resolve(process.cwd(), 'config.json'),
|
|
17
|
+
path.resolve(__dirname, '..', 'config.json'),
|
|
18
|
+
];
|
|
19
|
+
for (const configPath of configPaths) {
|
|
20
|
+
if (fs.existsSync(configPath)) {
|
|
21
|
+
try {
|
|
22
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
23
|
+
return {
|
|
24
|
+
baseUrl: config.baseUrl || 'https://mcp.avc.ai/enhance',
|
|
25
|
+
sam3BaseUrl: config.sam3BaseUrl || 'https://mcp.avc.ai/sam',
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return { baseUrl: 'https://mcp.avc.ai/enhance', sam3BaseUrl: 'https://mcp.avc.ai/sam' };
|
|
34
|
+
}
|
|
35
|
+
// 主入口
|
|
36
|
+
async function main() {
|
|
37
|
+
const args = process.argv.slice(2);
|
|
38
|
+
const config = loadConfig();
|
|
39
|
+
let baseUrl = process.env.HTTP_API_BASE_URL || config.baseUrl;
|
|
40
|
+
let apiKey = process.env.API_KEY || '';
|
|
41
|
+
let sam3BaseUrl = process.env.SAM3_API_BASE_URL || config.sam3BaseUrl;
|
|
42
|
+
let sam3ApiKey = apiKey;
|
|
43
|
+
let sam3PollInterval = parseInt(process.env.SAM3_POLL_INTERVAL || '2000', 10);
|
|
44
|
+
let sam3PollMaxAttempts = parseInt(process.env.SAM3_POLL_MAX_ATTEMPTS || '60', 10);
|
|
45
|
+
// 解析命令行参数
|
|
46
|
+
for (let i = 0; i < args.length; i++) {
|
|
47
|
+
if (args[i] === '--base-url' && i + 1 < args.length) {
|
|
48
|
+
baseUrl = args[i + 1];
|
|
49
|
+
i++;
|
|
50
|
+
}
|
|
51
|
+
else if (args[i] === '--api-key' && i + 1 < args.length) {
|
|
52
|
+
apiKey = args[i + 1];
|
|
53
|
+
i++;
|
|
54
|
+
}
|
|
55
|
+
else if (args[i] === '--sam3-base-url' && i + 1 < args.length) {
|
|
56
|
+
sam3BaseUrl = args[i + 1];
|
|
57
|
+
i++;
|
|
58
|
+
}
|
|
59
|
+
else if (args[i] === '--sam3-poll-interval' && i + 1 < args.length) {
|
|
60
|
+
sam3PollInterval = parseInt(args[i + 1], 10);
|
|
61
|
+
i++;
|
|
62
|
+
}
|
|
63
|
+
else if (args[i] === '--sam3-poll-max-attempts' && i + 1 < args.length) {
|
|
64
|
+
sam3PollMaxAttempts = parseInt(args[i + 1], 10);
|
|
65
|
+
i++;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (!apiKey) {
|
|
69
|
+
console.error('错误: 需要提供 --api-key 或设置 API_KEY 环境变量');
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
const server = new McpServer({
|
|
73
|
+
name: 'media-mcp',
|
|
74
|
+
version: '0.3.0',
|
|
75
|
+
}, {
|
|
76
|
+
capabilities: {
|
|
77
|
+
tools: {},
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
// 注册视频增强 tools
|
|
81
|
+
setupVideoEnhancementTools(server, baseUrl, apiKey);
|
|
82
|
+
// 注册 SAM3 tools
|
|
83
|
+
setupSam3Tools(server, sam3BaseUrl, sam3ApiKey, sam3PollInterval, sam3PollMaxAttempts);
|
|
84
|
+
const transport = new StdioServerTransport();
|
|
85
|
+
await server.connect(transport);
|
|
86
|
+
console.error('MCP Server running on stdio');
|
|
87
|
+
}
|
|
88
|
+
main().catch((error) => {
|
|
89
|
+
console.error('Server error:', error);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
});
|
|
92
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-enhancement.d.ts","sourceRoot":"","sources":["../src/video-enhancement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA0BpE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAgGnG"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import FormData from 'form-data';
|
|
6
|
+
// Schemas
|
|
7
|
+
const CreateTaskSchema = z.object({
|
|
8
|
+
video_source: z.string().describe('视频URL地址或本地文件路径(URL必须公网可访问,不支持需要登录或签名的链接)'),
|
|
9
|
+
type: z.enum(['url', 'local']).default('url').describe('上传类型:url=网络视频,local=本地文件'),
|
|
10
|
+
resolution: z.enum(['480p', '540p', '720p', '1080p', '2k']).default('720p').describe('目标分辨率,默认720p'),
|
|
11
|
+
});
|
|
12
|
+
const GetTaskStatusSchema = z.object({
|
|
13
|
+
task_id: z.string().describe('任务ID'),
|
|
14
|
+
});
|
|
15
|
+
const EnhanceVideoSyncSchema = z.object({
|
|
16
|
+
video_source: z.string().describe('视频URL地址或本地文件路径(URL必须公网可访问,不支持需要登录或签名的链接)'),
|
|
17
|
+
type: z.enum(['url', 'local']).default('url').describe('上传类型:url=网络视频,local=本地文件'),
|
|
18
|
+
resolution: z.enum(['480p', '540p', '720p', '1080p', '2k']).default('720p').describe('目标分辨率,默认720p'),
|
|
19
|
+
poll_interval: z.number().default(5).describe('轮询间隔(秒),默认5'),
|
|
20
|
+
timeout: z.number().default(600).describe('超时时间(秒),默认600'),
|
|
21
|
+
});
|
|
22
|
+
export function setupVideoEnhancementTools(server, baseUrl, apiKey) {
|
|
23
|
+
const client = axios.create({
|
|
24
|
+
baseURL: baseUrl.replace(/\/$/, ''),
|
|
25
|
+
headers: {
|
|
26
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
27
|
+
'Content-Type': 'application/json',
|
|
28
|
+
},
|
|
29
|
+
timeout: 60000,
|
|
30
|
+
});
|
|
31
|
+
// create_task tool
|
|
32
|
+
server.tool('create_task', `创建视频增强任务(异步)
|
|
33
|
+
|
|
34
|
+
支持两种上传方式:
|
|
35
|
+
1. URL 上传:提供视频 URL
|
|
36
|
+
2. 本地上传:提供本地文件路径,MCP Server 自动上传到 TOS 对象存储
|
|
37
|
+
|
|
38
|
+
参数说明:
|
|
39
|
+
- video_source: 视频 URL 或本地文件路径
|
|
40
|
+
- type: "url" 或 "local"
|
|
41
|
+
- resolution: 目标分辨率`, CreateTaskSchema.shape, async (args) => {
|
|
42
|
+
try {
|
|
43
|
+
const result = await createTask(client, args.video_source, args.type, args.resolution);
|
|
44
|
+
return {
|
|
45
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
50
|
+
return {
|
|
51
|
+
content: [{ type: 'text', text: JSON.stringify({ success: false, error: errorMessage }, null, 2) }],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
// get_task_status tool
|
|
56
|
+
server.tool('get_task_status', '查询视频增强任务状态', GetTaskStatusSchema.shape, async (args) => {
|
|
57
|
+
try {
|
|
58
|
+
const result = await getTaskStatus(client, args.task_id);
|
|
59
|
+
return {
|
|
60
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
65
|
+
return {
|
|
66
|
+
content: [{ type: 'text', text: JSON.stringify({ success: false, error: errorMessage }, null, 2) }],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
// enhance_video_sync tool
|
|
71
|
+
server.tool('enhance_video_sync', `同步增强视频(阻塞等待完成)
|
|
72
|
+
|
|
73
|
+
支持两种上传方式:
|
|
74
|
+
1. URL 上传:提供视频 URL
|
|
75
|
+
2. 本地上传:提供本地文件路径,MCP Server 自动上传到 TOS 对象存储
|
|
76
|
+
|
|
77
|
+
参数说明:
|
|
78
|
+
- video_source: 视频 URL 或本地文件路径
|
|
79
|
+
- type: "url" 或 "local"
|
|
80
|
+
- resolution: 目标分辨率
|
|
81
|
+
- poll_interval: 轮询间隔(秒)
|
|
82
|
+
- timeout: 超时时间(秒)`, EnhanceVideoSyncSchema.shape, async (args) => {
|
|
83
|
+
try {
|
|
84
|
+
const result = await enhanceVideoSync(client, args.video_source, args.type, args.resolution, args.poll_interval, args.timeout);
|
|
85
|
+
return {
|
|
86
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
91
|
+
return {
|
|
92
|
+
content: [{ type: 'text', text: JSON.stringify({ success: false, error: errorMessage }, null, 2) }],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function checkLocalFile(filePath) {
|
|
98
|
+
if (!fs.existsSync(filePath)) {
|
|
99
|
+
throw new Error(`文件不存在: ${filePath}`);
|
|
100
|
+
}
|
|
101
|
+
const stats = fs.statSync(filePath);
|
|
102
|
+
const maxSize = 100 * 1024 * 1024;
|
|
103
|
+
if (stats.size > maxSize) {
|
|
104
|
+
throw new Error('文件大小超过 100MB 限制');
|
|
105
|
+
}
|
|
106
|
+
return { filePath, fileName: path.basename(filePath) };
|
|
107
|
+
}
|
|
108
|
+
async function getTosSignature(client, fileName) {
|
|
109
|
+
const response = await client.post('/api/v3/contents/generations/tos-signature', {
|
|
110
|
+
file_type: 'video',
|
|
111
|
+
file_name: fileName,
|
|
112
|
+
});
|
|
113
|
+
const data = response.data;
|
|
114
|
+
if (data.code !== 0 && data.code !== 200) {
|
|
115
|
+
throw new Error(data.message || '获取 TOS 签名失败');
|
|
116
|
+
}
|
|
117
|
+
return data.data;
|
|
118
|
+
}
|
|
119
|
+
async function uploadToTos(filePath, signatureData) {
|
|
120
|
+
const formData = new FormData();
|
|
121
|
+
const objectKey = decodeURIComponent(new URL(signatureData.url).pathname.slice(1));
|
|
122
|
+
formData.append('key', objectKey);
|
|
123
|
+
const fieldMapping = {
|
|
124
|
+
algorithm: 'x-tos-algorithm',
|
|
125
|
+
credential: 'x-tos-credential',
|
|
126
|
+
date: 'x-tos-date',
|
|
127
|
+
signature: 'x-tos-signature',
|
|
128
|
+
};
|
|
129
|
+
for (const [key, value] of Object.entries(signatureData)) {
|
|
130
|
+
if (key === 'url' || key === 'origin_policy')
|
|
131
|
+
continue;
|
|
132
|
+
const formKey = fieldMapping[key] || key;
|
|
133
|
+
formData.append(formKey, String(value));
|
|
134
|
+
}
|
|
135
|
+
const fileName = path.basename(filePath);
|
|
136
|
+
formData.append('file', fs.createReadStream(filePath), fileName);
|
|
137
|
+
const response = await axios.post(signatureData.url, formData, {
|
|
138
|
+
headers: formData.getHeaders(),
|
|
139
|
+
maxBodyLength: Infinity,
|
|
140
|
+
maxContentLength: Infinity,
|
|
141
|
+
});
|
|
142
|
+
if (response.status >= 400) {
|
|
143
|
+
const debugInfo = JSON.stringify({
|
|
144
|
+
status: response.status,
|
|
145
|
+
statusText: response.statusText,
|
|
146
|
+
data: response.data,
|
|
147
|
+
url: signatureData.url,
|
|
148
|
+
signatureFields: Object.keys(signatureData),
|
|
149
|
+
fileName,
|
|
150
|
+
fileSize: fs.statSync(filePath).size,
|
|
151
|
+
}, null, 2);
|
|
152
|
+
throw new Error(`TOS 上传失败: ${response.status} ${response.statusText}\n调试信息: ${debugInfo}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function parseFileIdFromUrl(url) {
|
|
156
|
+
const pathname = new URL(url).pathname;
|
|
157
|
+
const segments = pathname.split('/');
|
|
158
|
+
return decodeURIComponent(segments.pop() || '');
|
|
159
|
+
}
|
|
160
|
+
async function createTask(client, videoSource, sourceType, resolution) {
|
|
161
|
+
let contentItem;
|
|
162
|
+
if (sourceType === 'local') {
|
|
163
|
+
const fileInfo = checkLocalFile(videoSource);
|
|
164
|
+
const signatureData = await getTosSignature(client, fileInfo.fileName);
|
|
165
|
+
await uploadToTos(videoSource, signatureData);
|
|
166
|
+
const fileId = parseFileIdFromUrl(signatureData.url);
|
|
167
|
+
contentItem = { type: 'video_file', file_id: fileId, file_name: fileInfo.fileName };
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
contentItem = { type: 'video_url', video_url: { url: videoSource } };
|
|
171
|
+
}
|
|
172
|
+
const payload = { model: 'avc-enhance', content: [contentItem], resolution };
|
|
173
|
+
const response = await client.post('/api/v3/contents/generations/tasks', payload);
|
|
174
|
+
const data = response.data;
|
|
175
|
+
if (data.code !== 0 && data.code !== 200) {
|
|
176
|
+
return { success: false, error: data.message };
|
|
177
|
+
}
|
|
178
|
+
return { success: true, task_id: data.data.task_id, status: data.data.status };
|
|
179
|
+
}
|
|
180
|
+
async function getTaskStatus(client, taskId) {
|
|
181
|
+
const response = await client.get(`/api/v3/contents/generations/tasks/${taskId}`);
|
|
182
|
+
const data = response.data;
|
|
183
|
+
if (data.code !== 0 && data.code !== 200) {
|
|
184
|
+
return { success: false, error: data.message };
|
|
185
|
+
}
|
|
186
|
+
const result = data.data;
|
|
187
|
+
return {
|
|
188
|
+
success: true,
|
|
189
|
+
task_id: result.task_id,
|
|
190
|
+
status: result.status,
|
|
191
|
+
progress: result.progress || 0,
|
|
192
|
+
video_url: result.video_url,
|
|
193
|
+
debug_video_url_length: result.video_url?.length,
|
|
194
|
+
debug_video_url_full: result.video_url,
|
|
195
|
+
error_message: result.error_message,
|
|
196
|
+
created_at: result.created_at,
|
|
197
|
+
updated_at: result.updated_at,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
async function enhanceVideoSync(client, videoSource, sourceType, resolution, pollInterval, timeout) {
|
|
201
|
+
const createResult = await createTask(client, videoSource, sourceType, resolution);
|
|
202
|
+
if (!createResult.success) {
|
|
203
|
+
return createResult;
|
|
204
|
+
}
|
|
205
|
+
const taskId = createResult.task_id;
|
|
206
|
+
const startTime = Date.now();
|
|
207
|
+
while (true) {
|
|
208
|
+
const status = await getTaskStatus(client, taskId);
|
|
209
|
+
if (!status.success) {
|
|
210
|
+
return status;
|
|
211
|
+
}
|
|
212
|
+
if (status.status === 'completed' || status.status === 'failed') {
|
|
213
|
+
return status;
|
|
214
|
+
}
|
|
215
|
+
const elapsed = (Date.now() - startTime) / 1000;
|
|
216
|
+
if (elapsed >= timeout) {
|
|
217
|
+
return { success: false, error: `任务超时: ${taskId}`, task_id: taskId };
|
|
218
|
+
}
|
|
219
|
+
await sleep(pollInterval * 1000);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
function sleep(ms) {
|
|
223
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=video-enhancement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-enhancement.js","sourceRoot":"","sources":["../src/video-enhancement.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "module",
|
|
3
|
+
"name": "@avclabs.ai/media-mcp",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "MCP Server for video enhancement and image segmentation (SAM3)",
|
|
6
|
+
"mcpName": "io.github.avclabs/media-mcp",
|
|
7
|
+
"main": "dist/server.js",
|
|
8
|
+
"types": "dist/server.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"media-mcp": "dist/server.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"config.json",
|
|
15
|
+
"LICENSE",
|
|
16
|
+
"README.md",
|
|
17
|
+
"README_EN.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"dev": "tsc --watch",
|
|
22
|
+
"prepare": "npm run build",
|
|
23
|
+
"prepublishOnly": "npm run build"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"mcp",
|
|
27
|
+
"model-context-protocol",
|
|
28
|
+
"video",
|
|
29
|
+
"enhancement",
|
|
30
|
+
"http",
|
|
31
|
+
"client",
|
|
32
|
+
"server",
|
|
33
|
+
"claude",
|
|
34
|
+
"anthropic"
|
|
35
|
+
],
|
|
36
|
+
"author": "Your Name <your.email@example.com>",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/avclabs/media-mcp.git"
|
|
41
|
+
},
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/avclabs/media-mcp/issues"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/avclabs/media-mcp#readme",
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
48
|
+
"axios": "^1.7.0",
|
|
49
|
+
"form-data": "^4.0.5",
|
|
50
|
+
"zod": "^3.23.0"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/node": "^20.0.0",
|
|
54
|
+
"typescript": "^5.4.0"
|
|
55
|
+
},
|
|
56
|
+
"mcpServer": {
|
|
57
|
+
"command": "npx",
|
|
58
|
+
"args": [
|
|
59
|
+
"-y",
|
|
60
|
+
"@avclabs.ai/media-mcp@latest"
|
|
61
|
+
],
|
|
62
|
+
"env": {
|
|
63
|
+
"API_KEY": "your-api-key",
|
|
64
|
+
"HTTP_API_BASE_URL": "https://mcp.avc.ai/enhance",
|
|
65
|
+
"SAM3_API_BASE_URL": "https://mcp.avc.ai/sam"
|
|
66
|
+
},
|
|
67
|
+
"description": "视频增强 + SAM3 图像分割 MCP 服务",
|
|
68
|
+
"setup": "需要替换 env.API_KEY 为你的 API Key"
|
|
69
|
+
},
|
|
70
|
+
"engines": {
|
|
71
|
+
"node": ">=18.0.0"
|
|
72
|
+
}
|
|
73
|
+
}
|