#!/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 OpenAI from "openai";
import fs from "fs-extra";
import path from "path";
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY || "placeholder",
});
const OUTPUT_DIR = process.env.OUTPUT_DIRECTORY || "./generated_images";
const DEFAULT_SIZE = process.env.DEFAULT_IMAGE_SIZE || "1024x1024";
const DEFAULT_QUALITY = process.env.DEFAULT_QUALITY || "standard";
class DallEMCPServer {
private server: Server;
constructor() {
this.server = new Server(
{
name: "dall-e-mcp-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
this.setupToolHandlers();
this.setupErrorHandling();
}
private setupErrorHandling() {
this.server.onerror = (error) => {
console.error("[MCP Error]", error);
};
process.on("SIGINT", async () => {
await this.server.close();
process.exit(0);
});
}
private setupToolHandlers() {
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "generate_image",
description:
"Generate an image using OpenAI's DALL-E 3 model based on a text prompt",
inputSchema: {
type: "object",
properties: {
prompt: {
type: "string",
description: "The text prompt describing the image to generate",
},
size: {
type: "string",
description: "Image size (1024x1024, 1024x1792, or 1792x1024)",
enum: ["1024x1024", "1024x1792", "1792x1024"],
default: DEFAULT_SIZE,
},
quality: {
type: "string",
description: "Image quality (standard or hd)",
enum: ["standard", "hd"],
default: DEFAULT_QUALITY,
},
style: {
type: "string",
description: "Image style (vivid or natural)",
enum: ["vivid", "natural"],
default: "vivid",
},
filename: {
type: "string",
description: "Optional custom filename (without extension)",
},
},
required: ["prompt"],
},
},
],
};
});
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "generate_image") {
return await this.handleImageGeneration(request.params.arguments);
}
throw new Error(`Unknown tool: ${request.params.name}`);
});
}
private async handleImageGeneration(args: any) {
try {
const {
prompt,
size = DEFAULT_SIZE,
quality = DEFAULT_QUALITY,
style = "vivid",
filename,
} = args;
if (!process.env.OPENAI_API_KEY) {
throw new Error("OPENAI_API_KEY environment variable is required");
}
console.log(`[DALL-E] Generating image: "${prompt.slice(0, 50)}..."`);
const response = await openai.images.generate({
model: "dall-e-3",
prompt: prompt,
n: 1,
size: size as "1024x1024" | "1024x1792" | "1792x1024",
quality: quality as "standard" | "hd",
style: style as "vivid" | "natural",
response_format: "url",
});
if (!response.data || !response.data[0]?.url) {
throw new Error("No image URL received from DALL-E API");
}
const imageUrl = response.data[0].url;
const imageResponse = await fetch(imageUrl);
if (!imageResponse.ok) {
throw new Error(`Failed to download image: ${imageResponse.statusText}`);
}
const imageBuffer = Buffer.from(await imageResponse.arrayBuffer());
await fs.ensureDir(OUTPUT_DIR);
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
const baseFilename = filename || `dalle_${timestamp}`;
const imagePath = path.join(OUTPUT_DIR, `${baseFilename}.png`);
await fs.writeFile(imagePath, imageBuffer);
const result = {
success: true,
message: "Image generated successfully",
details: {
prompt: prompt,
size: size,
quality: quality,
style: style,
file_path: path.resolve(imagePath),
file_size: imageBuffer.length,
timestamp: new Date().toISOString(),
},
};
console.log(`[DALL-E] Image saved: ${imagePath}`);
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
} catch (error) {
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
console.error(`[DALL-E Error] ${errorMessage}`);
const errorResult = {
success: false,
error: errorMessage,
timestamp: new Date().toISOString(),
};
return { content: [{ type: "text", text: JSON.stringify(errorResult, null, 2) }] };
}
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error("DALL-E MCP Server running on stdio");
}
}
const server = new DallEMCPServer();
server.run().catch(console.error);