@avclabs.ai/media-mcp 0.2.1 → 0.4.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
@@ -1,12 +1,16 @@
1
- # media-mcp (Node.js)
1
+ # media-mcp(Node.js,旧版全量包)
2
2
 
3
- [English](https://github.com/avclabs/media-mcp/blob/main/README.md) | 中文
3
+ [English](https://github.com/avclabs/media-mcp/blob/main/packages/media-mcp/README.md) | 中文
4
+
5
+ > **维护说明**:本包将全部 9 个工具打包在一个 server 中。新的接入建议改用按功能拆分的 [@avclabs.ai/video-mcp](../video-mcp)、[@avclabs.ai/image-mcp](../image-mcp)、[@avclabs.ai/sam3-mcp](../sam3-mcp),让每个 MCP 客户端会话只加载自己需要的工具定义。本全量包继续可用且配置完全兼容;迁移矩阵见[仓库 README](https://github.com/avclabs/media-mcp#readme)。
4
6
 
5
7
  [![npm version](https://img.shields.io/npm/v/@avclabs.ai/media-mcp)](https://www.npmjs.com/package/@avclabs.ai/media-mcp)
6
8
  [![Node.js >=18](https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg)](https://nodejs.org/)
7
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
10
 
9
- 基于 MCP 协议的视频增强与图像分割服务,作为 MCP Client-Server 与后端 HTTP Server 交互。
11
+ 基于 MCP 协议的视频增强、图片增强/上色/降噪与图像分割服务,作为 MCP Client-Server 与 AVCLabs 云端媒体服务交互。
12
+
13
+ > **发布状态**:当前 npm `latest`(`0.3.0`)包含 9 个工具——3 个视频、4 个图片、2 个 SAM3——全部正式可用。
10
14
 
11
15
  ## 功能
12
16
 
@@ -15,10 +19,17 @@
15
19
  **视频增强**
16
20
  - `create_task` - 创建视频增强任务(支持 URL 或本地文件上传)
17
21
  - `get_task_status` - 查询任务状态
18
- - `enhance_video_sync` - 同步增强视频(阻塞等待,默认50秒截断)
22
+ - `enhance_video_sync` - 同步增强视频(阻塞等待,默认45秒截断)
23
+
24
+ **图片增强**
25
+ - `enhance_image_sync` - 图片画质增强与人脸优化(支持 URL 或本地文件上传)
26
+ - `colorize_image_sync` - 黑白照片上色(支持 URL 或本地文件上传)
27
+ - `denoise_image_sync` - 图片降噪去噪(支持 URL 或本地文件上传)
28
+ - `get_image_task_status` - 查询图片任务状态(同步工具超时后用于轮询)
19
29
 
20
30
  **图像分割 (SAM3)**
21
31
  - `sam3_predict` - SAM3 图像分割(支持本地路径、URL 或 Base64 图片)
32
+ - `get_sam3_task_status` - 查询 SAM3 任务状态(同步工具超时后用于轮询)
22
33
 
23
34
  ## 前置要求
24
35
 
@@ -109,24 +120,27 @@ AI 会自动完成:
109
120
  重启客户端后,确认工具是否加载成功:
110
121
 
111
122
  1. 或直接问 AI:"你有哪些可用的工具?"
112
- 2. 应看到:`create_task`、`get_task_status`、`enhance_video_sync`、`sam3_predict`
123
+ 2. 当前 npm `latest=0.3.0` 应看到全部 9 个工具:`create_task`、`get_task_status`、`enhance_video_sync`、`enhance_image_sync`、`colorize_image_sync`、`denoise_image_sync`、`get_image_task_status`、`sam3_predict`、`get_sam3_task_status`。
113
124
 
114
125
  ## 配置项
115
126
 
116
127
  | 变量名 | 必填 | 默认值 | 说明 |
117
128
  |---|---|---|---|
118
- | `API_KEY` | **是** | - | API 认证密钥(视频增强和 SAM3 共用) |
119
- | `HTTP_API_BASE_URL` | 否 | `https://mcp.avc.ai/enhance` | 视频增强服务接口地址 |
120
- | `SAM3_API_BASE_URL` | 否 | `https://mcp.avc.ai/sam` | SAM3 服务接口地址 |
121
- | `SAM3_POLL_INTERVAL` | 否 | `2000` | SAM3 轮询间隔(毫秒) |
122
- | `SAM3_POLL_MAX_ATTEMPTS` | 否 | `25` | SAM3 最大轮询次数 |
129
+ | `API_KEY` | **是** | - | API 认证密钥(视频、图片和 SAM3 服务共用) |
130
+ | `HTTP_API_BASE_URL` | 否 | `https://mcp.avc.ai/enhance` | 视频与图片共用的增强服务地址 |
131
+ | `IMAGE_API_BASE_URL` | 否 | 与 `HTTP_API_BASE_URL` 相同 | 可选图片服务地址覆盖;共享生产服务无需配置 |
132
+ | `SAM3_API_BASE_URL` | 否 | `https://mcp.avc.ai/sam` | SAM3 服务地址 |
133
+ | `SAM3_POLL_INTERVAL_MS` | 否 | `2000` | SAM3 轮询间隔(毫秒,`SAM3_POLL_INTERVAL` 为已弃用别名) |
134
+ | `SAM3_POLL_MAX_ATTEMPTS` | 否 | `25` | SAM3 最大状态查询次数;时间预算为 间隔 × 次数,任一限制先耗尽即截断等待 |
135
+
136
+ `IMAGE_API_BASE_URL` 是可选的图片服务地址覆盖参数,用于把图片请求指向自定义图片服务。省略时,图片与视频请求共用 `HTTP_API_BASE_URL` 服务——这也是生产服务器的推荐配置。
123
137
 
124
138
  ### 自定义服务地址
125
139
 
126
140
  ```json
127
141
  {
128
142
  "env": {
129
- "HTTP_API_BASE_URL": "https://your-endpoint.com",
143
+ "HTTP_API_BASE_URL": "https://your-media-endpoint.com",
130
144
  "API_KEY": "your-api-key",
131
145
  "SAM3_API_BASE_URL": "https://your-sam3-endpoint.com"
132
146
  }
@@ -135,9 +149,11 @@ AI 会自动完成:
135
149
 
136
150
  或通过命令行参数:
137
151
  ```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
152
+ 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
153
  ```
140
154
 
155
+ 可选的 `--image-base-url` 参数仅用于主动拆分公网图片服务地址的部署;当前 npm `latest` 版本不使用它(图片请求共用主服务地址)。
156
+
141
157
  ## 推荐的工作流程
142
158
 
143
159
  本项目提供了**同步**和**异步**两种模式。
@@ -157,15 +173,15 @@ npx -y @avclabs.ai/media-mcp@latest --base-url https://your-endpoint.com --api-k
157
173
 
158
174
  **视频增强**:
159
175
  - 调用 `enhance_video_sync` → 服务器内部自动轮询
160
- - 默认最多等待50秒
161
- - 如果50秒内完成,直接返回结果
162
- - 如果50秒未完成,返回 `task_id` 和提示,让 Agent 切换到 `get_task_status` 继续查询
176
+ - 默认最多等待45秒
177
+ - 如果45秒内完成,直接返回结果
178
+ - 如果45秒未完成,返回 `task_id` 和提示,让 Agent 切换到 `get_task_status` 继续查询
163
179
 
164
180
  **图像分割 (SAM3)**:
165
181
  - 调用 `sam3_predict` → 服务器内部自动轮询
166
- - 默认最多等待50秒(25次 × 2秒轮询间隔)
167
- - 如果50秒内完成,直接返回分割结果
168
- - 如果50秒未完成,返回截断提示,告知任务仍在处理中
182
+ - 默认最多25次状态查询、约50秒时间预算(25次 × 2秒间隔,任一限制先耗尽即截断等待)
183
+ - 如果预算内完成,直接返回分割结果
184
+ - 如果预算内未完成,返回携带 `task_id` 的截断提示,告知任务仍在处理中
169
185
 
170
186
  ## 使用示例
171
187
 
@@ -175,6 +191,12 @@ npx -y @avclabs.ai/media-mcp@latest --base-url https://your-endpoint.com --api-k
175
191
 
176
192
  > "把我桌面的 video.mp4 提升到 2k 画质"
177
193
 
194
+ > "帮我把这张图片画质增强一下:https://example.com/photo.jpg"
195
+
196
+ > "帮我把这张黑白照片上色:/Users/me/Desktop/old_photo.png"
197
+
198
+ > "帮我把这张图片降噪去噪:C:\\Users\\xxx\\noisy.jpg"
199
+
178
200
  > "帮我分析这张图片,找出里面的所有物体:C:\\Users\\xxx\\photo.png"
179
201
 
180
202
  > "用 SAM3 分割这张图片,prompt 是 'find all cars'"
@@ -234,27 +256,141 @@ AI 会根据任务复杂度自动选择同步或异步工具完成任务。
234
256
 
235
257
  同步增强视频(阻塞等待完成)。
236
258
 
237
- > **仅适合短视频(预计处理时间 < 1 分钟)。** 如果任务在50秒内未完成,工具会提前返回并包含 `task_id`,你需要使用 `get_task_status` 继续查询。
259
+ > **仅适合短视频(预计处理时间 < 1 分钟)。** 如果任务在默认45秒等待预算内未完成,工具会提前返回并包含 `task_id`,你需要使用 `get_task_status` 继续查询。
238
260
 
239
261
  | 参数 | 类型 | 必填 | 默认值 | 说明 |
240
262
  |---|---|---|---|---|
241
263
  | `video_source` | string | 是 | - | 视频 URL 或本地文件路径 |
242
264
  | `type` | string | 否 | `url` | `url` 或 `local` |
243
265
  | `resolution` | string | 否 | `720p` | 目标分辨率 |
244
- | `poll_interval` | number | 否 | `5` | 轮询间隔(秒) |
245
- | `timeout` | number | 否 | `50` | 同步等待超时时间(秒),超过后主动返回 |
266
+ | `poll_interval` | number | 否 | `5` | 轮询间隔(秒,0.5-30) |
267
+ | `timeout` | number | 否 | `45` | 同步等待超时时间(秒,1-45),超过后主动返回 |
246
268
 
247
- **截断返回示例(50秒未完成):**
269
+ **截断返回示例(默认45秒预算内未完成):**
248
270
  ```json
249
271
  {
250
272
  "success": true,
251
273
  "status": "processing",
252
274
  "task_id": "xxx",
253
- "message": "Task is still processing (waited 50 seconds). Please use get_task_status to continue polling.",
275
+ "message": "Task is still processing (waited 45 seconds, 9 status queries). Please use get_task_status to continue polling.",
254
276
  "note": "The synchronous wait for this long-running task has been truncated. Switch to get_task_status polling."
255
277
  }
256
278
  ```
257
279
 
280
+ ### 图片增强
281
+
282
+ 提供三个图片处理工具,分别针对不同场景:
283
+
284
+ | 工具 | 功能 | 适用场景 |
285
+ |---|---|---|
286
+ | `enhance_image_sync` | 图片画质增强与人脸优化 | 模糊、低分辨率或画质下降的照片 |
287
+ | `colorize_image_sync` | 黑白照片上色 | 为老旧黑白照片恢复真实色彩 |
288
+ | `denoise_image_sync` | 图片降噪去噪 | 弱光环境下拍摄的噪点/颗粒感照片 |
289
+
290
+ 三个工具的参数和行为模式相同,均为**同步**调用——工具会阻塞直到图片处理完成或超时。
291
+
292
+ **支持的图片格式**:PNG、JPG、JPEG、BMP、WebP 等。
293
+
294
+ **两种上传方式**:
295
+ 1. **URL 上传**:提供公开可访问的图片 URL(`type: "url"`)
296
+ 2. **本地上传**:提供本地文件路径,MCP Server 自动上传到 TOS 对象存储(`type: "local"`,最大 100MB)
297
+
298
+ #### enhance_image_sync
299
+
300
+ 同步增强图片画质并优化人脸。
301
+
302
+ > 工具内部会创建任务并轮询结果。如果在超时时间内(默认 45 秒)处理完成,直接返回结果;否则提前返回 `task_id`,需用 `get_image_task_status` 继续轮询。
303
+
304
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
305
+ |---|---|---|---|---|
306
+ | `image_source` | string | 是 | - | 图片 URL 或本地文件路径(URL 必须公网可访问,不支持需要登录或签名的链接) |
307
+ | `type` | string | 否 | `url` | `url` 或 `local` |
308
+ | `scale` | number | 否 | `2` | 增强倍数(如 `2` 为 2 倍、`4` 为 4 倍放大) |
309
+ | `poll_interval` | number | 否 | `5` | 轮询间隔(秒,0.5-30) |
310
+ | `timeout` | number | 否 | `45` | 同步等待超时时间(秒,1-45),超过后主动返回 |
311
+
312
+ **正常完成返回:**
313
+ ```json
314
+ {
315
+ "success": true,
316
+ "task_id": "xxx",
317
+ "status": "completed",
318
+ "progress": 100,
319
+ "image_url": "https://..."
320
+ }
321
+ ```
322
+
323
+ **截断返回(默认45秒预算内未完成):**
324
+ ```json
325
+ {
326
+ "success": true,
327
+ "status": "processing",
328
+ "task_id": "xxx",
329
+ "message": "Task is still processing (waited 45 seconds, 9 status queries). Please use get_image_task_status to continue polling.",
330
+ "note": "The synchronous wait for this long-running task has been truncated. Switch to get_image_task_status polling."
331
+ }
332
+ ```
333
+
334
+ #### colorize_image_sync
335
+
336
+ 同步为黑白照片 AI 上色。
337
+
338
+ > 适合老旧黑白照片,AI 会为图片添加真实色彩。参数与返回格式与 `enhance_image_sync` 相同。
339
+
340
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
341
+ |---|---|---|---|---|
342
+ | `image_source` | string | 是 | - | 图片 URL 或本地文件路径(URL 必须公网可访问,不支持需要登录或签名的链接) |
343
+ | `type` | string | 否 | `url` | `url` 或 `local` |
344
+ | `poll_interval` | number | 否 | `5` | 轮询间隔(秒,0.5-30) |
345
+ | `timeout` | number | 否 | `45` | 同步等待超时时间(秒,1-45),超过后主动返回 |
346
+
347
+ **返回值:** 与 `enhance_image_sync` 相同。
348
+
349
+ #### denoise_image_sync
350
+
351
+ 同步为图片降噪去噪。
352
+
353
+ > 适合弱光环境或高 ISO 拍摄的噪点/颗粒感照片。参数与返回格式与 `enhance_image_sync` 相同。
354
+
355
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
356
+ |---|---|---|---|---|
357
+ | `image_source` | string | 是 | - | 图片 URL 或本地文件路径(URL 必须公网可访问,不支持需要登录或签名的链接) |
358
+ | `type` | string | 否 | `url` | `url` 或 `local` |
359
+ | `poll_interval` | number | 否 | `5` | 轮询间隔(秒,0.5-30) |
360
+ | `timeout` | number | 否 | `45` | 同步等待超时时间(秒,1-45),超过后主动返回 |
361
+
362
+ **返回值:** 与 `enhance_image_sync` 相同。
363
+
364
+ #### get_image_task_status
365
+
366
+ 查询图片处理任务状态。当同步工具超时后,用此工具轮询结果。
367
+
368
+ > 返回值中的 `status` 字段可能为:`processing`(处理中)、`completed`(已完成)、`failed`(失败)。如果 `status` 为 `processing`,等待几秒后再次调用此工具。
369
+
370
+ | 参数 | 类型 | 必填 |
371
+ |---|---|---|
372
+ | `task_id` | string | 是 |
373
+
374
+ **返回值:**
375
+ ```json
376
+ {
377
+ "success": true,
378
+ "task_id": "xxx",
379
+ "status": "completed",
380
+ "progress": 100,
381
+ "image_url": "https://...",
382
+ "message": "Task is still processing, please check again later"
383
+ }
384
+ ```
385
+
386
+ 其中 `message` 字段只在 `status` 为 `processing` 时出现,提示 Agent 继续等待。
387
+
388
+ #### 图片工具推荐工作流
389
+
390
+ 1. **大多数图片**:直接调用 `enhance_image_sync` / `colorize_image_sync` / `denoise_image_sync`,工具会完成全部流程并返回结果
391
+ 2. **如果被截断**:工具返回 `task_id`,然后用 `get_image_task_status` 轮询,直到 `status` 变为 `completed` 或 `failed`
392
+ 3. **如果失败**:查看 `error_message` 字段了解详情
393
+
258
394
  ### 图像分割 (SAM3)
259
395
 
260
396
  #### sam3_predict
@@ -309,19 +445,91 @@ AI 会根据任务复杂度自动选择同步或异步工具完成任务。
309
445
  }
310
446
  ```
311
447
 
312
- **截断返回示例(50秒未完成):**
448
+ **截断返回示例(预算内未完成):**
313
449
  ```json
314
450
  {
315
451
  "success": true,
316
452
  "status": "processing",
317
453
  "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."
454
+ "message": "Task is still processing (waited 50 seconds, 25 status queries). Please use get_sam3_task_status to continue polling.",
455
+ "note": "The synchronous wait for this long-running task has been truncated. Switch to task status polling."
456
+ }
457
+ ```
458
+
459
+ **结果下载失败(任务已完成、结果缺失):**
460
+ 任务已完成但结果文件下载失败时,工具返回 `success: false`,同时携带 `task_id` 与 `status: "completed"`。请用该 `task_id` 调用 `get_sam3_task_status` 恢复结果,不要重新提交任务。
461
+ ```json
462
+ {
463
+ "success": false,
464
+ "task_id": "xxx",
465
+ "status": "completed",
466
+ "error": "Failed to download the completed result for task xxx: ...",
467
+ "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."
468
+ }
469
+ ```
470
+
471
+ #### get_sam3_task_status
472
+
473
+ 查询 SAM3 分割任务状态。当 `sam3_predict` 超时后,用此工具轮询结果。
474
+
475
+ > 返回值中的 `status` 字段可能为:`processing`(处理中)、`completed`(已完成)、`failed`(失败)。如果 `status` 为 `processing`,等待几秒后再次调用此工具。
476
+
477
+ | 参数 | 类型 | 必填 |
478
+ |---|---|---|
479
+ | `task_id` | string | 是 |
480
+
481
+ **已完成返回:**
482
+ ```json
483
+ {
484
+ "success": true,
485
+ "task_id": "xxx",
486
+ "status": "completed",
487
+ "result_url": "https://..."
488
+ }
489
+ ```
490
+
491
+ **处理中返回:**
492
+ ```json
493
+ {
494
+ "success": true,
495
+ "task_id": "xxx",
496
+ "status": "processing",
497
+ "message": "Task is still processing, please check again later."
498
+ }
499
+ ```
500
+
501
+ **失败返回:**
502
+ ```json
503
+ {
504
+ "success": false,
505
+ "task_id": "xxx",
506
+ "status": "failed",
507
+ "error": "Task failed"
320
508
  }
321
509
  ```
322
510
 
323
511
  ## 常见问题
324
512
 
513
+ ### AVCLabs Media MCP 是免费的吗?
514
+
515
+ 注册即送免费额度,无需绑定信用卡。超出免费额度后按量付费:积分包($19.95 起)和月订阅($9.95/月起)。当前套餐见 https://mcp.avc.ai/pricing/ 。
516
+
517
+ ### 支持哪些 AI 客户端?
518
+
519
+ 任何兼容 MCP 的客户端。Claude Code、Cursor、Windsurf 有一键配置指南:https://mcp.avc.ai/docs/ (本包使用标准 MCP stdio 协议,其他 agent 使用相同的 `npx` 配置即可接入)。
520
+
521
+ ### 需要 GPU 或高性能硬件吗?
522
+
523
+ 不需要。视频增强与 SAM3 推理都在 AVCLabs 云端完成,本机只运行轻量的 MCP stdio 服务进程(Node.js 18+),普通笔记本即可。
524
+
525
+ ### API Key 在哪里获取?
526
+
527
+ 在 https://mcp.avc.ai/ 注册后在控制台创建。同一个 Key 同时用于视频增强、图片工具与 SAM3 分割。
528
+
529
+ ### `sam3_predict` 返回什么?
530
+
531
+ 文本提示所描述目标的像素级分割掩码(masks)、边界框(bounding boxes)和逐实例置信度分数——可直接用于合成、标注或后续分析。
532
+
325
533
  ### Agent 调用工具时报超时怎么办?
326
534
 
327
535
  这是本项目重点解决的问题。MCP Agent(如 Claude、Cursor)对单个 tool 调用通常有约 60 秒的超时限制。如果任务处理时间超过此限制,Agent 会报错并切断连接。
@@ -330,15 +538,11 @@ AI 会根据任务复杂度自动选择同步或异步工具完成任务。
330
538
 
331
539
  1. **优先使用异步工具**:对于视频增强等耗时任务,始终使用 `create_task` + `get_task_status`。这些工具每次调用都是瞬间返回的,不会触发超时。
332
540
 
333
- 2. **同步工具的截断机制**:`enhance_video_sync` 已在内部设置了50秒的截断限制。如果任务未在50秒内完成,工具会主动返回 `task_id`,并提示 Agent 使用 `get_task_status` 继续跟进。
541
+ 2. **同步工具的截断机制**:`enhance_video_sync` 已在内部设置了45秒的截断限制(默认 `timeout`)。如果任务未在预算内完成,工具会主动返回 `task_id`,并提示 Agent 使用 `get_task_status` 继续跟进。
334
542
 
335
- 3. **SAM3 的截断机制**:`sam3_predict` 默认轮询25次(约50秒),如果任务未完成会返回截断提示,告知任务仍在处理中。
543
+ 3. **SAM3 的截断机制**:`sam3_predict` 受两个独立限制约束:最多 `SAM3_POLL_MAX_ATTEMPTS` 次状态查询(默认25次)和时间预算 `SAM3_POLL_INTERVAL_MS × 次数`(默认 25 × 2秒 ≈ 50秒)。任一限制先耗尽即截断等待;返回的提示携带 `task_id` 以及实际经过时间和查询次数,远端任务继续运行。
336
544
 
337
- 4. **调整 SAM3 轮询参数**(高级):如果你确定 SAM3 任务通常很快(例如10秒内),可以通过环境变量增加轮询次数:
338
- ```bash
339
- SAM3_POLL_MAX_ATTEMPTS=60
340
- ```
341
- 但请确保总等待时间不超过 Agent 的超时限制。
545
+ 4. **调整 SAM3 轮询参数**(高级):两个限制相互独立,可以自由权衡间隔与次数(例如 `SAM3_POLL_INTERVAL_MS=1000` 配合 `SAM3_POLL_MAX_ATTEMPTS=50`,仍是约50秒预算、但查询频率翻倍)。如果任务通常几秒内完成,调低间隔可以更快发现完成状态。显式配置的非法值(非整数或超出允许范围)会在启动时直接报错退出,不会提交任何任务。等待预算只覆盖任务创建后的状态轮询——源准备、上传、任务提交和最后的结果下载都不计入,因此整个工具调用可能长于预算。
342
546
 
343
547
  ### 拖拽附件后提示找不到文件?
344
548
 
@@ -389,7 +593,7 @@ AI 会根据任务复杂度自动选择同步或异步工具完成任务。
389
593
 
390
594
  安装 Node.js >= 18:https://nodejs.org/
391
595
 
392
- ### "Error: --api-key argument or API_KEY environment variable is required"
596
+ ### "API key is required: pass --api-key or set the API_KEY environment variable"
393
597
 
394
598
  API Key 缺失,请检查配置中的 `env.API_KEY`。
395
599
 
@@ -402,7 +606,7 @@ API Key 缺失,请检查配置中的 `env.API_KEY`。
402
606
 
403
607
  ### "TOS 上传失败"
404
608
 
405
- 通常是签名不匹配,请确认 `HTTP_API_BASE_URL` 和 `API_KEY` 正确且有效。
609
+ 通常是签名不匹配,请确认 `IMAGE_API_BASE_URL`(未配置时回落到 `HTTP_API_BASE_URL`)和 `API_KEY` 正确且有效。
406
610
 
407
611
  ## 全局安装(可选)
408
612
 
@@ -414,6 +618,17 @@ npm install -g @avclabs.ai/media-mcp
414
618
 
415
619
  然后在配置中使用 `"command": "media-mcp"` 配合 `"args": ["--api-key", "your-api-key"]` 。
416
620
 
621
+ ## 开发与发布
622
+
623
+ 本包运行在 MCP 客户端本机,并通过 npm 发布;它不是部署到远程服务器的 Node 常驻进程。发布前验证工作区:
624
+
625
+ ```bash
626
+ npm ci
627
+ npm run release:verify
628
+ ```
629
+
630
+ 维护者请查阅[发布指南](https://github.com/avclabs/media-mcp/blob/main/docs/RELEASE.md)了解当前发布状态、版本同步、发布顺序、冒烟测试以及与门户/后端部署的关系。
631
+
417
632
  ## License
418
633
 
419
634
  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,36 @@
1
+ import { ConfigError } from '@avclabs.ai/media-mcp-core';
2
+ export { ConfigError };
3
+ export interface MediaHostCliOverrides {
4
+ baseUrl?: string;
5
+ imageBaseUrl?: string;
6
+ sam3BaseUrl?: string;
7
+ apiKey?: string;
8
+ /** Raw argument text; parsed and bounds-checked by the sam3 resolver. */
9
+ sam3PollIntervalMs?: string;
10
+ sam3PollMaxAttempts?: string;
11
+ }
12
+ export interface MediaHostEnv {
13
+ API_KEY?: string;
14
+ HTTP_API_BASE_URL?: string;
15
+ IMAGE_API_BASE_URL?: string;
16
+ SAM3_API_BASE_URL?: string;
17
+ /** Canonical name. */
18
+ SAM3_POLL_INTERVAL_MS?: string;
19
+ /** Deprecated alias of SAM3_POLL_INTERVAL_MS. */
20
+ SAM3_POLL_INTERVAL?: string;
21
+ SAM3_POLL_MAX_ATTEMPTS?: string;
22
+ }
23
+ export interface MediaHostConfig {
24
+ enhancementApiBaseUrl: string;
25
+ imageApiBaseUrl: string;
26
+ sam3ApiBaseUrl: string;
27
+ apiKey: string;
28
+ sam3PollIntervalMs: number;
29
+ sam3PollMaxAttempts: number;
30
+ }
31
+ export declare function resolveMediaHostConfig(options: {
32
+ cli?: MediaHostCliOverrides;
33
+ env?: MediaHostEnv;
34
+ file?: Record<string, unknown>;
35
+ }): MediaHostConfig;
36
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAKzD,OAAO,EAAE,WAAW,EAAE,CAAC;AAEvB,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,sBAAsB;IACtB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,iDAAiD;IACjD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE;IAC9C,GAAG,CAAC,EAAE,qBAAqB,CAAC;IAC5B,GAAG,CAAC,EAAE,YAAY,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,GAAG,eAAe,CAYlB"}
package/dist/config.js ADDED
@@ -0,0 +1,25 @@
1
+ // Legacy all-in-one host configuration. Composes the per-package resolvers so
2
+ // resolveMediaHostConfig keeps its historical semantics exactly: precedence
3
+ // per key is CLI > environment > file config > built-in default, the image
4
+ // base derives from the RESOLVED enhancement base, and validation happens
5
+ // before any tool is created. New integrations should use the per-function
6
+ // packages instead of this one.
7
+ import { ConfigError } from '@avclabs.ai/media-mcp-core';
8
+ import { resolveVideoConfig } from '@avclabs.ai/video-mcp';
9
+ import { resolveImageConfig } from '@avclabs.ai/image-mcp';
10
+ import { resolveSam3Config } from '@avclabs.ai/sam3-mcp';
11
+ export { ConfigError };
12
+ export function resolveMediaHostConfig(options) {
13
+ const video = resolveVideoConfig(options);
14
+ const image = resolveImageConfig(options);
15
+ const sam3 = resolveSam3Config(options);
16
+ return {
17
+ enhancementApiBaseUrl: video.apiBaseUrl,
18
+ imageApiBaseUrl: image.imageApiBaseUrl,
19
+ sam3ApiBaseUrl: sam3.apiBaseUrl,
20
+ apiKey: video.apiKey,
21
+ sam3PollIntervalMs: sam3.pollIntervalMs,
22
+ sam3PollMaxAttempts: sam3.pollMaxAttempts,
23
+ };
24
+ }
25
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,4EAA4E;AAC5E,2EAA2E;AAC3E,0EAA0E;AAC1E,2EAA2E;AAC3E,gCAAgC;AAEhC,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,EAAE,WAAW,EAAE,CAAC;AAiCvB,MAAM,UAAU,sBAAsB,CAAC,OAItC;IACC,MAAM,KAAK,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACxC,OAAO;QACL,qBAAqB,EAAE,KAAK,CAAC,UAAU;QACvC,eAAe,EAAE,KAAK,CAAC,eAAe;QACtC,cAAc,EAAE,IAAI,CAAC,UAAU;QAC/B,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,kBAAkB,EAAE,IAAI,CAAC,cAAc;QACvC,mBAAmB,EAAE,IAAI,CAAC,eAAe;KAC1C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { ConfigError, MediaHostCliOverrides, MediaHostConfig, MediaHostEnv, resolveMediaHostConfig, } from './config.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,eAAe,EACf,YAAY,EACZ,sBAAsB,GACvB,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ // Library surface for the legacy all-in-one package. The bin entry
2
+ // (server.ts) is deliberately not exported here: importing it starts the
3
+ // stdio server.
4
+ export { ConfigError, resolveMediaHostConfig, } from './config.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,yEAAyE;AACzE,gBAAgB;AAChB,OAAO,EACL,WAAW,EAIX,sBAAsB,GACvB,MAAM,aAAa,CAAC"}
package/dist/server.d.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * MCP Server - Video enhancement and SAM3 image segmentation
3
+ * media-mcp — legacy all-in-one MCP server: video enhancement, image
4
+ * enhancement/colorization/denoising, and SAM3 image segmentation (9 tools).
5
+ * Prefer the per-function packages @avclabs.ai/video-mcp, @avclabs.ai/image-mcp,
6
+ * and @avclabs.ai/sam3-mcp; this entry keeps existing client configurations
7
+ * working unchanged.
4
8
  */
5
9
  export {};
6
10
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA;;GAEG"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA;;;;;;GAMG"}
package/dist/server.js CHANGED
@@ -1,89 +1,41 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * MCP Server - Video enhancement and SAM3 image segmentation
3
+ * media-mcp — legacy all-in-one MCP server: video enhancement, image
4
+ * enhancement/colorization/denoising, and SAM3 image segmentation (9 tools).
5
+ * Prefer the per-function packages @avclabs.ai/video-mcp, @avclabs.ai/image-mcp,
6
+ * and @avclabs.ai/sam3-mcp; this entry keeps existing client configurations
7
+ * working unchanged.
4
8
  */
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
- // Main entry
9
+ import { extractConfigPath, loadBundledConfig, parseFlagValues, runStdioServer } from '@avclabs.ai/media-mcp-core';
10
+ import { setupVideoEnhancementTools } from '@avclabs.ai/video-mcp';
11
+ import { setupImageEnhancementTools } from '@avclabs.ai/image-mcp';
12
+ import { setupSam3Tools } from '@avclabs.ai/sam3-mcp';
13
+ import { resolveMediaHostConfig } from './config.js';
14
+ // Kept in sync with package.json; scripts/check-release.mjs fails the build on drift.
15
+ const SERVER_VERSION = '0.4.0';
36
16
  async function main() {
37
17
  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 || '25', 10);
45
- // Parse command line arguments
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('Error: --api-key argument or API_KEY environment variable is required');
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
- },
18
+ const fileConfig = loadBundledConfig(extractConfigPath(args), import.meta.url);
19
+ const hostConfig = resolveMediaHostConfig({
20
+ cli: parseFlagValues(args, {
21
+ '--base-url': 'baseUrl',
22
+ '--image-base-url': 'imageBaseUrl',
23
+ '--api-key': 'apiKey',
24
+ '--sam3-base-url': 'sam3BaseUrl',
25
+ '--sam3-poll-interval': 'sam3PollIntervalMs',
26
+ '--sam3-poll-max-attempts': 'sam3PollMaxAttempts',
27
+ }),
28
+ env: process.env,
29
+ file: fileConfig,
30
+ });
31
+ await runStdioServer({ name: 'media-mcp', version: SERVER_VERSION }, (server) => {
32
+ // Register video enhancement tools
33
+ setupVideoEnhancementTools(server, hostConfig.enhancementApiBaseUrl, hostConfig.apiKey);
34
+ // Register image enhancement tools
35
+ setupImageEnhancementTools(server, hostConfig.imageApiBaseUrl, hostConfig.apiKey);
36
+ // Register SAM3 tools
37
+ setupSam3Tools(server, hostConfig.sam3ApiBaseUrl, hostConfig.apiKey, hostConfig.sam3PollIntervalMs, hostConfig.sam3PollMaxAttempts);
79
38
  });
80
- // Register video enhancement tools
81
- setupVideoEnhancementTools(server, baseUrl, apiKey);
82
- // Register 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
39
  }
88
40
  main().catch((error) => {
89
41
  console.error('Server error:', error);