UNPKG

midjourney-mcp

Version:

A Model Context Protocol server for Midjourney integration via MJ API

244 lines • 11 kB
/** * Additional Midjourney tool handlers */ import { createTextContent, createErrorResult, createSuccessResult, isTaskCompleted, isTaskSuccessful, } from "../types/index.js"; /** * Handle blend task */ export async function handleBlendTask(args, apiClient, _taskPoller) { try { const response = await apiClient.submitBlend(args.images); if (response.code !== 1 || !response.result) { return createErrorResult(`Failed to submit blend task: ${response.description}`); } const taskId = response.result; return createSuccessResult(`šŸŽØ **Image Blending Started!**\n\n` + `**Task ID:** ${taskId}\n` + `**Images:** ${args.images.length} images to blend\n` + `**Status:** Task submitted successfully\n\n` + `šŸ’” **Next Steps:**\n` + `• Use \`midjourney_get_task\` with task ID "${taskId}" to check progress\n` + `• Blending typically takes 1-2 minutes\n` + `• The result will combine elements from all input images\n\n` + `ā±ļø **Estimated Time:** 60-120 seconds`); } catch (error) { return createErrorResult(`Failed to submit blend task: ${error instanceof Error ? error.message : String(error)}`); } } /** * Handle describe task */ export async function handleDescribeTask(args, apiClient, _taskPoller) { try { const response = await apiClient.submitDescribe(args.image); if (response.code !== 1 || !response.result) { return createErrorResult(`Failed to submit describe task: ${response.description}`); } const taskId = response.result; return createSuccessResult(`šŸ“ **Image Description Started!**\n\n` + `**Task ID:** ${taskId}\n` + `**Status:** Task submitted successfully\n\n` + `šŸ’” **Next Steps:**\n` + `• Use \`midjourney_get_task\` with task ID "${taskId}" to check progress\n` + `• Description typically takes 30-60 seconds\n` + `• You'll get detailed text descriptions that can be used as prompts\n\n` + `ā±ļø **Estimated Time:** 30-60 seconds`); } catch (error) { return createErrorResult(`Failed to submit describe task: ${error instanceof Error ? error.message : String(error)}`); } } /** * Handle get task status */ export async function handleGetTask(args, _apiClient, taskPoller) { try { const task = await taskPoller.getTaskStatus(args.task_id); if (!task) { return createErrorResult(`Task not found: ${args.task_id}`); } const progress = taskPoller.getTaskProgress(task); const statusText = taskPoller.formatTaskStatus(task); const isCompleted = isTaskCompleted(task.status || 'NOT_START'); const isSuccessful = isTaskSuccessful(task.status || 'NOT_START'); // Calculate task duration let durationInfo = ''; if (task.submitTime) { const submitTime = new Date(task.submitTime); const now = new Date(); const durationMs = now.getTime() - submitTime.getTime(); const durationMinutes = Math.floor(durationMs / 60000); const durationSeconds = Math.floor((durationMs % 60000) / 1000); durationInfo = `**Duration:** ${durationMinutes}m ${durationSeconds}s\n`; } let content = [ createTextContent(`šŸ“‹ **Task Status Report**\n\n` + `**Task ID:** ${args.task_id}\n` + `**Action:** ${task.action || 'Unknown'}\n` + `**Status:** ${statusText}\n` + `**Progress:** ${progress}%\n` + durationInfo) ]; if (task.prompt) { content.push(createTextContent(`**Prompt:** ${task.prompt}`)); } if (task.promptEn && task.promptEn !== task.prompt) { content.push(createTextContent(`**English Prompt:** ${task.promptEn}`)); } if (isCompleted) { if (isSuccessful) { content.push(createTextContent(`\nāœ… **Task Completed Successfully!**`)); if (task.imageUrl) { // Display image using markdown format for direct rendering content.push(createTextContent(`\nšŸ–¼ļø **Generated Image:**\n\n` + `![Generated Midjourney Image](${task.imageUrl})\n\n` + `šŸ“ø **Direct Link:** ${task.imageUrl}`)); } if (task.buttons && task.buttons.length > 0) { let actionsText = '\nšŸŽ® **Available Actions:**\n'; const upscaleButtons = task.buttons.filter(b => b.label?.startsWith('U')); const variationButtons = task.buttons.filter(b => b.label?.startsWith('V')); const rerollButtons = task.buttons.filter(b => b.emoji === 'šŸ”„'); if (upscaleButtons.length > 0) { actionsText += '\n**šŸ” Upscale (Higher Resolution):**\n'; upscaleButtons.forEach(button => { actionsText += `• **${button.label}**: Upscale image ${button.label.slice(1)}\n`; }); } if (variationButtons.length > 0) { actionsText += '\n**šŸŽ­ Variations (New Versions):**\n'; variationButtons.forEach(button => { actionsText += `• **${button.label}**: Create variation of image ${button.label.slice(1)}\n`; }); } if (rerollButtons.length > 0) { actionsText += '\n**šŸ”„ Reroll (Completely New):**\n'; actionsText += `• **Reroll**: Generate 4 new images with the same prompt\n`; } actionsText += '\nšŸ’” **How to use:** `midjourney_action` with task_id `' + args.task_id + '` and the action name (e.g., "U1", "V2", etc.)'; content.push(createTextContent(actionsText)); } } else { content.push(createTextContent(`\nāŒ **Task failed**`)); if (task.failReason) { content.push(createTextContent(`**Failure Reason:** ${task.failReason}`)); } } } else { // Check if task appears stuck const isStuck = taskPoller.isTaskStuck(task); if (isStuck) { content.push(createTextContent(`\nāš ļø **Task appears to be stuck!**\n\n` + `This task has been running for a long time. This could indicate:\n` + `• The API service is experiencing delays\n` + `• The task queue is busy\n` + `• There may be an issue with the specific request\n\n` + `**Suggestions:**\n` + `• Wait a bit longer and check again\n` + `• Try submitting a new task if this persists\n` + `• Check the API service status`)); } else { content.push(createTextContent(`\nā³ Task is still processing. Check again in a few moments.\n\n` + `šŸ’” **Tip:** Midjourney tasks typically take 1-3 minutes to complete.`)); } } // Add timing information if available if (task.submitTime || task.startTime || task.finishTime) { let timingInfo = '\nšŸ“… **Timing:**\n'; if (task.submitTime) { timingInfo += `• Submitted: ${new Date(task.submitTime).toLocaleString()}\n`; } if (task.startTime) { timingInfo += `• Started: ${new Date(task.startTime).toLocaleString()}\n`; } if (task.finishTime) { timingInfo += `• Finished: ${new Date(task.finishTime).toLocaleString()}\n`; } content.push(createTextContent(timingInfo)); } return { content, isError: false }; } catch (error) { return createErrorResult(`Failed to get task status: ${error instanceof Error ? error.message : String(error)}`); } } /** * Handle action task (button actions) */ export async function handleActionTask(args, _apiClient, taskPoller) { try { // First get the task to find the button const task = await taskPoller.getTaskStatus(args.task_id); if (!task || !task.buttons) { return createErrorResult(`Task not found or has no available actions: ${args.task_id}`); } // Find the button by label or customId const button = task.buttons.find(btn => btn.label === args.action || btn.customId === args.action); if (!button) { const availableActions = task.buttons.map(btn => btn.label).join(', '); return createErrorResult(`Action "${args.action}" not found. Available actions: ${availableActions}`); } // Submit the action using the button's customId // Note: This would need to be implemented in the API client // For now, return a placeholder response return createSuccessResult(`āœ… Action "${button.label}" would be executed on task ${args.task_id}\n\n` + `**Button:** ${button.label} ${button.emoji}\n` + `**Custom ID:** ${button.customId}\n\n` + `Note: Button action execution is not yet implemented in the API client.`); } catch (error) { return createErrorResult(`Failed to execute action: ${error instanceof Error ? error.message : String(error)}`); } } /** * Build prompt string with parameters */ export function buildPromptString(args) { let prompt = args.prompt; // Add aspect ratio if (args.aspect_ratio) { prompt += ` --ar ${args.aspect_ratio}`; } // Add quality if (args.quality) { const qualityMap = { low: '0.25', medium: '0.5', high: '1' }; prompt += ` --q ${qualityMap[args.quality] || '0.5'}`; } // Add style if (args.style === 'raw') { prompt += ` --style raw`; } // Add model if (args.model && args.model !== 'midjourney') { prompt += ` --${args.model}`; } // Add chaos if (args.chaos !== undefined) { prompt += ` --chaos ${args.chaos}`; } // Add stylize if (args.stylize !== undefined) { prompt += ` --stylize ${args.stylize}`; } // Add weird if (args.weird !== undefined) { prompt += ` --weird ${args.weird}`; } // Add seed if (args.seed !== undefined) { prompt += ` --seed ${args.seed}`; } // Add negative prompt if (args.no) { prompt += ` --no ${args.no}`; } return prompt; } //# sourceMappingURL=midjourney-handlers.js.map