Metadata-Version: 2.5
Name: video2gif-mcp
Version: 1.0.0
Summary: 把视频链接转成 GIF 动图的 MCP 服务 (含 SSRF 防护, 供魔搭/DEAP/Claude 等 MCP 客户端调用)
Author: video2gif-mcp contributors
License: MIT
Keywords: ffmpeg,gif,mcp,modelscope,video
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.10
Requires-Dist: imageio-ffmpeg<1,>=0.5
Requires-Dist: mcp<3,>=2.1
Requires-Dist: requests>=2.31
Requires-Dist: starlette>=0.37
Requires-Dist: uvicorn>=0.30
Description-Content-Type: text/markdown

# video2gif MCP 服务

把「视频链接 → GIF 动图」做成一个标准 MCP 服务，可被**魔搭、钉钉 DEAP、Claude Code / Desktop、Cursor** 等任意支持 MCP 的客户端调用。

- **工具**：`video_to_gif(video_url, size, ...)` —— 下载视频 → ffmpeg 两趟调色板转 GIF → 直接返回 GIF 图片 + 文本摘要。
- **传输**：`stdio`（魔搭托管 / uvx 默认），可选 `MCP_TRANSPORT=http` 起 Streamable HTTP（自托管）。
- **安全**：SSRF 防护（默认开，逐跳校验重定向）+ 可选鉴权 token（HTTP 自托管模式）。
- **资源上限**：输入视频 ≤50MB、fps≤30、宽度≤1280px、单次截取≤60s、输出 GIF≤20MB（防止 serverless 被打爆）。

## 目录结构

```
video2gif-mcp/
├── pyproject.toml           # 打包配置 + stdio 入口 + 依赖
├── src/video2gif/
│   ├── __init__.py
│   ├── __main__.py          # python -m video2gif
│   └── server.py            # MCP 服务 (MCPServer + video_to_gif 工具)
├── test_client.py           # 本地 stdio 测试客户端
├── deap-config.json         # DEAP 注册模板 (填入 URL 后可用)
├── Dockerfile               # 备选: 自托管 HTTP
└── LICENSE / README.md
```

## 工具参数

| 参数 | 类型 | 默认 | 说明 |
|------|------|------|------|
| `video_url` | string | 必填 | 可公开下载的视频直链 (mp4/mov/avi/webm/mkv) |
| `size` | string | `medium` | 体积预设：`small`(320px/8fps) / `medium`(480px/15fps) / `large`(720px/20fps) |
| `fps` | int | 0 | 覆盖帧率（上限 30），0=用 size 预设 |
| `width` | int | 0 | 覆盖宽度（上限 1280），0=用 size 预设 |
| `start` | float | 0 | 从第几秒开始 |
| `duration` | float | 0 | 截取时长（上限 60 秒），0=到结尾 |
| `loop` | int | 0 | 循环次数，0=无限，负值=不循环 |

## 快速开始（本地）

```bash
cd video2gif-mcp

# 方式一：uvx（无需安装，stdio）
uvx --from . video2gif-mcp

# 方式二：pip 安装后运行
pip install .
video2gif-mcp            # 或 python -m video2gif

# 本地验证工具调用（自动以 stdio 拉起服务，结果存到 output.gif）
python test_client.py --url "https://www.w3schools.com/html/mov_bbb.mp4" --size small
```

## 部署到魔搭 ModelScope（免费，供他人使用）

魔搭 MCP 广场的「可托管部署」要求 **PyPI 包 + `uvx` 拉起（stdio 传输）**，平台会帮你包成 HTTP 端点暴露出来。

1. **发布到 PyPI**：
   ```bash
   pip install uv
   uv build                     # 生成 dist/*.whl 和 *.tar.gz
   uv publish --token <你的PyPI token>
   ```

2. **魔搭 MCP 广场创建**：打开 <https://modelscope.cn/mcp> →「创建 MCP」→ 选「**可托管部署 / Hosted**」，填入配置 JSON（不要带注释）：
   ```json
   {
     "mcpServers": {
       "video2gif": {
         "command": "uvx",
         "args": ["video2gif-mcp"]
       }
     }
   }
   ```

3. **拿到端点**，形如：
   ```
   https://mcp.api-inference.modelscope.net/<你的服务ID>/mcp
   ```
   这个端点就是标准 MCP（Streamable HTTP），任何 MCP 客户端都能连。

> 魔搭托管底层是函数计算（无状态），GIF 直接以 base64 图片内容返回，不落盘、不依赖对象存储。

## 让其他智能体接入

拿到上面的端点后，各家按自己的格式配 Streamable HTTP 即可：

- **魔搭 Agent / MCP 广场**：托管后自动可被发现/调用，无需额外配置。
- **钉钉 DEAP**：「技能」→「添加插件」→「自定义 MCP」→ 传输类型选 **Streamable HTTP**，URL 填 `.../mcp`。也可直接用 [deap-config.json](deap-config.json) 导入。
- **Claude Code / Desktop**：
  ```json
  {
    "mcpServers": {
      "video2gif": {
        "type": "http",
        "url": "https://mcp.api-inference.modelscope.net/<你的服务ID>/mcp"
      }
    }
  }
  ```
- **Cursor / 通义灵码等**：在 MCP 设置里选 Streamable HTTP，填同一 URL 即可。

## 安全说明

| 能力 | 说明 | 是否默认开启 |
|------|------|------------|
| **SSRF 防护** | 只允许公网 http/https 链接，拒绝私网/环回/保留 IP（`127.*`、`192.168.*`、`10.*`、`169.254.*` 云元数据等），并逐个校验重定向 | ✅ 默认开启 |
| **鉴权 token** | 仅自托管 HTTP 模式：设置 `AUTH_TOKEN` 后要求 `Authorization: Bearer <token>` | ⬜ 自托管建议开启 |

环境变量：

- `MCP_TRANSPORT=http`：起 Streamable HTTP 自托管（默认是 stdio）。
- `AUTH_TOKEN`：自托管 HTTP 的共享密钥。魔搭托管由平台负责访问控制，一般无需自行设置。
- `ALLOW_PRIVATE_URLS=1`：**仅本地调试用**，跳过私网 IP 校验。生产环境**不要设置**。
- `PORT`：自托管 HTTP 端口（默认 8000）。

## 备选：自托管 HTTP（VPS / Docker）

```bash
docker build -t video2gif-mcp .
docker run -d -p 8000:8000 -e AUTH_TOKEN=<随机串> video2gif-mcp
```

然后客户端 URL 填 `http://<你的公网IP或域名>:8000/mcp`（建议前面加 HTTPS 反向代理）。

## 常见问题

- **魔搭「插件检测」拉不到工具**：确认代码已发 PyPI、配置 JSON 里 `command`/`args` 正确、无注释。
- **视频太大/太慢**：输入上限 50MB、下载超时 120s、单次截取≤60s；建议让用户先压缩或截取片段。
- **返回的 GIF 看不到**：极个别只认 URL 的客户端不渲染 base64 图片内容，需改走「上传对象存储返回 URL」方案（可后续加）。
