@avclabs.ai/media-mcp 0.2.1 → 0.3.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/README_CN.md CHANGED
@@ -6,7 +6,9 @@
6
6
  [![Node.js >=18](https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg)](https://nodejs.org/)
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
8
 
9
- 基于 MCP 协议的视频增强与图像分割服务,作为 MCP Client-Server 与后端 HTTP Server 交互。
9
+ 基于 MCP 协议的视频增强、图片增强/上色/降噪与图像分割服务,作为 MCP Client-Server 与后端 HTTP Server 交互。
10
+
11
+ > **发布状态**:当前 npm `latest`(`0.2.1`)包含 3 个视频工具和 2 个 SAM3 工具。图片增强工具正在积极开发中,将在后续版本发布——下文已提前列出供尝鲜参考,但目前尚不包含在已发布的 npm 包中。
10
12
 
11
13
  ## 功能
12
14
 
@@ -15,10 +17,17 @@
15
17
  **视频增强**
16
18
  - `create_task` - 创建视频增强任务(支持 URL 或本地文件上传)
17
19
  - `get_task_status` - 查询任务状态
18
- - `enhance_video_sync` - 同步增强视频(阻塞等待,默认50秒截断)
20
+ - `enhance_video_sync` - 同步增强视频(阻塞等待,默认45秒截断)
21
+
22
+ **图片增强(即将发布,暂不含于已发布的 npm 包)**
23
+ - `enhance_image_sync` - 图片画质增强与人脸优化(支持 URL 或本地文件上传)
24
+ - `colorize_image_sync` - 黑白照片上色(支持 URL 或本地文件上传)
25
+ - `denoise_image_sync` - 图片降噪去噪(支持 URL 或本地文件上传)
26
+ - `get_image_task_status` - 查询图片任务状态(同步工具超时后用于轮询)
19
27
 
20
28
  **图像分割 (SAM3)**
21
29
  - `sam3_predict` - SAM3 图像分割(支持本地路径、URL 或 Base64 图片)
30
+ - `get_sam3_task_status` - 查询 SAM3 任务状态(同步工具超时后用于轮询)
22
31
 
23
32
  ## 前置要求
24
33
 
@@ -109,24 +118,28 @@ AI 会自动完成:
109
118
  重启客户端后,确认工具是否加载成功:
110
119
 
111
120
  1. 或直接问 AI:"你有哪些可用的工具?"
112
- 2. 应看到:`create_task`、`get_task_status`、`enhance_video_sync`、`sam3_predict`
121
+ 2. 当前 npm `latest=0.2.1` 应看到 `create_task`、`get_task_status`、`enhance_video_sync`、`sam3_predict`、`get_sam3_task_status`。
122
+ 3. 图片工具随后续版本发布后,还应能看到 `enhance_image_sync`、`colorize_image_sync`、`denoise_image_sync`、`get_image_task_status`。
113
123
 
114
124
  ## 配置项
115
125
 
116
126
  | 变量名 | 必填 | 默认值 | 说明 |
117
127
  |---|---|---|---|
118
- | `API_KEY` | **是** | - | API 认证密钥(视频增强和 SAM3 共用) |
119
- | `HTTP_API_BASE_URL` | 否 | `https://mcp.avc.ai/enhance` | 视频增强服务接口地址 |
128
+ | `API_KEY` | **是** | - | API 认证密钥(视频、图片和 SAM3 服务共用) |
129
+ | `HTTP_API_BASE_URL` | 否 | `https://mcp.avc.ai/enhance` | 视频与图片共用的 HTTP 服务接口地址 |
130
+ | `IMAGE_API_BASE_URL` | 否 | 与 `HTTP_API_BASE_URL` 相同 | 可选图片接口覆盖;共享生产服务无需配置 |
120
131
  | `SAM3_API_BASE_URL` | 否 | `https://mcp.avc.ai/sam` | SAM3 服务接口地址 |
121
- | `SAM3_POLL_INTERVAL` | 否 | `2000` | SAM3 轮询间隔(毫秒) |
122
- | `SAM3_POLL_MAX_ATTEMPTS` | 否 | `25` | SAM3 最大轮询次数 |
132
+ | `SAM3_POLL_INTERVAL_MS` | 否 | `2000` | SAM3 轮询间隔(毫秒,`SAM3_POLL_INTERVAL` 为已弃用别名) |
133
+ | `SAM3_POLL_MAX_ATTEMPTS` | 否 | `25` | SAM3 最大状态查询次数;时间预算为 间隔 × 次数,任一限制先耗尽即截断等待 |
134
+
135
+ `IMAGE_API_BASE_URL` 是可选的图片端点覆盖参数,用于把图片请求指向自定义图片服务。省略时,图片与视频请求共用 `HTTP_API_BASE_URL` 服务——这也是生产服务器的推荐配置。
123
136
 
124
137
  ### 自定义服务地址
125
138
 
126
139
  ```json
127
140
  {
128
141
  "env": {
129
- "HTTP_API_BASE_URL": "https://your-endpoint.com",
142
+ "HTTP_API_BASE_URL": "https://your-media-endpoint.com",
130
143
  "API_KEY": "your-api-key",
131
144
  "SAM3_API_BASE_URL": "https://your-sam3-endpoint.com"
132
145
  }
@@ -135,9 +148,11 @@ AI 会自动完成:
135
148
 
136
149
  或通过命令行参数:
137
150
  ```bash
138
- npx -y @avclabs.ai/media-mcp@latest --base-url https://your-endpoint.com --api-key your-api-key --sam3-base-url https://your-sam3-endpoint.com
151
+ npx -y @avclabs.ai/media-mcp@latest --base-url https://your-media-endpoint.com --api-key your-api-key --sam3-base-url https://your-sam3-endpoint.com
139
152
  ```
140
153
 
154
+ 可选的 `--image-base-url` 参数仅用于主动拆分公网图片端点的部署;当前 npm `latest` 版本不使用它(图片请求共用主端点)。
155
+
141
156
  ## 推荐的工作流程
142
157
 
143
158
  本项目提供了**同步**和**异步**两种模式。
@@ -157,15 +172,15 @@ npx -y @avclabs.ai/media-mcp@latest --base-url https://your-endpoint.com --api-k
157
172
 
158
173
  **视频增强**:
159
174
  - 调用 `enhance_video_sync` → 服务器内部自动轮询
160
- - 默认最多等待50秒
161
- - 如果50秒内完成,直接返回结果
162
- - 如果50秒未完成,返回 `task_id` 和提示,让 Agent 切换到 `get_task_status` 继续查询
175
+ - 默认最多等待45秒
176
+ - 如果45秒内完成,直接返回结果
177
+ - 如果45秒未完成,返回 `task_id` 和提示,让 Agent 切换到 `get_task_status` 继续查询
163
178
 
164
179
  **图像分割 (SAM3)**:
165
180
  - 调用 `sam3_predict` → 服务器内部自动轮询
166
- - 默认最多等待50秒(25次 × 2秒轮询间隔)
167
- - 如果50秒内完成,直接返回分割结果
168
- - 如果50秒未完成,返回截断提示,告知任务仍在处理中
181
+ - 默认最多25次状态查询、约50秒时间预算(25次 × 2秒间隔,任一限制先耗尽即截断等待)
182
+ - 如果预算内完成,直接返回分割结果
183
+ - 如果预算内未完成,返回携带 `task_id` 的截断提示,告知任务仍在处理中
169
184
 
170
185
  ## 使用示例
171
186
 
@@ -175,6 +190,12 @@ npx -y @avclabs.ai/media-mcp@latest --base-url https://your-endpoint.com --api-k
175
190
 
176
191
  > "把我桌面的 video.mp4 提升到 2k 画质"
177
192
 
193
+ > "帮我把这张图片画质增强一下:https://example.com/photo.jpg"
194
+
195
+ > "帮我把这张黑白照片上色:/Users/me/Desktop/old_photo.png"
196
+
197
+ > "帮我把这张图片降噪去噪:C:\\Users\\xxx\\noisy.jpg"
198
+
178
199
  > "帮我分析这张图片,找出里面的所有物体:C:\\Users\\xxx\\photo.png"
179
200
 
180
201
  > "用 SAM3 分割这张图片,prompt 是 'find all cars'"
@@ -234,27 +255,141 @@ AI 会根据任务复杂度自动选择同步或异步工具完成任务。
234
255
 
235
256
  同步增强视频(阻塞等待完成)。
236
257
 
237
- > **仅适合短视频(预计处理时间 < 1 分钟)。** 如果任务在50秒内未完成,工具会提前返回并包含 `task_id`,你需要使用 `get_task_status` 继续查询。
258
+ > **仅适合短视频(预计处理时间 < 1 分钟)。** 如果任务在默认45秒等待预算内未完成,工具会提前返回并包含 `task_id`,你需要使用 `get_task_status` 继续查询。
238
259
 
239
260
  | 参数 | 类型 | 必填 | 默认值 | 说明 |
240
261
  |---|---|---|---|---|
241
262
  | `video_source` | string | 是 | - | 视频 URL 或本地文件路径 |
242
263
  | `type` | string | 否 | `url` | `url` 或 `local` |
243
264
  | `resolution` | string | 否 | `720p` | 目标分辨率 |
244
- | `poll_interval` | number | 否 | `5` | 轮询间隔(秒) |
245
- | `timeout` | number | 否 | `50` | 同步等待超时时间(秒),超过后主动返回 |
265
+ | `poll_interval` | number | 否 | `5` | 轮询间隔(秒,0.5-30) |
266
+ | `timeout` | number | 否 | `45` | 同步等待超时时间(秒,1-45),超过后主动返回 |
246
267
 
247
- **截断返回示例(50秒未完成):**
268
+ **截断返回示例(默认45秒预算内未完成):**
248
269
  ```json
249
270
  {
250
271
  "success": true,
251
272
  "status": "processing",
252
273
  "task_id": "xxx",
253
- "message": "Task is still processing (waited 50 seconds). Please use get_task_status to continue polling.",
274
+ "message": "Task is still processing (waited 45 seconds, 9 status queries). Please use get_task_status to continue polling.",
254
275
  "note": "The synchronous wait for this long-running task has been truncated. Switch to get_task_status polling."
255
276
  }
256
277
  ```
257
278
 
279
+ ### 图片增强
280
+
281
+ 提供三个图片处理工具,分别针对不同场景:
282
+
283
+ | 工具 | 功能 | 适用场景 |
284
+ |---|---|---|
285
+ | `enhance_image_sync` | 图片画质增强与人脸优化 | 模糊、低分辨率或画质下降的照片 |
286
+ | `colorize_image_sync` | 黑白照片上色 | 为老旧黑白照片恢复真实色彩 |
287
+ | `denoise_image_sync` | 图片降噪去噪 | 弱光环境下拍摄的噪点/颗粒感照片 |
288
+
289
+ 三个工具的参数和行为模式相同,均为**同步**调用——工具会阻塞直到图片处理完成或超时。
290
+
291
+ **支持的图片格式**:PNG、JPG、JPEG、BMP、WebP 等。
292
+
293
+ **两种上传方式**:
294
+ 1. **URL 上传**:提供公开可访问的图片 URL(`type: "url"`)
295
+ 2. **本地上传**:提供本地文件路径,MCP Server 自动上传到 TOS 对象存储(`type: "local"`,最大 100MB)
296
+
297
+ #### enhance_image_sync
298
+
299
+ 同步增强图片画质并优化人脸。
300
+
301
+ > 工具内部会创建任务并轮询结果。如果在超时时间内(默认 45 秒)处理完成,直接返回结果;否则提前返回 `task_id`,需用 `get_image_task_status` 继续轮询。
302
+
303
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
304
+ |---|---|---|---|---|
305
+ | `image_source` | string | 是 | - | 图片 URL 或本地文件路径(URL 必须公网可访问,不支持需要登录或签名的链接) |
306
+ | `type` | string | 否 | `url` | `url` 或 `local` |
307
+ | `scale` | number | 否 | `2` | 增强倍数(如 `2` 为 2 倍、`4` 为 4 倍放大) |
308
+ | `poll_interval` | number | 否 | `5` | 轮询间隔(秒,0.5-30) |
309
+ | `timeout` | number | 否 | `45` | 同步等待超时时间(秒,1-45),超过后主动返回 |
310
+
311
+ **正常完成返回:**
312
+ ```json
313
+ {
314
+ "success": true,
315
+ "task_id": "xxx",
316
+ "status": "completed",
317
+ "progress": 100,
318
+ "image_url": "https://..."
319
+ }
320
+ ```
321
+
322
+ **截断返回(默认45秒预算内未完成):**
323
+ ```json
324
+ {
325
+ "success": true,
326
+ "status": "processing",
327
+ "task_id": "xxx",
328
+ "message": "Task is still processing (waited 45 seconds, 9 status queries). Please use get_image_task_status to continue polling.",
329
+ "note": "The synchronous wait for this long-running task has been truncated. Switch to get_image_task_status polling."
330
+ }
331
+ ```
332
+
333
+ #### colorize_image_sync
334
+
335
+ 同步为黑白照片 AI 上色。
336
+
337
+ > 适合老旧黑白照片,AI 会为图片添加真实色彩。参数与返回格式与 `enhance_image_sync` 相同。
338
+
339
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
340
+ |---|---|---|---|---|
341
+ | `image_source` | string | 是 | - | 图片 URL 或本地文件路径(URL 必须公网可访问,不支持需要登录或签名的链接) |
342
+ | `type` | string | 否 | `url` | `url` 或 `local` |
343
+ | `poll_interval` | number | 否 | `5` | 轮询间隔(秒,0.5-30) |
344
+ | `timeout` | number | 否 | `45` | 同步等待超时时间(秒,1-45),超过后主动返回 |
345
+
346
+ **返回值:** 与 `enhance_image_sync` 相同。
347
+
348
+ #### denoise_image_sync
349
+
350
+ 同步为图片降噪去噪。
351
+
352
+ > 适合弱光环境或高 ISO 拍摄的噪点/颗粒感照片。参数与返回格式与 `enhance_image_sync` 相同。
353
+
354
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
355
+ |---|---|---|---|---|
356
+ | `image_source` | string | 是 | - | 图片 URL 或本地文件路径(URL 必须公网可访问,不支持需要登录或签名的链接) |
357
+ | `type` | string | 否 | `url` | `url` 或 `local` |
358
+ | `poll_interval` | number | 否 | `5` | 轮询间隔(秒,0.5-30) |
359
+ | `timeout` | number | 否 | `45` | 同步等待超时时间(秒,1-45),超过后主动返回 |
360
+
361
+ **返回值:** 与 `enhance_image_sync` 相同。
362
+
363
+ #### get_image_task_status
364
+
365
+ 查询图片处理任务状态。当同步工具超时后,用此工具轮询结果。
366
+
367
+ > 返回值中的 `status` 字段可能为:`processing`(处理中)、`completed`(已完成)、`failed`(失败)。如果 `status` 为 `processing`,等待几秒后再次调用此工具。
368
+
369
+ | 参数 | 类型 | 必填 |
370
+ |---|---|---|
371
+ | `task_id` | string | 是 |
372
+
373
+ **返回值:**
374
+ ```json
375
+ {
376
+ "success": true,
377
+ "task_id": "xxx",
378
+ "status": "completed",
379
+ "progress": 100,
380
+ "image_url": "https://...",
381
+ "message": "Task is still processing, please check again later"
382
+ }
383
+ ```
384
+
385
+ 其中 `message` 字段只在 `status` 为 `processing` 时出现,提示 Agent 继续等待。
386
+
387
+ #### 图片工具推荐工作流
388
+
389
+ 1. **大多数图片**:直接调用 `enhance_image_sync` / `colorize_image_sync` / `denoise_image_sync`,工具会完成全部流程并返回结果
390
+ 2. **如果被截断**:工具返回 `task_id`,然后用 `get_image_task_status` 轮询,直到 `status` 变为 `completed` 或 `failed`
391
+ 3. **如果失败**:查看 `error_message` 字段了解详情
392
+
258
393
  ### 图像分割 (SAM3)
259
394
 
260
395
  #### sam3_predict
@@ -309,19 +444,91 @@ AI 会根据任务复杂度自动选择同步或异步工具完成任务。
309
444
  }
310
445
  ```
311
446
 
312
- **截断返回示例(50秒未完成):**
447
+ **截断返回示例(预算内未完成):**
448
+ ```json
449
+ {
450
+ "success": true,
451
+ "status": "processing",
452
+ "task_id": "xxx",
453
+ "message": "Task is still processing (waited 50 seconds, 25 status queries). Please use get_sam3_task_status to continue polling.",
454
+ "note": "The synchronous wait for this long-running task has been truncated. Switch to task status polling."
455
+ }
456
+ ```
457
+
458
+ **结果下载失败(任务已完成、结果缺失):**
459
+ 任务已完成但结果文件下载失败时,工具返回 `success: false`,同时携带 `task_id` 与 `status: "completed"`。请用该 `task_id` 调用 `get_sam3_task_status` 恢复结果,不要重新提交任务。
460
+ ```json
461
+ {
462
+ "success": false,
463
+ "task_id": "xxx",
464
+ "status": "completed",
465
+ "error": "Failed to download the completed result for task xxx: ...",
466
+ "note": "The task has completed; only the result download failed. Do not resubmit. Use get_sam3_task_status with this task_id to recover the result."
467
+ }
468
+ ```
469
+
470
+ #### get_sam3_task_status
471
+
472
+ 查询 SAM3 分割任务状态。当 `sam3_predict` 超时后,用此工具轮询结果。
473
+
474
+ > 返回值中的 `status` 字段可能为:`processing`(处理中)、`completed`(已完成)、`failed`(失败)。如果 `status` 为 `processing`,等待几秒后再次调用此工具。
475
+
476
+ | 参数 | 类型 | 必填 |
477
+ |---|---|---|
478
+ | `task_id` | string | 是 |
479
+
480
+ **已完成返回:**
481
+ ```json
482
+ {
483
+ "success": true,
484
+ "task_id": "xxx",
485
+ "status": "completed",
486
+ "result_url": "https://..."
487
+ }
488
+ ```
489
+
490
+ **处理中返回:**
313
491
  ```json
314
492
  {
315
493
  "success": true,
494
+ "task_id": "xxx",
316
495
  "status": "processing",
496
+ "message": "Task is still processing, please check again later."
497
+ }
498
+ ```
499
+
500
+ **失败返回:**
501
+ ```json
502
+ {
503
+ "success": false,
317
504
  "task_id": "xxx",
318
- "message": "Task is still processing (waited about 50 seconds). Please retry later or record this task_id for manual follow-up.",
319
- "note": "The synchronous wait for this long-running task has been truncated."
505
+ "status": "failed",
506
+ "error": "Task failed"
320
507
  }
321
508
  ```
322
509
 
323
510
  ## 常见问题
324
511
 
512
+ ### AVCLabs Media MCP 是免费的吗?
513
+
514
+ 注册即送免费额度,无需绑定信用卡。超出免费额度后按量付费:积分包($19.95 起)和月订阅($9.95/月起)。当前套餐见 https://mcp.avc.ai/pricing/ 。
515
+
516
+ ### 支持哪些 AI 客户端?
517
+
518
+ 任何兼容 MCP 的客户端。Claude Code、Cursor、Windsurf 有一键配置指南:https://mcp.avc.ai/docs/ (本包使用标准 MCP stdio 协议,其他 agent 使用相同的 `npx` 配置即可接入)。
519
+
520
+ ### 需要 GPU 或高性能硬件吗?
521
+
522
+ 不需要。视频增强与 SAM3 推理都在 AVCLabs 云端完成,本机只运行轻量的 MCP stdio 服务进程(Node.js 18+),普通笔记本即可。
523
+
524
+ ### API Key 在哪里获取?
525
+
526
+ 在 https://mcp.avc.ai/ 注册后在控制台创建。同一个 Key 同时用于视频增强、图片工具与 SAM3 分割。
527
+
528
+ ### `sam3_predict` 返回什么?
529
+
530
+ 文本提示所描述目标的像素级分割掩码(masks)、边界框(bounding boxes)和逐实例置信度分数——可直接用于合成、标注或后续分析。
531
+
325
532
  ### Agent 调用工具时报超时怎么办?
326
533
 
327
534
  这是本项目重点解决的问题。MCP Agent(如 Claude、Cursor)对单个 tool 调用通常有约 60 秒的超时限制。如果任务处理时间超过此限制,Agent 会报错并切断连接。
@@ -330,15 +537,11 @@ AI 会根据任务复杂度自动选择同步或异步工具完成任务。
330
537
 
331
538
  1. **优先使用异步工具**:对于视频增强等耗时任务,始终使用 `create_task` + `get_task_status`。这些工具每次调用都是瞬间返回的,不会触发超时。
332
539
 
333
- 2. **同步工具的截断机制**:`enhance_video_sync` 已在内部设置了50秒的截断限制。如果任务未在50秒内完成,工具会主动返回 `task_id`,并提示 Agent 使用 `get_task_status` 继续跟进。
540
+ 2. **同步工具的截断机制**:`enhance_video_sync` 已在内部设置了45秒的截断限制(默认 `timeout`)。如果任务未在预算内完成,工具会主动返回 `task_id`,并提示 Agent 使用 `get_task_status` 继续跟进。
334
541
 
335
- 3. **SAM3 的截断机制**:`sam3_predict` 默认轮询25次(约50秒),如果任务未完成会返回截断提示,告知任务仍在处理中。
542
+ 3. **SAM3 的截断机制**:`sam3_predict` 受两个独立限制约束:最多 `SAM3_POLL_MAX_ATTEMPTS` 次状态查询(默认25次)和时间预算 `SAM3_POLL_INTERVAL_MS × 次数`(默认 25 × 2秒 ≈ 50秒)。任一限制先耗尽即截断等待;返回的提示携带 `task_id` 以及实际经过时间和查询次数,远端任务继续运行。
336
543
 
337
- 4. **调整 SAM3 轮询参数**(高级):如果你确定 SAM3 任务通常很快(例如10秒内),可以通过环境变量增加轮询次数:
338
- ```bash
339
- SAM3_POLL_MAX_ATTEMPTS=60
340
- ```
341
- 但请确保总等待时间不超过 Agent 的超时限制。
544
+ 4. **调整 SAM3 轮询参数**(高级):两个限制相互独立,可以自由权衡间隔与次数(例如 `SAM3_POLL_INTERVAL_MS=1000` 配合 `SAM3_POLL_MAX_ATTEMPTS=50`,仍是约50秒预算、但查询频率翻倍)。如果任务通常几秒内完成,调低间隔可以更快发现完成状态。显式配置的非法值(非整数或超出允许范围)会在启动时直接报错退出,不会提交任何任务。等待预算只覆盖任务创建后的状态轮询——源准备、上传、任务提交和最后的结果下载都不计入,因此整个工具调用可能长于预算。
342
545
 
343
546
  ### 拖拽附件后提示找不到文件?
344
547
 
@@ -389,7 +592,7 @@ AI 会根据任务复杂度自动选择同步或异步工具完成任务。
389
592
 
390
593
  安装 Node.js >= 18:https://nodejs.org/
391
594
 
392
- ### "Error: --api-key argument or API_KEY environment variable is required"
595
+ ### "API key is required: pass --api-key or set the API_KEY environment variable"
393
596
 
394
597
  API Key 缺失,请检查配置中的 `env.API_KEY`。
395
598
 
@@ -402,7 +605,7 @@ API Key 缺失,请检查配置中的 `env.API_KEY`。
402
605
 
403
606
  ### "TOS 上传失败"
404
607
 
405
- 通常是签名不匹配,请确认 `HTTP_API_BASE_URL` 和 `API_KEY` 正确且有效。
608
+ 通常是签名不匹配,请确认 `IMAGE_API_BASE_URL`(未配置时回落到 `HTTP_API_BASE_URL`)和 `API_KEY` 正确且有效。
406
609
 
407
610
  ## 全局安装(可选)
408
611
 
@@ -414,6 +617,17 @@ npm install -g @avclabs.ai/media-mcp
414
617
 
415
618
  然后在配置中使用 `"command": "media-mcp"` 配合 `"args": ["--api-key", "your-api-key"]` 。
416
619
 
620
+ ## 开发与发布
621
+
622
+ 本包运行在 MCP 客户端本机,并通过 npm 发布;它不是部署到远程服务器的 Node 常驻进程。发布前验证工作区:
623
+
624
+ ```bash
625
+ npm ci
626
+ npm run release:verify
627
+ ```
628
+
629
+ 维护者请查阅[发布指南](https://github.com/avclabs/media-mcp/blob/main/docs/RELEASE.md)了解当前发布状态、版本同步、发布顺序、冒烟测试以及与门户/后端部署的关系。
630
+
417
631
  ## License
418
632
 
419
633
  MIT License - 详见 [LICENSE](LICENSE) 文件
package/config.json CHANGED
@@ -1,4 +1,5 @@
1
1
  {
2
2
  "baseUrl": "https://mcp.avc.ai/enhance",
3
+ "imageBaseUrl": null,
3
4
  "sam3BaseUrl": "https://mcp.avc.ai/sam"
4
5
  }
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function setupImageEnhancementTools(server: McpServer, baseUrl: string, apiKey: string): void;
3
+ //# sourceMappingURL=image-enhancement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-enhancement.d.ts","sourceRoot":"","sources":["../src/image-enhancement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA8CpE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAwEnG"}
@@ -0,0 +1,185 @@
1
+ import axios from 'axios';
2
+ import * as fs from 'fs';
3
+ import { z } from 'zod';
4
+ import { checkLocalFile, formatRequestError, parseTosSignature, unwrapEnvelope, uploadToTos, } from './tos.js';
5
+ import { classifyStatus, POLL_REQUEST_TIMEOUT_MS, pollUntilTerminal, registerTool } from './tooling.js';
6
+ const PollIntervalSchema = z.number().min(0.5).max(30).default(5).describe('Polling interval in seconds (0.5-30), default 5');
7
+ const SyncTimeoutSchema = z.number().min(1).max(45).default(45).describe('Synchronous wait timeout in seconds (1-45), default 45. Returns task_id early when exceeded, use get_image_task_status to continue polling');
8
+ // Schemas
9
+ const EnhanceImageSyncSchema = z.object({
10
+ image_source: z.string().describe('Image URL or local file path (URL must be publicly accessible, login or signed links are not supported)'),
11
+ type: z.enum(['url', 'local']).default('url').describe('Upload type: url=remote image, local=local file'),
12
+ scale: z.number().int().min(1).max(4).default(2).describe('Enhancement scale multiplier (1-4), default 2. Controls the upscaling factor for image enhancement (e.g. 2=2x, 4=4x)'),
13
+ poll_interval: PollIntervalSchema,
14
+ timeout: SyncTimeoutSchema,
15
+ });
16
+ const ColorizeImageSyncSchema = z.object({
17
+ image_source: z.string().describe('Image URL or local file path (URL must be publicly accessible, login or signed links are not supported)'),
18
+ type: z.enum(['url', 'local']).default('url').describe('Upload type: url=remote image, local=local file'),
19
+ poll_interval: PollIntervalSchema,
20
+ timeout: SyncTimeoutSchema,
21
+ });
22
+ const DenoiseImageSyncSchema = z.object({
23
+ image_source: z.string().describe('Image URL or local file path (URL must be publicly accessible, login or signed links are not supported)'),
24
+ type: z.enum(['url', 'local']).default('url').describe('Upload type: url=remote image, local=local file'),
25
+ poll_interval: PollIntervalSchema,
26
+ timeout: SyncTimeoutSchema,
27
+ });
28
+ // Schema - status query
29
+ const GetImageTaskStatusSchema = z.object({
30
+ task_id: z.string().describe('Task ID'),
31
+ });
32
+ export function setupImageEnhancementTools(server, baseUrl, apiKey) {
33
+ const client = axios.create({
34
+ baseURL: baseUrl.replace(/\/$/, ''),
35
+ headers: {
36
+ 'Authorization': `Bearer ${apiKey}`,
37
+ 'Content-Type': 'application/json',
38
+ },
39
+ timeout: 60000,
40
+ });
41
+ // ========== Sync task tools ==========
42
+ registerTool(server, 'enhance_image_sync', `Enhance/upscale an image to improve quality (图片增强/放大/超分辨率). Use this tool ONLY for image enhancement and upscaling tasks.
43
+
44
+ Two upload methods are supported:
45
+ 1. URL upload: provide an image URL
46
+ 2. Local upload: provide a local file path, the MCP Server will auto-upload to TOS object storage
47
+
48
+ Best for images with estimated processing time < 1 minute. If the task is not completed within the timeout, the tool returns early with a task_id. Use get_image_task_status to continue polling.`, EnhanceImageSyncSchema.shape, async (args) => processImageSync(client, args.image_source, args.type, 'enhance', args.poll_interval, args.timeout, args.scale));
49
+ registerTool(server, 'colorize_image_sync', `Colorize a black-and-white photo (黑白照片上色/旧照片上色). Use this tool ONLY for adding color to grayscale or black-and-white images.
50
+
51
+ Two upload methods are supported:
52
+ 1. URL upload: provide an image URL
53
+ 2. Local upload: provide a local file path, the MCP Server will auto-upload to TOS object storage
54
+
55
+ Best for images with estimated processing time < 1 minute. If the task is not completed within the timeout, the tool returns early with a task_id. Use get_image_task_status to continue polling.`, ColorizeImageSyncSchema.shape, async (args) => processImageSync(client, args.image_source, args.type, 'colorize', args.poll_interval, args.timeout));
56
+ registerTool(server, 'denoise_image_sync', `Remove noise from an image (图片降噪/去噪). Use this tool ONLY for denoising noisy or grainy images.
57
+
58
+ Two upload methods are supported:
59
+ 1. URL upload: provide an image URL
60
+ 2. Local upload: provide a local file path, the MCP Server will auto-upload to TOS object storage
61
+
62
+ Best for images with estimated processing time < 1 minute. If the task is not completed within the timeout, the tool returns early with a task_id. Use get_image_task_status to continue polling.`, DenoiseImageSyncSchema.shape, async (args) => processImageSync(client, args.image_source, args.type, 'denoise', args.poll_interval, args.timeout));
63
+ // ========== Status query tool ==========
64
+ registerTool(server, 'get_image_task_status', 'Query image processing task status. The status field can be: processing, completed, or failed. If status is processing, wait a few seconds and call this tool again to poll.', GetImageTaskStatusSchema.shape, async (args) => {
65
+ const result = await getImageTaskStatus(client, args.task_id);
66
+ return {
67
+ ...result,
68
+ // registerTool marks isError on success===false: a terminal failed
69
+ // status is a failed query outcome, not a healthy poll tick.
70
+ success: classifyStatus(result.status) !== 'failed',
71
+ message: result.status === 'processing' ? 'Task is still processing, please check again later' : undefined,
72
+ };
73
+ });
74
+ }
75
+ async function getImageTosSignature(client, fileName) {
76
+ const response = await client.post('/api/v3/contents/generations/tos-signature', {
77
+ file_type: 'image',
78
+ file_name: fileName,
79
+ });
80
+ const unwrapped = unwrapEnvelope(response);
81
+ if (!unwrapped.ok) {
82
+ throw new Error(unwrapped.error);
83
+ }
84
+ return unwrapped.data;
85
+ }
86
+ function getEndpointByTaskType(taskType) {
87
+ switch (taskType) {
88
+ case 'enhance':
89
+ return '/api/v3/contents/generations/image/enhance';
90
+ case 'colorize':
91
+ return '/api/v3/contents/generations/image/colorize';
92
+ case 'denoise':
93
+ return '/api/v3/contents/generations/image/denoise';
94
+ }
95
+ }
96
+ function getModelByTaskType(taskType) {
97
+ switch (taskType) {
98
+ case 'enhance':
99
+ return 'avc-image-enhance';
100
+ case 'colorize':
101
+ return 'avc-image-colorize';
102
+ case 'denoise':
103
+ return 'avc-image-denoise';
104
+ }
105
+ }
106
+ async function createImageTask(client, imageSource, sourceType, taskType, scale) {
107
+ let contentItem;
108
+ if (sourceType === 'local') {
109
+ const fileInfo = checkLocalFile(imageSource, 'image');
110
+ // Step 1: Get TOS signature
111
+ let target;
112
+ try {
113
+ target = parseTosSignature(await getImageTosSignature(client, fileInfo.fileName));
114
+ }
115
+ catch (error) {
116
+ throw new Error(`[Step 1: TOS signature failed] ${formatRequestError(error)}`);
117
+ }
118
+ // Step 2: Upload to TOS
119
+ try {
120
+ await uploadToTos(target, fs.createReadStream(imageSource), fileInfo.fileName);
121
+ }
122
+ catch (error) {
123
+ throw new Error(`[Step 2: TOS upload failed] ${error.message}`);
124
+ }
125
+ contentItem = { type: 'image_file', file_id: target.fileId, file_name: fileInfo.fileName };
126
+ }
127
+ else {
128
+ contentItem = { type: 'image_url', image_url: { url: imageSource } };
129
+ }
130
+ // Step 3: Call image API
131
+ const endpoint = getEndpointByTaskType(taskType);
132
+ const payload = { model: getModelByTaskType(taskType), content: [contentItem] };
133
+ if (scale !== undefined) {
134
+ payload.scale = scale;
135
+ }
136
+ let response;
137
+ try {
138
+ response = await client.post(endpoint, payload);
139
+ }
140
+ catch (error) {
141
+ throw new Error(`[Step 3: API call failed] endpoint=${endpoint} ${formatRequestError(error)}`);
142
+ }
143
+ const unwrapped = unwrapEnvelope(response);
144
+ if (!unwrapped.ok) {
145
+ return { success: false, error: unwrapped.error };
146
+ }
147
+ return { success: true, task_id: unwrapped.data.task_id, status: unwrapped.data.status };
148
+ }
149
+ async function getImageTaskStatus(client, taskId, signal) {
150
+ const response = await client.get(`/api/v3/contents/generations/tasks/${encodeURIComponent(taskId)}`, {
151
+ timeout: POLL_REQUEST_TIMEOUT_MS,
152
+ signal,
153
+ });
154
+ const unwrapped = unwrapEnvelope(response);
155
+ if (!unwrapped.ok) {
156
+ throw new Error(unwrapped.error);
157
+ }
158
+ const result = unwrapped.data;
159
+ return {
160
+ task_id: result.task_id,
161
+ status: result.status,
162
+ progress: result.progress ?? 0,
163
+ image_url: result.image_url,
164
+ error_message: result.error_message,
165
+ created_at: result.created_at,
166
+ updated_at: result.updated_at,
167
+ };
168
+ }
169
+ async function processImageSync(client, imageSource, sourceType, taskType, pollInterval, timeout, scale) {
170
+ const createResult = await createImageTask(client, imageSource, sourceType, taskType, scale);
171
+ if (!createResult.success) {
172
+ return createResult;
173
+ }
174
+ return pollUntilTerminal({
175
+ taskId: createResult.task_id,
176
+ timeoutSeconds: timeout,
177
+ pollIntervalSeconds: pollInterval,
178
+ continueHint: 'get_image_task_status',
179
+ fetchStatus: async (signal) => {
180
+ const { task_id, status, ...payload } = await getImageTaskStatus(client, createResult.task_id, signal);
181
+ return { status, payload };
182
+ },
183
+ });
184
+ }
185
+ //# sourceMappingURL=image-enhancement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-enhancement.js","sourceRoot":"","sources":["../src/image-enhancement.ts"],"names":[],"mappings":"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"}
package/dist/sam3.d.ts CHANGED
@@ -1,3 +1,10 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  export declare function setupSam3Tools(server: McpServer, baseUrl: string, apiKey: string, pollInterval: number, pollMaxAttempts: number): void;
3
+ /**
4
+ * Last-hop fetch for a completed SAM3 task. Never throws: a download failure
5
+ * becomes a structured object that keeps task_id and the terminal status, so
6
+ * the caller can resume via get_sam3_task_status. A download failure is not
7
+ * a truncated wait and never rewrites the remote status to failed/processing.
8
+ */
9
+ export declare function fetchSam3ResultPayload(taskId: string, resultUrl: unknown): Promise<Record<string, any>>;
3
10
  //# sourceMappingURL=sam3.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"sam3.d.ts","sourceRoot":"","sources":["../src/sam3.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA4BpE,wBAAgB,cAAc,CAC5B,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,MAAM,GACtB,IAAI,CA8CN;AAkED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAwB7G"}