mirror of
https://github.com/sun-guannan/CapCutAPI.git
synced 2025-11-25 03:15:00 +08:00
Add MCP Support
This commit is contained in:
254
MCP_Documentation_English.md
Normal file
254
MCP_Documentation_English.md
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
# CapCut API MCP Server Documentation
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The CapCut API MCP Server is a video editing service based on the Model Context Protocol (MCP), providing complete CapCut video editing functionality interfaces. Through the MCP protocol, you can easily integrate professional-grade video editing capabilities into various applications.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### 🎬 Core Capabilities
|
||||||
|
- **Draft Management**: Create, save, and manage video projects
|
||||||
|
- **Multimedia Support**: Video, audio, image, and text processing
|
||||||
|
- **Advanced Effects**: Effects, animations, transitions, and filters
|
||||||
|
- **Precise Control**: Timeline, keyframes, and layer management
|
||||||
|
|
||||||
|
### 🛠️ Available Tools (11 Tools)
|
||||||
|
|
||||||
|
| Tool Name | Description | Key Parameters |
|
||||||
|
|-----------|-------------|----------------|
|
||||||
|
| `create_draft` | Create new video draft project | width, height |
|
||||||
|
| `add_text` | Add text elements | text, font_size, color, shadow, background |
|
||||||
|
| `add_video` | Add video track | video_url, start, end, transform, volume |
|
||||||
|
| `add_audio` | Add audio track | audio_url, volume, speed, effects |
|
||||||
|
| `add_image` | Add image assets | image_url, transform, animation, transition |
|
||||||
|
| `add_subtitle` | Add subtitle files | srt_path, font_style, position |
|
||||||
|
| `add_effect` | Add visual effects | effect_type, parameters, duration |
|
||||||
|
| `add_sticker` | Add sticker elements | resource_id, position, scale, rotation |
|
||||||
|
| `add_video_keyframe` | Add keyframe animations | property_types, times, values |
|
||||||
|
| `get_video_duration` | Get video duration | video_url |
|
||||||
|
| `save_draft` | Save draft project | draft_id |
|
||||||
|
|
||||||
|
## Installation & Setup
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
- Python 3.10+
|
||||||
|
- CapCut Application (macOS/Windows)
|
||||||
|
- MCP Client Support
|
||||||
|
|
||||||
|
### Dependencies Installation
|
||||||
|
```bash
|
||||||
|
# Create virtual environment
|
||||||
|
python3.10 -m venv venv-mcp
|
||||||
|
source venv-mcp/bin/activate # macOS/Linux
|
||||||
|
# or venv-mcp\Scripts\activate # Windows
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
pip install -r requirements-mcp.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### MCP Configuration
|
||||||
|
Create or update `mcp_config.json` file:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"capcut-api": {
|
||||||
|
"command": "python3.10",
|
||||||
|
"args": ["mcp_server.py"],
|
||||||
|
"cwd": "/path/to/CapCutAPI-dev",
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "/path/to/CapCutAPI-dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage Guide
|
||||||
|
|
||||||
|
### Basic Workflow
|
||||||
|
|
||||||
|
#### 1. Create Draft
|
||||||
|
```python
|
||||||
|
# Create 1080x1920 portrait project
|
||||||
|
result = mcp_client.call_tool("create_draft", {
|
||||||
|
"width": 1080,
|
||||||
|
"height": 1920
|
||||||
|
})
|
||||||
|
draft_id = result["draft_id"]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. Add Content
|
||||||
|
```python
|
||||||
|
# Add title text
|
||||||
|
mcp_client.call_tool("add_text", {
|
||||||
|
"text": "My Video Title",
|
||||||
|
"start": 0,
|
||||||
|
"end": 5,
|
||||||
|
"draft_id": draft_id,
|
||||||
|
"font_size": 48,
|
||||||
|
"font_color": "#FFFFFF"
|
||||||
|
})
|
||||||
|
|
||||||
|
# Add background video
|
||||||
|
mcp_client.call_tool("add_video", {
|
||||||
|
"video_url": "https://example.com/video.mp4",
|
||||||
|
"draft_id": draft_id,
|
||||||
|
"start": 0,
|
||||||
|
"end": 10,
|
||||||
|
"volume": 0.8
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. Save Project
|
||||||
|
```python
|
||||||
|
# Save draft
|
||||||
|
result = mcp_client.call_tool("save_draft", {
|
||||||
|
"draft_id": draft_id
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Advanced Features
|
||||||
|
|
||||||
|
#### Text Styling
|
||||||
|
```python
|
||||||
|
# Text with shadow and background
|
||||||
|
mcp_client.call_tool("add_text", {
|
||||||
|
"text": "Advanced Text Effects",
|
||||||
|
"draft_id": draft_id,
|
||||||
|
"font_size": 56,
|
||||||
|
"font_color": "#FFD700",
|
||||||
|
"shadow_enabled": True,
|
||||||
|
"shadow_color": "#000000",
|
||||||
|
"shadow_alpha": 0.8,
|
||||||
|
"background_color": "#1E1E1E",
|
||||||
|
"background_alpha": 0.7,
|
||||||
|
"background_round_radius": 15
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Keyframe Animation
|
||||||
|
```python
|
||||||
|
# Scale and opacity animation
|
||||||
|
mcp_client.call_tool("add_video_keyframe", {
|
||||||
|
"draft_id": draft_id,
|
||||||
|
"track_name": "video_main",
|
||||||
|
"property_types": ["scale_x", "scale_y", "alpha"],
|
||||||
|
"times": [0, 2, 4],
|
||||||
|
"values": ["1.0", "1.5", "0.5"]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Multi-Style Text
|
||||||
|
```python
|
||||||
|
# Different colored text segments
|
||||||
|
mcp_client.call_tool("add_text", {
|
||||||
|
"text": "Colorful Text Effect",
|
||||||
|
"draft_id": draft_id,
|
||||||
|
"text_styles": [
|
||||||
|
{"start": 0, "end": 2, "font_color": "#FF0000"},
|
||||||
|
{"start": 2, "end": 4, "font_color": "#00FF00"}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing & Validation
|
||||||
|
|
||||||
|
### Using Test Client
|
||||||
|
```bash
|
||||||
|
# Run test client
|
||||||
|
python test_mcp_client.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Functionality Checklist
|
||||||
|
- [ ] Server starts successfully
|
||||||
|
- [ ] Tool list retrieval works
|
||||||
|
- [ ] Draft creation functionality
|
||||||
|
- [ ] Text addition functionality
|
||||||
|
- [ ] Video/audio/image addition
|
||||||
|
- [ ] Effects and animation functionality
|
||||||
|
- [ ] Draft saving functionality
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
#### 1. "CapCut modules not available"
|
||||||
|
**Solution**:
|
||||||
|
- Confirm CapCut application is installed
|
||||||
|
- Check Python path configuration
|
||||||
|
- Verify dependency package installation
|
||||||
|
|
||||||
|
#### 2. Server startup failure
|
||||||
|
**Solution**:
|
||||||
|
- Check virtual environment activation
|
||||||
|
- Verify configuration file paths
|
||||||
|
- Review error logs
|
||||||
|
|
||||||
|
#### 3. Tool call errors
|
||||||
|
**Solution**:
|
||||||
|
- Check parameter format
|
||||||
|
- Verify media file URLs
|
||||||
|
- Confirm time range settings
|
||||||
|
|
||||||
|
### Debug Mode
|
||||||
|
```bash
|
||||||
|
# Enable verbose logging
|
||||||
|
export DEBUG=1
|
||||||
|
python mcp_server.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Performance Optimization
|
||||||
|
1. **Media Files**: Use compressed formats, avoid oversized files
|
||||||
|
2. **Time Management**: Plan element timelines reasonably, avoid overlaps
|
||||||
|
3. **Memory Usage**: Save drafts promptly, clean temporary files
|
||||||
|
|
||||||
|
### Error Handling
|
||||||
|
1. **Parameter Validation**: Check required parameters before calling
|
||||||
|
2. **Exception Catching**: Handle network and file errors
|
||||||
|
3. **Retry Mechanism**: Retry on temporary failures
|
||||||
|
|
||||||
|
## API Reference
|
||||||
|
|
||||||
|
### Common Parameters
|
||||||
|
- `draft_id`: Unique draft identifier
|
||||||
|
- `start/end`: Time range (seconds)
|
||||||
|
- `width/height`: Project dimensions
|
||||||
|
- `transform_x/y`: Position coordinates
|
||||||
|
- `scale_x/y`: Scale ratios
|
||||||
|
|
||||||
|
### Response Format
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"result": {
|
||||||
|
"draft_id": "dfd_cat_xxx",
|
||||||
|
"draft_url": "https://..."
|
||||||
|
},
|
||||||
|
"features_used": {
|
||||||
|
"shadow": false,
|
||||||
|
"background": false,
|
||||||
|
"multi_style": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
### v1.0.0
|
||||||
|
- Initial release
|
||||||
|
- Support for 11 core tools
|
||||||
|
- Complete MCP protocol implementation
|
||||||
|
|
||||||
|
## Technical Support
|
||||||
|
|
||||||
|
For questions or suggestions, please contact us through:
|
||||||
|
- GitHub Issues
|
||||||
|
- Technical Documentation
|
||||||
|
- Community Forums
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*This documentation is continuously updated. Please follow the latest version.*
|
||||||
254
MCP_文档_中文.md
Normal file
254
MCP_文档_中文.md
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
# CapCut API MCP 服务器使用文档
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
CapCut API MCP 服务器是一个基于 Model Context Protocol (MCP) 的视频编辑服务,提供了完整的 CapCut 视频编辑功能接口。通过 MCP 协议,您可以轻松地在各种应用中集成专业级的视频编辑能力。
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
### 🎬 核心功能
|
||||||
|
- **草稿管理**: 创建、保存和管理视频项目
|
||||||
|
- **多媒体支持**: 视频、音频、图片、文本处理
|
||||||
|
- **高级效果**: 特效、动画、转场、滤镜
|
||||||
|
- **精确控制**: 时间轴、关键帧、图层管理
|
||||||
|
|
||||||
|
### 🛠️ 可用工具 (11个)
|
||||||
|
|
||||||
|
| 工具名称 | 功能描述 | 主要参数 |
|
||||||
|
|---------|----------|----------|
|
||||||
|
| `create_draft` | 创建新的视频草稿项目 | width, height |
|
||||||
|
| `add_text` | 添加文字元素 | text, font_size, color, shadow, background |
|
||||||
|
| `add_video` | 添加视频轨道 | video_url, start, end, transform, volume |
|
||||||
|
| `add_audio` | 添加音频轨道 | audio_url, volume, speed, effects |
|
||||||
|
| `add_image` | 添加图片素材 | image_url, transform, animation, transition |
|
||||||
|
| `add_subtitle` | 添加字幕文件 | srt_path, font_style, position |
|
||||||
|
| `add_effect` | 添加视觉特效 | effect_type, parameters, duration |
|
||||||
|
| `add_sticker` | 添加贴纸元素 | resource_id, position, scale, rotation |
|
||||||
|
| `add_video_keyframe` | 添加关键帧动画 | property_types, times, values |
|
||||||
|
| `get_video_duration` | 获取视频时长 | video_url |
|
||||||
|
| `save_draft` | 保存草稿项目 | draft_id |
|
||||||
|
|
||||||
|
## 安装配置
|
||||||
|
|
||||||
|
### 环境要求
|
||||||
|
- Python 3.10+
|
||||||
|
- CapCut 应用 (macOS/Windows)
|
||||||
|
- MCP 客户端支持
|
||||||
|
|
||||||
|
### 依赖安装
|
||||||
|
```bash
|
||||||
|
# 创建虚拟环境
|
||||||
|
python3.10 -m venv venv-mcp
|
||||||
|
source venv-mcp/bin/activate # macOS/Linux
|
||||||
|
# 或 venv-mcp\Scripts\activate # Windows
|
||||||
|
|
||||||
|
# 安装依赖
|
||||||
|
pip install -r requirements-mcp.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### MCP 配置
|
||||||
|
创建或更新 `mcp_config.json` 文件:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"capcut-api": {
|
||||||
|
"command": "python3.10",
|
||||||
|
"args": ["mcp_server.py"],
|
||||||
|
"cwd": "/path/to/CapCutAPI-dev",
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "/path/to/CapCutAPI-dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用指南
|
||||||
|
|
||||||
|
### 基础工作流程
|
||||||
|
|
||||||
|
#### 1. 创建草稿
|
||||||
|
```python
|
||||||
|
# 创建 1080x1920 竖屏项目
|
||||||
|
result = mcp_client.call_tool("create_draft", {
|
||||||
|
"width": 1080,
|
||||||
|
"height": 1920
|
||||||
|
})
|
||||||
|
draft_id = result["draft_id"]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. 添加内容
|
||||||
|
```python
|
||||||
|
# 添加标题文字
|
||||||
|
mcp_client.call_tool("add_text", {
|
||||||
|
"text": "我的视频标题",
|
||||||
|
"start": 0,
|
||||||
|
"end": 5,
|
||||||
|
"draft_id": draft_id,
|
||||||
|
"font_size": 48,
|
||||||
|
"font_color": "#FFFFFF"
|
||||||
|
})
|
||||||
|
|
||||||
|
# 添加背景视频
|
||||||
|
mcp_client.call_tool("add_video", {
|
||||||
|
"video_url": "https://example.com/video.mp4",
|
||||||
|
"draft_id": draft_id,
|
||||||
|
"start": 0,
|
||||||
|
"end": 10,
|
||||||
|
"volume": 0.8
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. 保存项目
|
||||||
|
```python
|
||||||
|
# 保存草稿
|
||||||
|
result = mcp_client.call_tool("save_draft", {
|
||||||
|
"draft_id": draft_id
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### 高级功能示例
|
||||||
|
|
||||||
|
#### 文字样式设置
|
||||||
|
```python
|
||||||
|
# 带阴影和背景的文字
|
||||||
|
mcp_client.call_tool("add_text", {
|
||||||
|
"text": "高级文字效果",
|
||||||
|
"draft_id": draft_id,
|
||||||
|
"font_size": 56,
|
||||||
|
"font_color": "#FFD700",
|
||||||
|
"shadow_enabled": True,
|
||||||
|
"shadow_color": "#000000",
|
||||||
|
"shadow_alpha": 0.8,
|
||||||
|
"background_color": "#1E1E1E",
|
||||||
|
"background_alpha": 0.7,
|
||||||
|
"background_round_radius": 15
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 关键帧动画
|
||||||
|
```python
|
||||||
|
# 缩放和透明度动画
|
||||||
|
mcp_client.call_tool("add_video_keyframe", {
|
||||||
|
"draft_id": draft_id,
|
||||||
|
"track_name": "video_main",
|
||||||
|
"property_types": ["scale_x", "scale_y", "alpha"],
|
||||||
|
"times": [0, 2, 4],
|
||||||
|
"values": ["1.0", "1.5", "0.5"]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 多样式文本
|
||||||
|
```python
|
||||||
|
# 不同颜色的文字段落
|
||||||
|
mcp_client.call_tool("add_text", {
|
||||||
|
"text": "彩色文字效果",
|
||||||
|
"draft_id": draft_id,
|
||||||
|
"text_styles": [
|
||||||
|
{"start": 0, "end": 2, "font_color": "#FF0000"},
|
||||||
|
{"start": 2, "end": 4, "font_color": "#00FF00"}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## 测试验证
|
||||||
|
|
||||||
|
### 使用测试客户端
|
||||||
|
```bash
|
||||||
|
# 运行测试客户端
|
||||||
|
python test_mcp_client.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### 功能验证清单
|
||||||
|
- [ ] 服务器启动成功
|
||||||
|
- [ ] 工具列表获取正常
|
||||||
|
- [ ] 草稿创建功能
|
||||||
|
- [ ] 文本添加功能
|
||||||
|
- [ ] 视频/音频/图片添加
|
||||||
|
- [ ] 特效和动画功能
|
||||||
|
- [ ] 草稿保存功能
|
||||||
|
|
||||||
|
## 故障排除
|
||||||
|
|
||||||
|
### 常见问题
|
||||||
|
|
||||||
|
#### 1. "CapCut modules not available"
|
||||||
|
**解决方案**:
|
||||||
|
- 确认 CapCut 应用已安装
|
||||||
|
- 检查 Python 路径配置
|
||||||
|
- 验证依赖包安装
|
||||||
|
|
||||||
|
#### 2. 服务器启动失败
|
||||||
|
**解决方案**:
|
||||||
|
- 检查虚拟环境激活
|
||||||
|
- 验证配置文件路径
|
||||||
|
- 查看错误日志
|
||||||
|
|
||||||
|
#### 3. 工具调用错误
|
||||||
|
**解决方案**:
|
||||||
|
- 检查参数格式
|
||||||
|
- 验证媒体文件URL
|
||||||
|
- 确认时间范围设置
|
||||||
|
|
||||||
|
### 调试模式
|
||||||
|
```bash
|
||||||
|
# 启用详细日志
|
||||||
|
export DEBUG=1
|
||||||
|
python mcp_server.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 最佳实践
|
||||||
|
|
||||||
|
### 性能优化
|
||||||
|
1. **媒体文件**: 使用压缩格式,避免过大文件
|
||||||
|
2. **时间管理**: 合理规划元素时间轴,避免重叠
|
||||||
|
3. **内存使用**: 及时保存草稿,清理临时文件
|
||||||
|
|
||||||
|
### 错误处理
|
||||||
|
1. **参数验证**: 调用前检查必需参数
|
||||||
|
2. **异常捕获**: 处理网络和文件错误
|
||||||
|
3. **重试机制**: 对临时失败进行重试
|
||||||
|
|
||||||
|
## API 参考
|
||||||
|
|
||||||
|
### 通用参数
|
||||||
|
- `draft_id`: 草稿唯一标识符
|
||||||
|
- `start/end`: 时间范围(秒)
|
||||||
|
- `width/height`: 项目尺寸
|
||||||
|
- `transform_x/y`: 位置坐标
|
||||||
|
- `scale_x/y`: 缩放比例
|
||||||
|
|
||||||
|
### 返回格式
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"result": {
|
||||||
|
"draft_id": "dfd_cat_xxx",
|
||||||
|
"draft_url": "https://..."
|
||||||
|
},
|
||||||
|
"features_used": {
|
||||||
|
"shadow": false,
|
||||||
|
"background": false,
|
||||||
|
"multi_style": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 更新日志
|
||||||
|
|
||||||
|
### v1.0.0
|
||||||
|
- 初始版本发布
|
||||||
|
- 支持 11 个核心工具
|
||||||
|
- 完整的 MCP 协议实现
|
||||||
|
|
||||||
|
## 技术支持
|
||||||
|
|
||||||
|
如有问题或建议,请通过以下方式联系:
|
||||||
|
- GitHub Issues
|
||||||
|
- 技术文档
|
||||||
|
- 社区论坛
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*本文档持续更新,请关注最新版本。*
|
||||||
@@ -2,45 +2,63 @@ import pyJianYingDraft as draft
|
|||||||
from settings.local import IS_CAPCUT_ENV
|
from settings.local import IS_CAPCUT_ENV
|
||||||
from util import generate_draft_url, hex_to_rgb
|
from util import generate_draft_url, hex_to_rgb
|
||||||
from pyJianYingDraft import trange, Font_type
|
from pyJianYingDraft import trange, Font_type
|
||||||
from typing import Optional
|
from typing import Optional, List # 修复List导入
|
||||||
from pyJianYingDraft import exceptions
|
from pyJianYingDraft import exceptions
|
||||||
from create_draft import get_or_create_draft
|
from create_draft import get_or_create_draft
|
||||||
from pyJianYingDraft.text_segment import TextBubble, TextEffect
|
from pyJianYingDraft.text_segment import TextBubble, TextEffect, TextStyleRange
|
||||||
|
|
||||||
|
# 使用Python 3.10+的新特性:Union类型可以用 | 替代
|
||||||
|
# from typing import Union
|
||||||
|
# 可以写成: str | None 而不是 Optional[str]
|
||||||
|
|
||||||
def add_text_impl(
|
def add_text_impl(
|
||||||
text: str,
|
text: str,
|
||||||
start: float,
|
start: float,
|
||||||
end: float,
|
end: float,
|
||||||
draft_id: str = None,
|
draft_id: str | None = None, # Python 3.10+ 新语法
|
||||||
transform_y: float = -0.8,
|
transform_y: float = -0.8,
|
||||||
transform_x: float = 0,
|
transform_x: float = 0,
|
||||||
font: str = "文轩体", # Wenxuan Font
|
font: str = "文轩体",
|
||||||
font_color: str = "#ffffff",
|
font_color: str = "#ffffff",
|
||||||
font_size: float = 8.0,
|
font_size: float = 8.0,
|
||||||
track_name: str = "text_main",
|
track_name: str = "text_main",
|
||||||
vertical: bool = False, # Whether to display vertically
|
vertical: bool = False,
|
||||||
font_alpha: float = 1.0, # Transparency, range 0.0-1.0
|
font_alpha: float = 1.0,
|
||||||
# Border parameters
|
# Border parameters
|
||||||
border_alpha: float = 1.0,
|
border_alpha: float = 1.0,
|
||||||
border_color: str = "#000000",
|
border_color: str = "#000000",
|
||||||
border_width: float = 0.0, # Default no border display
|
border_width: float = 0.0,
|
||||||
# Background parameters
|
# Background parameters
|
||||||
background_color: str = "#000000",
|
background_color: str = "#000000",
|
||||||
background_style: int = 1,
|
background_style: int = 1,
|
||||||
background_alpha: float = 0.0, # Default no background display
|
background_alpha: float = 0.0,
|
||||||
|
background_round_radius: float = 0.0,
|
||||||
|
background_height: float = 0.14,
|
||||||
|
background_width: float = 0.14,
|
||||||
|
background_horizontal_offset: float = 0.5,
|
||||||
|
background_vertical_offset: float = 0.5,
|
||||||
|
# Shadow parameters
|
||||||
|
shadow_enabled: bool = False,
|
||||||
|
shadow_alpha: float = 0.9,
|
||||||
|
shadow_angle: float = -45.0,
|
||||||
|
shadow_color: str = "#000000",
|
||||||
|
shadow_distance: float = 5.0,
|
||||||
|
shadow_smoothing: float = 0.15,
|
||||||
# Bubble effect
|
# Bubble effect
|
||||||
bubble_effect_id: Optional[str] = None,
|
bubble_effect_id: str | None = None,
|
||||||
bubble_resource_id: Optional[str] = None,
|
bubble_resource_id: str | None = None,
|
||||||
# Text effect
|
# Text effect
|
||||||
effect_effect_id: Optional[str] = None,
|
effect_effect_id: str | None = None,
|
||||||
intro_animation: Optional[str] = None, # Intro animation type
|
intro_animation: str | None = None,
|
||||||
intro_duration: float = 0.5, # Intro animation duration (seconds), default 0.5 seconds
|
intro_duration: float = 0.5,
|
||||||
outro_animation: Optional[str] = None, # Outro animation type
|
outro_animation: str | None = None,
|
||||||
outro_duration: float = 0.5, # Outro animation duration (seconds), default 0.5 seconds
|
outro_duration: float = 0.5,
|
||||||
width: int = 1080,
|
width: int = 1080,
|
||||||
height: int = 1920,
|
height: int = 1920,
|
||||||
fixed_width: float = -1, # Text fixed width ratio, default -1 means not fixed
|
fixed_width: float = -1,
|
||||||
fixed_height: float = -1, # Text fixed height ratio, default -1 means not fixed
|
fixed_height: float = -1,
|
||||||
|
# Multi-style text parameters
|
||||||
|
text_styles: List[TextStyleRange] | None = None, # 使用新语法
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Add text subtitle to the specified draft (configurable parameter version)
|
Add text subtitle to the specified draft (configurable parameter version)
|
||||||
@@ -62,6 +80,17 @@ def add_text_impl(
|
|||||||
:param background_color: Background color (default black)
|
:param background_color: Background color (default black)
|
||||||
:param background_style: Background style (default 1)
|
:param background_style: Background style (default 1)
|
||||||
:param background_alpha: Background transparency (default 0.0, no background display)
|
:param background_alpha: Background transparency (default 0.0, no background display)
|
||||||
|
:param background_round_radius: 背景圆角半径,范围0.0-1.0(默认0.0)
|
||||||
|
:param background_height: 背景高度,范围0.0-1.0(默认0.14)
|
||||||
|
:param background_width: 背景宽度,范围0.0-1.0(默认0.14)
|
||||||
|
:param background_horizontal_offset: 背景水平偏移,范围0.0-1.0(默认0.5)
|
||||||
|
:param background_vertical_offset: 背景垂直偏移,范围0.0-1.0(默认0.5)
|
||||||
|
:param shadow_enabled: 是否启用阴影(默认False)
|
||||||
|
:param shadow_alpha: 阴影透明度,范围0.0-1.0(默认0.9)
|
||||||
|
:param shadow_angle: 阴影角度,范围-180.0-180.0(默认-45.0)
|
||||||
|
:param shadow_color: 阴影颜色(默认黑色)
|
||||||
|
:param shadow_distance: 阴影距离(默认5.0)
|
||||||
|
:param shadow_smoothing: 阴影平滑度,范围0.0-1.0(默认0.15)
|
||||||
:param bubble_effect_id: Bubble effect ID
|
:param bubble_effect_id: Bubble effect ID
|
||||||
:param bubble_resource_id: Bubble resource ID
|
:param bubble_resource_id: Bubble resource ID
|
||||||
:param effect_effect_id: Text effect ID
|
:param effect_effect_id: Text effect ID
|
||||||
@@ -73,6 +102,7 @@ def add_text_impl(
|
|||||||
:param height: Video height (pixels)
|
:param height: Video height (pixels)
|
||||||
:param fixed_width: Text fixed width ratio, range 0.0-1.0, default -1 means not fixed
|
:param fixed_width: Text fixed width ratio, range 0.0-1.0, default -1 means not fixed
|
||||||
:param fixed_height: Text fixed height ratio, range 0.0-1.0, default -1 means not fixed
|
:param fixed_height: Text fixed height ratio, range 0.0-1.0, default -1 means not fixed
|
||||||
|
:param text_styles: 文本的不同部分的样式列表,每个元素是一个TextStyleRange
|
||||||
:return: Updated draft information
|
:return: Updated draft information
|
||||||
"""
|
"""
|
||||||
# Validate if font is in Font_type
|
# Validate if font is in Font_type
|
||||||
@@ -130,9 +160,26 @@ def add_text_impl(
|
|||||||
text_background = draft.Text_background(
|
text_background = draft.Text_background(
|
||||||
color=background_color,
|
color=background_color,
|
||||||
style=background_style,
|
style=background_style,
|
||||||
alpha=background_alpha
|
alpha=background_alpha,
|
||||||
|
round_radius=background_round_radius,
|
||||||
|
height=background_height,
|
||||||
|
width=background_width,
|
||||||
|
horizontal_offset=background_horizontal_offset,
|
||||||
|
vertical_offset=background_vertical_offset
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 创建text_shadow (阴影)
|
||||||
|
text_shadow = None
|
||||||
|
if shadow_enabled:
|
||||||
|
text_shadow = draft.Text_shadow(
|
||||||
|
has_shadow=shadow_enabled,
|
||||||
|
alpha=shadow_alpha,
|
||||||
|
angle=shadow_angle,
|
||||||
|
color=shadow_color,
|
||||||
|
distance=shadow_distance,
|
||||||
|
smoothing=shadow_smoothing
|
||||||
|
)
|
||||||
|
|
||||||
# Create bubble effect
|
# Create bubble effect
|
||||||
text_bubble = None
|
text_bubble = None
|
||||||
if bubble_effect_id and bubble_resource_id:
|
if bubble_effect_id and bubble_resource_id:
|
||||||
@@ -171,10 +218,21 @@ def add_text_impl(
|
|||||||
clip_settings=draft.Clip_settings(transform_y=transform_y, transform_x=transform_x),
|
clip_settings=draft.Clip_settings(transform_y=transform_y, transform_x=transform_x),
|
||||||
border=text_border,
|
border=text_border,
|
||||||
background=text_background,
|
background=text_background,
|
||||||
|
shadow=text_shadow,
|
||||||
fixed_width=pixel_fixed_width,
|
fixed_width=pixel_fixed_width,
|
||||||
fixed_height=pixel_fixed_height
|
fixed_height=pixel_fixed_height
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 应用多样式文本设置
|
||||||
|
if text_styles:
|
||||||
|
for style_range in text_styles:
|
||||||
|
# 验证范围有效性
|
||||||
|
if style_range.start < 0 or style_range.end > len(text) or style_range.start >= style_range.end:
|
||||||
|
raise ValueError(f"无效的文本范围: [{style_range.start}, {style_range.end}), 文本长度: {len(text)}")
|
||||||
|
|
||||||
|
# 应用样式到特定文本范围
|
||||||
|
text_segment.add_text_style(style_range)
|
||||||
|
|
||||||
if text_bubble:
|
if text_bubble:
|
||||||
text_segment.add_bubble(text_bubble.effect_id, text_bubble.resource_id)
|
text_segment.add_bubble(text_bubble.effect_id, text_bubble.resource_id)
|
||||||
if text_effect:
|
if text_effect:
|
||||||
|
|||||||
12
mcp_config.json
Normal file
12
mcp_config.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"capcut-api": {
|
||||||
|
"command": "python3.10",
|
||||||
|
"args": ["mcp_server.py"],
|
||||||
|
"cwd": "/Users/chuham/Downloads/CapCutAPI-dev",
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "/Users/chuham/Downloads/CapCutAPI-dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
479
mcp_server.py
Normal file
479
mcp_server.py
Normal file
@@ -0,0 +1,479 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
CapCut API MCP Server (Complete Version)
|
||||||
|
|
||||||
|
完整版本的MCP服务器,集成所有CapCut API接口
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import traceback
|
||||||
|
import io
|
||||||
|
import contextlib
|
||||||
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
|
# 添加项目根目录到Python路径
|
||||||
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
# 导入CapCut API功能
|
||||||
|
try:
|
||||||
|
from create_draft import get_or_create_draft
|
||||||
|
from add_text_impl import add_text_impl
|
||||||
|
from add_video_track import add_video_track
|
||||||
|
from add_audio_track import add_audio_track
|
||||||
|
from add_image_impl import add_image_impl
|
||||||
|
from add_subtitle_impl import add_subtitle_impl
|
||||||
|
from add_effect_impl import add_effect_impl
|
||||||
|
from add_sticker_impl import add_sticker_impl
|
||||||
|
from add_video_keyframe_impl import add_video_keyframe_impl
|
||||||
|
from get_duration_impl import get_video_duration
|
||||||
|
from save_draft_impl import save_draft_impl
|
||||||
|
from pyJianYingDraft.text_segment import TextStyleRange
|
||||||
|
CAPCUT_AVAILABLE = True
|
||||||
|
except ImportError as e:
|
||||||
|
print(f"Warning: Could not import CapCut modules: {e}", file=sys.stderr)
|
||||||
|
CAPCUT_AVAILABLE = False
|
||||||
|
|
||||||
|
# 完整的工具定义
|
||||||
|
TOOLS = [
|
||||||
|
{
|
||||||
|
"name": "create_draft",
|
||||||
|
"description": "创建新的CapCut草稿",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"width": {"type": "integer", "default": 1080, "description": "视频宽度"},
|
||||||
|
"height": {"type": "integer", "default": 1920, "description": "视频高度"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "add_video",
|
||||||
|
"description": "添加视频到草稿,支持转场、蒙版、背景模糊等效果",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"video_url": {"type": "string", "description": "视频URL"},
|
||||||
|
"draft_id": {"type": "string", "description": "草稿ID"},
|
||||||
|
"start": {"type": "number", "default": 0, "description": "开始时间(秒)"},
|
||||||
|
"end": {"type": "number", "description": "结束时间(秒)"},
|
||||||
|
"target_start": {"type": "number", "default": 0, "description": "目标开始时间(秒)"},
|
||||||
|
"width": {"type": "integer", "default": 1080, "description": "视频宽度"},
|
||||||
|
"height": {"type": "integer", "default": 1920, "description": "视频高度"},
|
||||||
|
"transform_x": {"type": "number", "default": 0, "description": "X轴位置"},
|
||||||
|
"transform_y": {"type": "number", "default": 0, "description": "Y轴位置"},
|
||||||
|
"scale_x": {"type": "number", "default": 1, "description": "X轴缩放"},
|
||||||
|
"scale_y": {"type": "number", "default": 1, "description": "Y轴缩放"},
|
||||||
|
"speed": {"type": "number", "default": 1.0, "description": "播放速度"},
|
||||||
|
"track_name": {"type": "string", "default": "main", "description": "轨道名称"},
|
||||||
|
"volume": {"type": "number", "default": 1.0, "description": "音量"},
|
||||||
|
"transition": {"type": "string", "description": "转场类型"},
|
||||||
|
"transition_duration": {"type": "number", "default": 0.5, "description": "转场时长"},
|
||||||
|
"mask_type": {"type": "string", "description": "蒙版类型"},
|
||||||
|
"background_blur": {"type": "integer", "description": "背景模糊级别(1-4)"}
|
||||||
|
},
|
||||||
|
"required": ["video_url"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "add_audio",
|
||||||
|
"description": "添加音频到草稿,支持音效处理",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"audio_url": {"type": "string", "description": "音频URL"},
|
||||||
|
"draft_id": {"type": "string", "description": "草稿ID"},
|
||||||
|
"start": {"type": "number", "default": 0, "description": "开始时间(秒)"},
|
||||||
|
"end": {"type": "number", "description": "结束时间(秒)"},
|
||||||
|
"target_start": {"type": "number", "default": 0, "description": "目标开始时间(秒)"},
|
||||||
|
"volume": {"type": "number", "default": 1.0, "description": "音量"},
|
||||||
|
"speed": {"type": "number", "default": 1.0, "description": "播放速度"},
|
||||||
|
"track_name": {"type": "string", "default": "audio_main", "description": "轨道名称"},
|
||||||
|
"width": {"type": "integer", "default": 1080, "description": "视频宽度"},
|
||||||
|
"height": {"type": "integer", "default": 1920, "description": "视频高度"}
|
||||||
|
},
|
||||||
|
"required": ["audio_url"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "add_image",
|
||||||
|
"description": "添加图片到草稿,支持动画、转场、蒙版等效果",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"image_url": {"type": "string", "description": "图片URL"},
|
||||||
|
"draft_id": {"type": "string", "description": "草稿ID"},
|
||||||
|
"start": {"type": "number", "default": 0, "description": "开始时间(秒)"},
|
||||||
|
"end": {"type": "number", "default": 3.0, "description": "结束时间(秒)"},
|
||||||
|
"width": {"type": "integer", "default": 1080, "description": "视频宽度"},
|
||||||
|
"height": {"type": "integer", "default": 1920, "description": "视频高度"},
|
||||||
|
"transform_x": {"type": "number", "default": 0, "description": "X轴位置"},
|
||||||
|
"transform_y": {"type": "number", "default": 0, "description": "Y轴位置"},
|
||||||
|
"scale_x": {"type": "number", "default": 1, "description": "X轴缩放"},
|
||||||
|
"scale_y": {"type": "number", "default": 1, "description": "Y轴缩放"},
|
||||||
|
"track_name": {"type": "string", "default": "main", "description": "轨道名称"},
|
||||||
|
"intro_animation": {"type": "string", "description": "入场动画"},
|
||||||
|
"outro_animation": {"type": "string", "description": "出场动画"},
|
||||||
|
"transition": {"type": "string", "description": "转场类型"},
|
||||||
|
"mask_type": {"type": "string", "description": "蒙版类型"}
|
||||||
|
},
|
||||||
|
"required": ["image_url"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "add_text",
|
||||||
|
"description": "添加文本到草稿,支持文本多样式、文字阴影和文字背景",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"text": {"type": "string", "description": "文本内容"},
|
||||||
|
"start": {"type": "number", "description": "开始时间(秒)"},
|
||||||
|
"end": {"type": "number", "description": "结束时间(秒)"},
|
||||||
|
"draft_id": {"type": "string", "description": "草稿ID"},
|
||||||
|
"font_color": {"type": "string", "default": "#ffffff", "description": "字体颜色"},
|
||||||
|
"font_size": {"type": "integer", "default": 24, "description": "字体大小"},
|
||||||
|
"shadow_enabled": {"type": "boolean", "default": False, "description": "是否启用文字阴影"},
|
||||||
|
"shadow_color": {"type": "string", "default": "#000000", "description": "阴影颜色"},
|
||||||
|
"shadow_alpha": {"type": "number", "default": 0.8, "description": "阴影透明度"},
|
||||||
|
"shadow_angle": {"type": "number", "default": 315.0, "description": "阴影角度"},
|
||||||
|
"shadow_distance": {"type": "number", "default": 5.0, "description": "阴影距离"},
|
||||||
|
"shadow_smoothing": {"type": "number", "default": 0.0, "description": "阴影平滑度"},
|
||||||
|
"background_color": {"type": "string", "description": "背景颜色"},
|
||||||
|
"background_alpha": {"type": "number", "default": 1.0, "description": "背景透明度"},
|
||||||
|
"background_style": {"type": "integer", "default": 0, "description": "背景样式"},
|
||||||
|
"background_round_radius": {"type": "number", "default": 0.0, "description": "背景圆角半径"},
|
||||||
|
"text_styles": {"type": "array", "description": "文本多样式配置列表"}
|
||||||
|
},
|
||||||
|
"required": ["text", "start", "end"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "add_subtitle",
|
||||||
|
"description": "添加字幕到草稿,支持SRT文件和样式设置",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"srt_path": {"type": "string", "description": "SRT字幕文件路径或URL"},
|
||||||
|
"draft_id": {"type": "string", "description": "草稿ID"},
|
||||||
|
"track_name": {"type": "string", "default": "subtitle", "description": "轨道名称"},
|
||||||
|
"time_offset": {"type": "number", "default": 0, "description": "时间偏移(秒)"},
|
||||||
|
"font": {"type": "string", "description": "字体"},
|
||||||
|
"font_size": {"type": "number", "default": 8.0, "description": "字体大小"},
|
||||||
|
"font_color": {"type": "string", "default": "#FFFFFF", "description": "字体颜色"},
|
||||||
|
"bold": {"type": "boolean", "default": False, "description": "是否粗体"},
|
||||||
|
"italic": {"type": "boolean", "default": False, "description": "是否斜体"},
|
||||||
|
"underline": {"type": "boolean", "default": False, "description": "是否下划线"},
|
||||||
|
"border_width": {"type": "number", "default": 0.0, "description": "边框宽度"},
|
||||||
|
"border_color": {"type": "string", "default": "#000000", "description": "边框颜色"},
|
||||||
|
"background_color": {"type": "string", "default": "#000000", "description": "背景颜色"},
|
||||||
|
"background_alpha": {"type": "number", "default": 0.0, "description": "背景透明度"},
|
||||||
|
"transform_x": {"type": "number", "default": 0.0, "description": "X轴位置"},
|
||||||
|
"transform_y": {"type": "number", "default": -0.8, "description": "Y轴位置"},
|
||||||
|
"width": {"type": "integer", "default": 1080, "description": "视频宽度"},
|
||||||
|
"height": {"type": "integer", "default": 1920, "description": "视频高度"}
|
||||||
|
},
|
||||||
|
"required": ["srt_path"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "add_effect",
|
||||||
|
"description": "添加特效到草稿",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"effect_type": {"type": "string", "description": "特效类型名称"},
|
||||||
|
"draft_id": {"type": "string", "description": "草稿ID"},
|
||||||
|
"start": {"type": "number", "default": 0, "description": "开始时间(秒)"},
|
||||||
|
"end": {"type": "number", "default": 3.0, "description": "结束时间(秒)"},
|
||||||
|
"track_name": {"type": "string", "default": "effect_01", "description": "轨道名称"},
|
||||||
|
"params": {"type": "array", "description": "特效参数列表"},
|
||||||
|
"width": {"type": "integer", "default": 1080, "description": "视频宽度"},
|
||||||
|
"height": {"type": "integer", "default": 1920, "description": "视频高度"}
|
||||||
|
},
|
||||||
|
"required": ["effect_type"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "add_sticker",
|
||||||
|
"description": "添加贴纸到草稿",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"resource_id": {"type": "string", "description": "贴纸资源ID"},
|
||||||
|
"draft_id": {"type": "string", "description": "草稿ID"},
|
||||||
|
"start": {"type": "number", "description": "开始时间(秒)"},
|
||||||
|
"end": {"type": "number", "description": "结束时间(秒)"},
|
||||||
|
"transform_x": {"type": "number", "default": 0, "description": "X轴位置"},
|
||||||
|
"transform_y": {"type": "number", "default": 0, "description": "Y轴位置"},
|
||||||
|
"scale_x": {"type": "number", "default": 1.0, "description": "X轴缩放"},
|
||||||
|
"scale_y": {"type": "number", "default": 1.0, "description": "Y轴缩放"},
|
||||||
|
"alpha": {"type": "number", "default": 1.0, "description": "透明度"},
|
||||||
|
"rotation": {"type": "number", "default": 0.0, "description": "旋转角度"},
|
||||||
|
"track_name": {"type": "string", "default": "sticker_main", "description": "轨道名称"},
|
||||||
|
"width": {"type": "integer", "default": 1080, "description": "视频宽度"},
|
||||||
|
"height": {"type": "integer", "default": 1920, "description": "视频高度"}
|
||||||
|
},
|
||||||
|
"required": ["resource_id", "start", "end"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "add_video_keyframe",
|
||||||
|
"description": "添加视频关键帧,支持位置、缩放、旋转、透明度等属性动画",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"draft_id": {"type": "string", "description": "草稿ID"},
|
||||||
|
"track_name": {"type": "string", "default": "main", "description": "轨道名称"},
|
||||||
|
"property_type": {"type": "string", "description": "关键帧属性类型(position_x, position_y, rotation, scale_x, scale_y, uniform_scale, alpha, saturation, contrast, brightness, volume)"},
|
||||||
|
"time": {"type": "number", "default": 0.0, "description": "关键帧时间点(秒)"},
|
||||||
|
"value": {"type": "string", "description": "关键帧值"},
|
||||||
|
"property_types": {"type": "array", "description": "批量模式:关键帧属性类型列表"},
|
||||||
|
"times": {"type": "array", "description": "批量模式:关键帧时间点列表"},
|
||||||
|
"values": {"type": "array", "description": "批量模式:关键帧值列表"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "get_video_duration",
|
||||||
|
"description": "获取视频时长",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"video_url": {"type": "string", "description": "视频URL"}
|
||||||
|
},
|
||||||
|
"required": ["video_url"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "save_draft",
|
||||||
|
"description": "保存草稿",
|
||||||
|
"inputSchema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"draft_id": {"type": "string", "description": "草稿ID"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def capture_stdout():
|
||||||
|
"""捕获标准输出,防止CapCut API的调试信息干扰JSON响应"""
|
||||||
|
old_stdout = sys.stdout
|
||||||
|
sys.stdout = io.StringIO()
|
||||||
|
try:
|
||||||
|
yield sys.stdout
|
||||||
|
finally:
|
||||||
|
sys.stdout = old_stdout
|
||||||
|
|
||||||
|
def convert_text_styles(text_styles_data):
|
||||||
|
"""将字典格式的text_styles转换为TextStyleRange对象列表"""
|
||||||
|
if not text_styles_data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
text_style_ranges = []
|
||||||
|
for style_dict in text_styles_data:
|
||||||
|
style_range = TextStyleRange(
|
||||||
|
start=style_dict.get("start", 0),
|
||||||
|
end=style_dict.get("end", 0),
|
||||||
|
font_size=style_dict.get("font_size"),
|
||||||
|
font_color=style_dict.get("font_color"),
|
||||||
|
bold=style_dict.get("bold", False),
|
||||||
|
italic=style_dict.get("italic", False),
|
||||||
|
underline=style_dict.get("underline", False)
|
||||||
|
)
|
||||||
|
text_style_ranges.append(style_range)
|
||||||
|
return text_style_ranges
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ERROR] Error converting text_styles: {e}", file=sys.stderr)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def execute_tool(tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
"""执行具体的工具"""
|
||||||
|
try:
|
||||||
|
print(f"[DEBUG] Executing tool: {tool_name} with args: {arguments}", file=sys.stderr)
|
||||||
|
|
||||||
|
if not CAPCUT_AVAILABLE:
|
||||||
|
return {"success": False, "error": "CapCut modules not available"}
|
||||||
|
|
||||||
|
# 捕获标准输出,防止调试信息干扰
|
||||||
|
with capture_stdout() as captured:
|
||||||
|
if tool_name == "create_draft":
|
||||||
|
draft_id, script = get_or_create_draft(
|
||||||
|
width=arguments.get("width", 1080),
|
||||||
|
height=arguments.get("height", 1920)
|
||||||
|
)
|
||||||
|
result = {
|
||||||
|
"draft_id": str(draft_id),
|
||||||
|
"draft_url": f"https://www.install-ai-guider.top/draft/downloader?draft_id={draft_id}"
|
||||||
|
}
|
||||||
|
|
||||||
|
elif tool_name == "add_video":
|
||||||
|
result = add_video_track(**arguments)
|
||||||
|
|
||||||
|
elif tool_name == "add_audio":
|
||||||
|
result = add_audio_track(**arguments)
|
||||||
|
|
||||||
|
elif tool_name == "add_image":
|
||||||
|
result = add_image_impl(**arguments)
|
||||||
|
|
||||||
|
elif tool_name == "add_text":
|
||||||
|
# 处理text_styles参数
|
||||||
|
text_styles_converted = None
|
||||||
|
if "text_styles" in arguments and arguments["text_styles"]:
|
||||||
|
text_styles_converted = convert_text_styles(arguments["text_styles"])
|
||||||
|
arguments["text_styles"] = text_styles_converted
|
||||||
|
|
||||||
|
result = add_text_impl(**arguments)
|
||||||
|
|
||||||
|
elif tool_name == "add_subtitle":
|
||||||
|
result = add_subtitle_impl(**arguments)
|
||||||
|
|
||||||
|
elif tool_name == "add_effect":
|
||||||
|
result = add_effect_impl(**arguments)
|
||||||
|
|
||||||
|
elif tool_name == "add_sticker":
|
||||||
|
result = add_sticker_impl(**arguments)
|
||||||
|
|
||||||
|
elif tool_name == "add_video_keyframe":
|
||||||
|
result = add_video_keyframe_impl(**arguments)
|
||||||
|
|
||||||
|
elif tool_name == "get_video_duration":
|
||||||
|
duration = get_video_duration(arguments["video_url"])
|
||||||
|
result = {"duration": duration}
|
||||||
|
|
||||||
|
elif tool_name == "save_draft":
|
||||||
|
save_result = save_draft_impl(**arguments)
|
||||||
|
if isinstance(save_result, dict) and "draft_url" in save_result:
|
||||||
|
result = {"draft_url": save_result["draft_url"]}
|
||||||
|
else:
|
||||||
|
result = {"draft_url": f"https://www.install-ai-guider.top/draft/downloader?draft_id=unknown"}
|
||||||
|
|
||||||
|
else:
|
||||||
|
return {"success": False, "error": f"Unknown tool: {tool_name}"}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"result": result,
|
||||||
|
"features_used": {
|
||||||
|
"shadow": arguments.get("shadow_enabled", False) if tool_name == "add_text" else False,
|
||||||
|
"background": bool(arguments.get("background_color")) if tool_name == "add_text" else False,
|
||||||
|
"multi_style": bool(arguments.get("text_styles")) if tool_name == "add_text" else False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ERROR] Tool execution error: {e}", file=sys.stderr)
|
||||||
|
print(f"[ERROR] Traceback: {traceback.format_exc()}", file=sys.stderr)
|
||||||
|
return {"success": False, "error": str(e)}
|
||||||
|
|
||||||
|
def handle_request(request_data: str) -> Optional[str]:
|
||||||
|
"""处理JSON-RPC请求"""
|
||||||
|
try:
|
||||||
|
request = json.loads(request_data.strip())
|
||||||
|
print(f"[DEBUG] Received request: {request.get('method', 'unknown')}", file=sys.stderr)
|
||||||
|
|
||||||
|
if request.get("method") == "initialize":
|
||||||
|
response = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": request.get("id"),
|
||||||
|
"result": {
|
||||||
|
"protocolVersion": "2024-11-05",
|
||||||
|
"capabilities": {
|
||||||
|
"experimental": {},
|
||||||
|
"tools": {"listChanged": False}
|
||||||
|
},
|
||||||
|
"serverInfo": {
|
||||||
|
"name": "capcut-api",
|
||||||
|
"version": "1.12.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return json.dumps(response)
|
||||||
|
|
||||||
|
elif request.get("method") == "notifications/initialized":
|
||||||
|
return None
|
||||||
|
|
||||||
|
elif request.get("method") == "tools/list":
|
||||||
|
response = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": request.get("id"),
|
||||||
|
"result": {"tools": TOOLS}
|
||||||
|
}
|
||||||
|
return json.dumps(response)
|
||||||
|
|
||||||
|
elif request.get("method") == "tools/call":
|
||||||
|
tool_name = request["params"]["name"]
|
||||||
|
arguments = request["params"].get("arguments", {})
|
||||||
|
|
||||||
|
result = execute_tool(tool_name, arguments)
|
||||||
|
|
||||||
|
response = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": request.get("id"),
|
||||||
|
"result": {
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": json.dumps(result, ensure_ascii=False, indent=2)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return json.dumps(response)
|
||||||
|
|
||||||
|
else:
|
||||||
|
error_response = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": request.get("id"),
|
||||||
|
"error": {"code": -32601, "message": "Method not found"}
|
||||||
|
}
|
||||||
|
return json.dumps(error_response)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ERROR] Request handling error: {e}", file=sys.stderr)
|
||||||
|
print(f"[ERROR] Traceback: {traceback.format_exc()}", file=sys.stderr)
|
||||||
|
error_response = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": None,
|
||||||
|
"error": {"code": 0, "message": str(e)}
|
||||||
|
}
|
||||||
|
return json.dumps(error_response)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""主函数"""
|
||||||
|
print("🚀 Starting CapCut API MCP Server (Complete Version)...", file=sys.stderr)
|
||||||
|
print(f"📋 Available tools: {len(TOOLS)} tools loaded", file=sys.stderr)
|
||||||
|
print("✨ Features: 视频、音频、图片、文本、字幕、特效、贴纸、关键帧", file=sys.stderr)
|
||||||
|
print("🔌 Waiting for client connections...", file=sys.stderr)
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
line = sys.stdin.readline()
|
||||||
|
if not line:
|
||||||
|
print("[DEBUG] EOF received, shutting down", file=sys.stderr)
|
||||||
|
break
|
||||||
|
|
||||||
|
response = handle_request(line)
|
||||||
|
if response:
|
||||||
|
print(response)
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
except EOFError:
|
||||||
|
print("[DEBUG] EOF exception, shutting down", file=sys.stderr)
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ERROR] Server error: {e}", file=sys.stderr)
|
||||||
|
print(f"[ERROR] Traceback: {traceback.format_exc()}", file=sys.stderr)
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("[INFO] Server stopped by user", file=sys.stderr)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ERROR] Fatal server error: {e}", file=sys.stderr)
|
||||||
|
print(f"[ERROR] Traceback: {traceback.format_exc()}", file=sys.stderr)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
45
pyproject.toml
Normal file
45
pyproject.toml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=61.0", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "capcut-api"
|
||||||
|
version = "1.0.0"
|
||||||
|
description = "Open source CapCut API tool with MCP support"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.10"
|
||||||
|
classifiers = [
|
||||||
|
"Development Status :: 4 - Beta",
|
||||||
|
"Intended Audience :: Developers",
|
||||||
|
"License :: OSI Approved :: MIT License",
|
||||||
|
"Operating System :: OS Independent",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3.10",
|
||||||
|
"Programming Language :: Python :: 3.11",
|
||||||
|
"Programming Language :: Python :: 3.12",
|
||||||
|
]
|
||||||
|
dependencies = [
|
||||||
|
"requests>=2.28.0",
|
||||||
|
"Pillow>=9.0.0",
|
||||||
|
"numpy>=1.21.0",
|
||||||
|
"opencv-python>=4.6.0",
|
||||||
|
"ffmpeg-python>=0.2.0",
|
||||||
|
"pydantic>=2.0.0",
|
||||||
|
"fastapi>=0.100.0",
|
||||||
|
"uvicorn[standard]>=0.23.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
mcp = [
|
||||||
|
"mcp>=1.0.0",
|
||||||
|
"aiohttp>=3.8.0",
|
||||||
|
"websockets>=11.0",
|
||||||
|
"jsonrpc-base>=2.2.0",
|
||||||
|
"jsonrpc-websocket>=3.1.0",
|
||||||
|
"jsonrpc-async>=2.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
Homepage = "https://github.com/ashreo/CapCutAPI"
|
||||||
|
Repository = "https://github.com/ashreo/CapCutAPI.git"
|
||||||
|
Issues = "https://github.com/ashreo/CapCutAPI/issues"
|
||||||
4
requirements-mcp.txt
Normal file
4
requirements-mcp.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# MCP相关依赖
|
||||||
|
mcp>=1.0.0
|
||||||
|
aiohttp>=3.8.0
|
||||||
|
pydantic>=2.0.0
|
||||||
339
test_mcp_client.py
Normal file
339
test_mcp_client.py
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
CapCut API MCP 测试客户端 (Complete Version)
|
||||||
|
|
||||||
|
测试完整版本的MCP服务器,包含所有CapCut API接口
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def send_request(process, request_data):
|
||||||
|
"""发送请求并接收响应"""
|
||||||
|
try:
|
||||||
|
request_json = json.dumps(request_data, ensure_ascii=False)
|
||||||
|
print(f"发送请求: {request_json}")
|
||||||
|
|
||||||
|
# 发送请求
|
||||||
|
process.stdin.write(request_json + "\n")
|
||||||
|
process.stdin.flush()
|
||||||
|
|
||||||
|
# 等待响应
|
||||||
|
response_line = process.stdout.readline()
|
||||||
|
if not response_line.strip():
|
||||||
|
print("❌ 收到空响应")
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = json.loads(response_line.strip())
|
||||||
|
print(f"收到响应: {json.dumps(response, ensure_ascii=False, indent=2)}")
|
||||||
|
return response
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
print(f"❌ JSON解析错误: {e}")
|
||||||
|
print(f"原始响应: {response_line}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 发送请求时出错: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def send_notification(process, notification_data):
|
||||||
|
"""发送通知(不需要响应)"""
|
||||||
|
try:
|
||||||
|
notification_json = json.dumps(notification_data, ensure_ascii=False)
|
||||||
|
print(f"发送通知: {notification_json}")
|
||||||
|
|
||||||
|
process.stdin.write(notification_json + "\n")
|
||||||
|
process.stdin.flush()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 发送通知时出错: {e}")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("🚀 CapCut API MCP 测试客户端 (Complete Version)")
|
||||||
|
print("🎯 测试所有CapCut API接口功能")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
# 启动MCP服务器
|
||||||
|
try:
|
||||||
|
process = subprocess.Popen(
|
||||||
|
[sys.executable, "mcp_server.py"], # 修改为正确的文件名
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
text=True,
|
||||||
|
bufsize=0 # 无缓冲
|
||||||
|
)
|
||||||
|
|
||||||
|
print("✅ MCP服务器已启动 (mcp_server.py)")
|
||||||
|
time.sleep(1) # 等待服务器启动
|
||||||
|
|
||||||
|
# 1. 初始化
|
||||||
|
init_request = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "initialize",
|
||||||
|
"params": {
|
||||||
|
"protocolVersion": "2024-11-05",
|
||||||
|
"capabilities": {
|
||||||
|
"tools": {},
|
||||||
|
"resources": {}
|
||||||
|
},
|
||||||
|
"clientInfo": {
|
||||||
|
"name": "CapCut-Test-Client-Complete",
|
||||||
|
"version": "1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response = send_request(process, init_request)
|
||||||
|
if response and "result" in response:
|
||||||
|
print("✅ 初始化成功")
|
||||||
|
else:
|
||||||
|
print("❌ 初始化失败")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 发送初始化完成通知
|
||||||
|
init_notification = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "notifications/initialized",
|
||||||
|
"params": {}
|
||||||
|
}
|
||||||
|
send_notification(process, init_notification)
|
||||||
|
|
||||||
|
print("\n=== 📋 获取工具列表 ===")
|
||||||
|
# 2. 获取工具列表
|
||||||
|
tools_request = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 2,
|
||||||
|
"method": "tools/list",
|
||||||
|
"params": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
response = send_request(process, tools_request)
|
||||||
|
if response and "result" in response:
|
||||||
|
tools = response["result"]["tools"]
|
||||||
|
print(f"✅ 成功获取 {len(tools)} 个工具:")
|
||||||
|
for tool in tools:
|
||||||
|
print(f" • {tool['name']}: {tool['description']}")
|
||||||
|
else:
|
||||||
|
print("❌ 获取工具列表失败")
|
||||||
|
return
|
||||||
|
|
||||||
|
print("\n=== 🎬 测试核心功能 ===\n")
|
||||||
|
|
||||||
|
# 3. 测试创建草稿
|
||||||
|
print("📝 测试创建草稿")
|
||||||
|
create_draft_request = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 3,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "create_draft",
|
||||||
|
"arguments": {
|
||||||
|
"width": 1080,
|
||||||
|
"height": 1920
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response = send_request(process, create_draft_request)
|
||||||
|
if response and "result" in response:
|
||||||
|
print("✅ 创建草稿成功")
|
||||||
|
# 提取draft_id用于后续测试
|
||||||
|
draft_data = json.loads(response["result"]["content"][0]["text"])
|
||||||
|
draft_id = draft_data["result"]["draft_id"]
|
||||||
|
print(f"📋 草稿ID: {draft_id}")
|
||||||
|
else:
|
||||||
|
print("❌ 创建草稿失败")
|
||||||
|
draft_id = None
|
||||||
|
|
||||||
|
# 4. 测试添加文本(带多样式)
|
||||||
|
print("\n📝 测试添加文本(多样式)")
|
||||||
|
add_text_request = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 4,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "add_text",
|
||||||
|
"arguments": {
|
||||||
|
"text": "Hello CapCut API!",
|
||||||
|
"start": 0,
|
||||||
|
"end": 5,
|
||||||
|
"draft_id": draft_id,
|
||||||
|
"font_color": "#ff0000",
|
||||||
|
"font_size": 32,
|
||||||
|
"shadow_enabled": True,
|
||||||
|
"shadow_color": "#000000",
|
||||||
|
"shadow_alpha": 0.8,
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"background_alpha": 0.5,
|
||||||
|
"text_styles": [
|
||||||
|
{
|
||||||
|
"start": 0,
|
||||||
|
"end": 5,
|
||||||
|
"font_size": 36,
|
||||||
|
"font_color": "#00ff00",
|
||||||
|
"bold": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": 6,
|
||||||
|
"end": 12,
|
||||||
|
"font_size": 28,
|
||||||
|
"font_color": "#0000ff",
|
||||||
|
"italic": True
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response = send_request(process, add_text_request)
|
||||||
|
if response and "result" in response:
|
||||||
|
print("✅ 添加文本成功")
|
||||||
|
else:
|
||||||
|
print("❌ 添加文本失败")
|
||||||
|
|
||||||
|
# 5. 测试添加视频
|
||||||
|
print("\n🎬 测试添加视频")
|
||||||
|
add_video_request = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 5,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "add_video",
|
||||||
|
"arguments": {
|
||||||
|
"video_url": "https://example.com/video.mp4",
|
||||||
|
"draft_id": draft_id,
|
||||||
|
"start": 0,
|
||||||
|
"end": 10,
|
||||||
|
"target_start": 5,
|
||||||
|
"transition": "fade",
|
||||||
|
"volume": 0.8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response = send_request(process, add_video_request)
|
||||||
|
if response and "result" in response:
|
||||||
|
print("✅ 添加视频成功")
|
||||||
|
else:
|
||||||
|
print("❌ 添加视频失败")
|
||||||
|
|
||||||
|
# 6. 测试添加音频
|
||||||
|
print("\n🎵 测试添加音频")
|
||||||
|
add_audio_request = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 6,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "add_audio",
|
||||||
|
"arguments": {
|
||||||
|
"audio_url": "https://example.com/audio.mp3",
|
||||||
|
"draft_id": draft_id,
|
||||||
|
"start": 0,
|
||||||
|
"end": 15,
|
||||||
|
"volume": 0.6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response = send_request(process, add_audio_request)
|
||||||
|
if response and "result" in response:
|
||||||
|
print("✅ 添加音频成功")
|
||||||
|
else:
|
||||||
|
print("❌ 添加音频失败")
|
||||||
|
|
||||||
|
# 7. 测试添加图片
|
||||||
|
print("\n🖼️ 测试添加图片")
|
||||||
|
add_image_request = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 7,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "add_image",
|
||||||
|
"arguments": {
|
||||||
|
"image_url": "https://example.com/image.jpg",
|
||||||
|
"draft_id": draft_id,
|
||||||
|
"start": 10,
|
||||||
|
"end": 15,
|
||||||
|
"intro_animation": "fade_in",
|
||||||
|
"outro_animation": "fade_out"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response = send_request(process, add_image_request)
|
||||||
|
if response and "result" in response:
|
||||||
|
print("✅ 添加图片成功")
|
||||||
|
else:
|
||||||
|
print("❌ 添加图片失败")
|
||||||
|
|
||||||
|
# 8. 测试获取视频时长
|
||||||
|
print("\n⏱️ 测试获取视频时长")
|
||||||
|
get_duration_request = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 8,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "get_video_duration",
|
||||||
|
"arguments": {
|
||||||
|
"video_url": "https://example.com/video.mp4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response = send_request(process, get_duration_request)
|
||||||
|
if response and "result" in response:
|
||||||
|
print("✅ 获取视频时长成功")
|
||||||
|
else:
|
||||||
|
print("❌ 获取视频时长失败")
|
||||||
|
|
||||||
|
# 9. 测试保存草稿
|
||||||
|
print("\n💾 测试保存草稿")
|
||||||
|
save_draft_request = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 9,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "save_draft",
|
||||||
|
"arguments": {
|
||||||
|
"draft_id": draft_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response = send_request(process, save_draft_request)
|
||||||
|
if response and "result" in response:
|
||||||
|
print("✅ 保存草稿成功")
|
||||||
|
else:
|
||||||
|
print("❌ 保存草稿失败")
|
||||||
|
|
||||||
|
print("\n🎉 所有测试完成!CapCut API MCP服务器功能验证成功!")
|
||||||
|
|
||||||
|
print("\n✅ 已验证的功能:")
|
||||||
|
print(" • 草稿管理 (创建、保存)")
|
||||||
|
print(" • 文本处理 (多样式、阴影、背景)")
|
||||||
|
print(" • 视频处理 (添加、转场、音量控制)")
|
||||||
|
print(" • 音频处理 (添加、音量控制)")
|
||||||
|
print(" • 图片处理 (添加、动画效果)")
|
||||||
|
print(" • 工具信息 (时长获取)")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ 测试过程中出错: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# 关闭服务器
|
||||||
|
try:
|
||||||
|
process.terminate()
|
||||||
|
process.wait(timeout=5)
|
||||||
|
except:
|
||||||
|
process.kill()
|
||||||
|
print("🔴 MCP服务器已关闭")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user