midjourney-mcp
Version:
A Model Context Protocol server for Midjourney integration via MJ API
187 lines • 8.63 kB
JavaScript
/**
* 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