UNPKG

midjourney-mcp

Version:

A Model Context Protocol server for Midjourney integration via MJ API

187 lines 8.63 kB
/** * Midjourney tools for MCP server */ import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from "@modelcontextprotocol/sdk/types.js"; import { MJApiClient, ApiError } from "../utils/api-client.js"; import { TaskPoller } from "../utils/task-poller.js"; import { validateToolParams } from "../utils/validators.js"; import { ALL_MIDJOURNEY_TOOLS, createErrorResult, createSuccessResult, } from "../types/index.js"; import { handleBlendTask, handleDescribeTask, handleGetTask, handleActionTask, buildPromptString, } from "./midjourney-handlers.js"; /** * Registers all Midjourney tools with the MCP server */ export function registerMidjourneyTools(server, config) { const apiClient = new MJApiClient(config); const taskPoller = new TaskPoller(apiClient); // Register tool list handler server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: ALL_MIDJOURNEY_TOOLS }; }); // Register tool call handler server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { // Validate parameters const validation = validateToolParams(name, args); if (!validation.isValid) { const errorMessages = validation.errors.map(e => `${e.field}: ${e.message}`).join(', '); const errorResult = createErrorResult(`Invalid parameters: ${errorMessages}`); return { content: errorResult.content }; } // Route to appropriate handler let result; switch (name) { case "midjourney_imagine": result = await handleImagineTask(args, apiClient, taskPoller); break; case "midjourney_upscale": result = await handleUpscaleTask(args, apiClient, taskPoller); break; case "midjourney_variation": result = await handleVariationTask(args, apiClient, taskPoller); break; case "midjourney_reroll": result = await handleRerollTask(args, apiClient, taskPoller); break; case "midjourney_blend": result = await handleBlendTask(args, apiClient, taskPoller); break; case "midjourney_describe": result = await handleDescribeTask(args, apiClient, taskPoller); break; case "midjourney_get_task": result = await handleGetTask(args, apiClient, taskPoller); break; case "midjourney_action": result = await handleActionTask(args, apiClient, taskPoller); break; default: throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`); } return { content: result.content }; } catch (error) { if (error instanceof McpError) { throw error; } if (error instanceof ApiError) { const errorResult = createErrorResult(`API Error ${error.code}: ${error.description}`); return { content: errorResult.content }; } const errorResult = createErrorResult(`Tool execution failed: ${error instanceof Error ? error.message : String(error)}`); return { content: errorResult.content }; } }); } // ============================================================================ // Tool Handler Functions // ============================================================================ /** * Handle Midjourney imagine task */ async function handleImagineTask(args, apiClient, _taskPoller) { try { // Build the prompt with parameters const prompt = buildPromptString(args); // Prepare request const request = { prompt, base64Array: args.reference_images, }; // Submit the task const response = await apiClient.submitImagine(request); if (response.code !== 1 || !response.result) { return createErrorResult(`Failed to submit imagine task: ${response.description}`); } const taskId = response.result; return createSuccessResult(`🎨 **Image Generation Started!**\n\n` + `**Task ID:** ${taskId}\n` + `**Prompt:** ${prompt}\n` + `**Status:** Task submitted successfully\n\n` + `💡 **Next Steps:**\n` + `• Use \`midjourney_get_task\` with task ID "${taskId}" to check progress\n` + `• Typical generation time: 1-3 minutes\n` + `• You'll be able to upscale (U1-U4) or create variations (V1-V4) once complete\n\n` + `⏱️ **Estimated Time:** 30-90 seconds`); } catch (error) { return createErrorResult(`Failed to submit imagine task: ${error instanceof Error ? error.message : String(error)}`); } } /** * Handle upscale task */ async function handleUpscaleTask(args, apiClient, _taskPoller) { try { const response = await apiClient.submitUpscale(args.task_id, args.index); if (response.code !== 1 || !response.result) { return createErrorResult(`Failed to submit upscale task: ${response.description}`); } const taskId = response.result; return createSuccessResult(`🔍 **Image Upscale Started!**\n\n` + `**New Task ID:** ${taskId}\n` + `**Original Task:** ${args.task_id}\n` + `**Image Index:** ${args.index}\n` + `**Status:** Task submitted successfully\n\n` + `💡 **Next Steps:**\n` + `• Use \`midjourney_get_task\` with task ID "${taskId}" to check progress\n` + `• Upscaling typically takes 30-60 seconds\n` + `• The result will be a higher resolution version of the selected image\n\n` + `⏱️ **Estimated Time:** 30-60 seconds`); } catch (error) { return createErrorResult(`Failed to submit upscale task: ${error instanceof Error ? error.message : String(error)}`); } } /** * Handle variation task */ async function handleVariationTask(args, apiClient, _taskPoller) { try { const response = await apiClient.submitVariation(args.task_id, args.index); if (response.code !== 1 || !response.result) { return createErrorResult(`Failed to submit variation task: ${response.description}`); } const taskId = response.result; return createSuccessResult(`🎭 **Image Variation Started!**\n\n` + `**New Task ID:** ${taskId}\n` + `**Original Task:** ${args.task_id}\n` + `**Image Index:** ${args.index}\n` + `**Status:** Task submitted successfully\n\n` + `💡 **Next Steps:**\n` + `• Use \`midjourney_get_task\` with task ID "${taskId}" to check progress\n` + `• Variations typically take 1-2 minutes\n` + `• You'll get 4 new variations based on the selected image\n\n` + `⏱️ **Estimated Time:** 60-120 seconds`); } catch (error) { return createErrorResult(`Failed to submit variation task: ${error instanceof Error ? error.message : String(error)}`); } } /** * Handle reroll task */ async function handleRerollTask(args, apiClient, _taskPoller) { try { const response = await apiClient.submitReroll(args.task_id); if (response.code !== 1 || !response.result) { return createErrorResult(`Failed to submit reroll task: ${response.description}`); } const taskId = response.result; return createSuccessResult(`🔄 **Image Reroll Started!**\n\n` + `**New Task ID:** ${taskId}\n` + `**Original Task:** ${args.task_id}\n` + `**Status:** Task submitted successfully\n\n` + `💡 **Next Steps:**\n` + `• Use \`midjourney_get_task\` with task ID "${taskId}" to check progress\n` + `• Rerolls typically take 1-3 minutes\n` + `• You'll get 4 completely new images with the same prompt\n\n` + `⏱️ **Estimated Time:** 60-180 seconds`); } catch (error) { return createErrorResult(`Failed to submit reroll task: ${error instanceof Error ? error.message : String(error)}`); } } //# sourceMappingURL=midjourney.js.map