Skip to main content
Glama

export_draft

Export video drafts from JianYing MCP server to local CapCut project files for further editing and completion.

Instructions

导出草稿为剪映项目,导出到本地剪映的草稿路径下

Args: draft_id: 草稿ID,必须是已存在的草稿 jianying_draft_path: 导出路径

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
draft_idYes
jianying_draft_pathNo/app/output

Implementation Reference

  • MCP tool handler for 'export_draft'. Validates draft existence, instantiates ExportDraft, calls its export method, processes result into ToolResponse.
    @mcp.tool() def export_draft(draft_id: str, jianying_draft_path: str = OUTPUT_PATH) -> ToolResponse: """ 导出草稿为剪映项目,导出到本地剪映的草稿路径下 Args: draft_id: 草稿ID,必须是已存在的草稿 jianying_draft_path: 导出路径 """ try: # 验证草稿是否存在 draft_data_path = os.path.join(SAVE_PATH, draft_id) if not os.path.exists(draft_data_path): return ToolResponse( success=False, message=f"草稿不存在: {draft_id}" ) # 验证草稿数据文件是否存在 draft_json_path = os.path.join(draft_data_path, "draft.json") if not os.path.exists(draft_json_path): return ToolResponse( success=False, message=f"草稿数据文件不存在: {draft_id}/draft.json" ) # 创建导出器 exporter = ExportDraft(jianying_draft_path) # 执行导出 export_result = exporter.export(draft_id) if export_result and isinstance(export_result, dict): return ToolResponse( success=True, message="草稿导出成功", data={ "draft_id": draft_id, "output_path": export_result.get("output") + f"/{export_result.get("draft_name")}", "draft_name": export_result.get("draft_name"), "export_logs": export_result.get("export_logs", []), "summary": export_result.get("summary", {}), "processing_details": { "total_operations": len(export_result.get("export_logs", [])), "successful_operations": len( [log for log in export_result.get("export_logs", []) if log.get("level") == "info"]), "warnings": len( [log for log in export_result.get("export_logs", []) if log.get("level") == "warning"]), "errors": len( [log for log in export_result.get("export_logs", []) if log.get("level") == "error"]) } } ) else: return ToolResponse( success=False, message="草稿导出失败,请检查草稿数据完整性" ) except FileNotFoundError as e: return ToolResponse( success=False, message=f"文件不存在: {str(e)}" ) except Exception as e: return ToolResponse( success=False, message=f"导出失败: {str(e)}" )
  • Core implementation of draft export in ExportDraft.export(). Loads draft data (tracks, segments), creates pyJianYingDraft script, adds tracks and segments (video, text, audio), copies materials, saves the draft folder.
    def export(self, draft_id: str) -> dict: """ 导出草稿 Args: draft_id: 草稿ID Returns: bool: 导出是否成功 """ try: self._log(f"开始导出草稿: {draft_id}") # 验证草稿数据是否存在 draft_data_path = f"{SAVE_PATH}/{draft_id}" if not os.path.exists(draft_data_path): raise FileNotFoundError(f"草稿数据不存在: {draft_data_path}") # 验证导出路径是否存在 if not os.path.exists(self.output_path): raise FileNotFoundError(f"导出路径不存在: {self.output_path}") # 1. 读取所有数据 draft_info = self._load_draft_data(draft_id) track_data = self._load_track_data(draft_id) video_data = self._load_video_data(draft_id) text_data = self._load_text_data(draft_id) audio_data = self._load_audio_data(draft_id) if not draft_info: raise FileNotFoundError(f"未找到草稿信息文件: {draft_id}/draft.json") # 2. 验证目标草稿是否已存在 draft_name = draft_info.get("draft_name", f"Draft_{draft_id}") # 3. 创建草稿 width = draft_info.get("width", 1920) height = draft_info.get("height", 1080) if os.path.exists(os.path.join(self.output_path, draft_name)): # 删除文件夹 shutil.rmtree(os.path.join(self.output_path, draft_name)) script = self.draft_folder.create_draft(draft_name, width, height) # 3. 复制素材文件 self._copy_material_files(draft_id, draft_name) # 4. 添加轨道 self._create_tracks(script, track_data) # 5. 处理视频片段 video_segments = self._process_video_segments(video_data, draft_name) # 6. 处理文本片段 text_segments = self._process_text_segments(text_data) # 7. 处理音频片段 audio_segments = self._process_audio_segments(audio_data, draft_name) # 8. 添加视频片段到轨道 self._add_video_segments_to_tracks(script, video_segments) # 为文本片段分配轨道 self._add_text_segments_to_tracks(script, text_segments) # 为音频片段分配轨道 self._add_audio_segments_to_tracks(script, audio_segments) # 9. 保存草稿 script.save() data = { "output": self.output_path, "draft_name": draft_name, "export_logs": self.export_logs, "summary": { "total_logs": len(self.export_logs), "info_count": len([log for log in self.export_logs if log["level"] == "info"]), "warning_count": len([log for log in self.export_logs if log["level"] == "warning"]), "error_count": len([log for log in self.export_logs if log["level"] == "error"]) } } return data except Exception as e: self._log(f"导出草稿失败: {e}", "error") import traceback traceback.print_exc() return { "output": self.output_path, "draft_name": draft_name, "export_logs": self.export_logs, "summary": { "total_logs": len(self.export_logs), "info_count": len([log for log in self.export_logs if log["level"] == "info"]), "warning_count": len([log for log in self.export_logs if log["level"] == "warning"]), "error_count": len([]) } }
  • The draft_tools function registers all draft-related MCP tools, including export_draft via @mcp.tool() decorator.
    def draft_tools(mcp: FastMCP): @mcp.tool() def rules(): """制作视频的规范,这一步必须执行,方便了解如何规范的使用工具制作视频""" prompt = """ 核心工作原则 1.询问用户应当怎么制作视频,有什么建议,你可以使用parse_media_info(了解素材信息),然后不断地向用户询问制作视频的细节,在制作前,你应该向用户说明你准备怎么制作视频,用户没有意见后才开始制作视频 2. 严格遵循操作流程 必须按照以下顺序执行,不可跳步骤: 创建草稿 → create_draft 创建轨道 → create_track(根据需要创建video、audio、text轨道) 添加素材 → add_*_segment(添加视频、音频、文本片段) 查询特效 → find_effects_by_type(查找可用特效) 应用特效 → add_*_effect/animation(添加各种特效和动画) 导出草稿 → export_draft 3. ID管理规则 draft_id:创建草稿后获得,用于所有后续操作 track_id:创建轨道后获得,用于添加对应类型的素材 segment_id:添加素材后获得,用于添加特效和动画 严格保存和传递这些ID,它们是工具链的关键纽带 4.轨道规则 一般情况下同类型的轨道只需要一个就可以,除非需要画中画等复杂情况才会创建多个同类型的轨道 5.时长规则 在规划视频、音频时长时,必须从素材本身时长出发,使用本身的时长,切记不能超出素材本身时长 注意素材的总时长,在传入target_timerange参数时,所占的轨道时长不能超过素材总时长,不能因为其他原因使得轨道时长超过素材时长,例如当视频总时长5s,音频时长为4.2s,不能因为视频比音频时间长,就改变音频轨道时长,即音频可传入的最大时长为4.2s 添加素材的add_audio_segment和add_video_segment工具中,target_timerange参数描述的是轨道上的时间范围,同一轨道中不可有重复时间段,即0s-4.2s和4s-5s,第一段素材最后0.2s与第二段素材重叠了,只能是0s-4.2s和4.ss-5s 添加素材的add_audio_segment和add_video_segment工具中,source_timerange参数描述的是素材本身取的时长,默认取全部时长,一般情况下不设置,除非用户说明,若素材时长为5s,用户需要取其中1s-5s的内容,才配置 6.其他 add_text_segment工具其中的参数clip_settings的transform_y,强烈建议修改为-0.7(这样字幕是在正下方,不影响视频观感) 特效不存在:查看建议列表,选择相似特效 时间冲突:调整时间范围,查看素材时间以及工具参数 添加转场:若三个视频间需要添加转场,那转场应该添加在第一个和第二个视频后添加转场,而非第二个和第三个视频里 """ return ToolResponse( success=True, message="获取成功", data={"rules": prompt} ) @mcp.tool() def create_draft(draft_name: str, width: int = 1920, height: int = 1080, fps: int = 30): """ 创建草稿 Args: draft_name: str 草稿名称 width: int,视频宽度,默认1920 height: int,视频高度,默认1080 fps: int,帧率,默认30 """ # 验证SAVE_PATH是否存在 if not os.path.exists(SAVE_PATH): raise FileNotFoundError(f"草稿存储路径不存在: {SAVE_PATH}") # 生成草稿ID draft_id = str(uuid.uuid4()) # 构建完整的草稿路径 draft_path = os.path.join(SAVE_PATH, draft_id) # 创建草稿数据 draft_data = { "draft_id": draft_id, "draft_name": draft_name, "width": width, "height": height, "fps": fps } # 在SAVE_PATH下创建以草稿ID命名的文件夹 os.makedirs(draft_path, exist_ok=True) # 保存draft.json文件 draft_json_path = os.path.join(draft_path, "draft.json") with open(draft_json_path, "w", encoding="utf-8") as f: json.dump(draft_data, f, ensure_ascii=False, indent=4) # 添加草稿索引记录 draft_info = { "draft_name": draft_name, "created_time": datetime.datetime.now().isoformat(), "width": width, "height": height, "fps": fps } index_manager.add_draft_mapping(draft_id, draft_info) return draft_data @mcp.tool()
  • Input schema defined by function parameters and docstring: draft_id (str, required), jianying_draft_path (str, optional default OUTPUT_PATH). Returns ToolResponse.
    @mcp.tool() def export_draft(draft_id: str, jianying_draft_path: str = OUTPUT_PATH) -> ToolResponse: """ 导出草稿为剪映项目,导出到本地剪映的草稿路径下 Args: draft_id: 草稿ID,必须是已存在的草稿 jianying_draft_path: 导出路径 """

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hey-jian-wei/jianying-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server