#!/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 fetch from 'node-fetch';
const server = new Server({
name: 'fal-openai-image-server',
version: '1.0.0',
}, {
capabilities: {
tools: {},
},
});
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'generate_image',
description: 'Generate images using fal.ai GPT image-1 text-to-image API',
inputSchema: {
type: 'object',
properties: {
prompt: {
type: 'string',
description: 'Text description of the image to generate',
},
image_size: {
type: 'string',
enum: ['auto', '1024x1024', '1536x1024', '1024x1536'],
description: 'Size of the generated image',
default: 'auto',
},
num_images: {
type: 'number',
minimum: 1,
maximum: 4,
description: 'Number of images to generate',
default: 1,
},
quality: {
type: 'string',
enum: ['auto', 'low', 'medium', 'high'],
description: 'Quality of the generated image',
default: 'auto',
},
background: {
type: 'string',
enum: ['auto', 'transparent', 'opaque'],
description: 'Background type of the generated image',
default: 'auto',
},
},
required: ['prompt'],
},
},
],
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === 'generate_image') {
const params = request.params.arguments;
const openaiApiKey = process.env.OPENAI_API_KEY;
const falApiKey = process.env.FAL_KEY;
if (!openaiApiKey) {
throw new Error('OPENAI_API_KEY environment variable is required');
}
if (!falApiKey) {
throw new Error('FAL_KEY environment variable is required');
}
try {
const requestBody = {
prompt: params.prompt,
openai_api_key: openaiApiKey,
...(params.image_size && { image_size: params.image_size }),
...(params.num_images && { num_images: params.num_images }),
...(params.quality && { quality: params.quality }),
...(params.background && { background: params.background }),
};
const response = await fetch('https://fal.run/fal-ai/gpt-image-1/text-to-image/byok', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Key ${falApiKey}`,
},
body: JSON.stringify(requestBody),
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`API request failed: ${response.status} ${response.statusText} - ${errorText}`);
}
const result = await response.json();
return {
content: [
{
type: 'text',
text: JSON.stringify({
success: true,
images: result.images,
count: result.images.length,
}, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: JSON.stringify({
success: false,
error: error instanceof Error ? error.message : 'Unknown error occurred',
}, null, 2),
},
],
};
}
}
throw new Error(`Unknown tool: ${request.params.name}`);
});
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
main().catch((error) => {
console.error('Server error:', error);
process.exit(1);
});