UNPKG

coze-video-concatenator-mcp

Version:
196 lines (172 loc) 6.13 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import { spawn } from 'child_process'; // 创建MCP服务器 const server = new Server({ name: 'coze-video-concatenator', version: '1.0.0', }); // 列出可用工具 server.setRequestHandler(ListToolsRequestSchema, async () => { console.error('[DEBUG] ListToolsRequestSchema called'); return { tools: [ { name: 'run_video_concatenation_workflow', description: '使用Coze工作流进行视频拼接,支持多个视频URL输入进行拼接', inputSchema: { type: 'object', properties: { input: { type: 'array', items: { type: 'string' }, description: '输入视频的URL数组,多个视频将按顺序拼接' }, workflow_id: { type: 'string', description: 'Coze视频拼接工作流ID', default: '7543475034791936027' } }, required: ['input'] } } ] }; }); // 处理工具调用 server.setRequestHandler(CallToolRequestSchema, async (request) => { console.error('[DEBUG] CallToolRequestSchema called:', JSON.stringify(request.params, null, 2)); const { name, arguments: args } = request.params; try { let result; switch (name) { case 'run_video_concatenation_workflow': console.error('[DEBUG] Running video concatenation workflow'); result = await runVideoConcatenationWorkflow(args); console.error('[DEBUG] Workflow completed successfully'); // 格式化输出结果,提取关键信息 if (result && result.data) { try { const data = typeof result.data === 'string' ? JSON.parse(result.data) : result.data; if (data.output) { result.formatted_output = { success: true, output_video_url: data.output, debug_url: result.debug_url, usage: result.usage, message: '视频拼接完成' }; } } catch (e) { console.error('[DEBUG] Failed to parse data field:', e.message); } } break; default: result = `未知工具: ${name}`; } return { content: [{ type: 'text', text: typeof result === 'string' ? result : JSON.stringify(result) }] }; } catch (error) { console.error('[ERROR] Tool execution failed:', error.message); return { content: [ { type: 'text', text: `执行错误: ${error.message}` } ] }; } }); // Coze视频拼接工作流工具:根据多个视频URL进行视频拼接 async function runVideoConcatenationWorkflow({ input, workflow_id = '7543475034791936027' }) { console.error('[DEBUG] runVideoConcatenationWorkflow called with:', { input, workflow_id }); const apiKey = process.env.COZE_API_KEY; if (!apiKey) { throw new Error('请设置 COZE_API_KEY 环境变量'); } // 验证 input 为字符串数组 if (!Array.isArray(input)) { throw new Error('input 必须为字符串数组'); } const urlList = input .map((s) => String(s).trim()) .filter((s) => s.length > 0); if (urlList.length === 0) { throw new Error('input 不能为空'); } // 基础URL格式校验(简单判断) const invalid = urlList.find((u) => !/^https?:\/\//i.test(u)); if (invalid) { throw new Error(`检测到无效URL: ${invalid}`); } // 构建输入参数 - 多个视频URL保持为数组格式 console.error('[DEBUG] Final input array:', urlList); const payload = { parameters: { input: urlList }, workflow_id: workflow_id }; console.error('[DEBUG] Sending payload to Coze API:', JSON.stringify(payload, null, 2)); return new Promise((resolve, reject) => { const args = [ '-sS', '-X', 'POST', 'https://api.coze.cn/v1/workflow/run', '-H', 'Content-Type: application/json', '-H', `Authorization: Bearer ${apiKey}`, '-d', JSON.stringify(payload) ]; console.error('[DEBUG] Executing curl with args:', args); const proc = spawn('curl', args, { stdio: ['ignore', 'pipe', 'pipe'] }); let stdout = ''; let stderr = ''; proc.stdout.on('data', (d) => { stdout += d.toString(); }); proc.stderr.on('data', (d) => { stderr += d.toString(); }); proc.on('close', (code) => { console.error('[DEBUG] curl process closed with code:', code); console.error('[DEBUG] stdout:', stdout); console.error('[DEBUG] stderr:', stderr); if (code !== 0) { return reject(new Error(`curl 执行失败,退出码 ${code}, 错误: ${stderr || '无'}`)); } try { const json = JSON.parse(stdout); console.error('[DEBUG] Parsed response:', JSON.stringify(json, null, 2)); // 检查API响应状态 if (json.code !== 0) { return reject(new Error(`Coze API 返回错误: ${json.msg || '未知错误'}`)); } resolve(json); } catch (e) { reject(new Error(`解析响应失败: ${e.message}; 原始输出: ${stdout}`)); } }); proc.on('error', (err) => { console.error('[ERROR] curl process error:', err.message); reject(new Error(`启动curl失败: ${err.message}`)); }); }); } // 启动服务器 async function main() { try { console.error('[DEBUG] Starting MCP server...'); const transport = new StdioServerTransport(); await server.connect(transport); console.error('Coze Video Concatenator MCP Server started'); } catch (error) { console.error('[ERROR] Failed to start server:', error.message); process.exit(1); } } main().catch((error) => { console.error('[ERROR] Main function failed:', error.message); process.exit(1); });