christmas-mcp-image-describe
Version:
MCP server that analyzes images and provides structured metadata for website placement decisions using OpenAI GPT-4o Vision API
263 lines (225 loc) • 9.22 kB
JavaScript
#!/usr/bin/env node
import { analyzeImage } from '../src/imageAnalyzer.js';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import process from 'process';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
async function startMCPServer() {
console.error('[MCP Server] Starting Christmas MCP Image Describe server...');
// Import and start MCP server
const { Server } = await import('@modelcontextprotocol/sdk/server/index.js');
const { StdioServerTransport } = await import('@modelcontextprotocol/sdk/server/stdio.js');
const { CallToolRequestSchema, ListToolsRequestSchema } = await import('@modelcontextprotocol/sdk/types.js');
const { analyzeImage, analyzeImages } = await import('../src/imageAnalyzer.js');
class ImageAnalysisMCPServer {
constructor() {
this.server = new Server(
{
name: 'christmas-mcp-image-describe',
version: '1.0.4',
},
{
capabilities: {
tools: {},
},
}
);
this.setupHandlers();
console.error('[MCP Server] Server initialized successfully');
}
setupHandlers() {
// List available tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
console.error('[MCP Server] Listing tools');
return {
tools: [
{
name: 'analyze_image',
description: 'Analyze a single image and return structured metadata for website placement decisions',
inputSchema: {
type: 'object',
properties: {
imagePath: {
type: 'string',
description: 'Path to the image file to analyze'
},
context: {
type: 'string',
description: 'Optional context about where the image will be used (e.g., "homepage hero", "about section")'
},
apiKey: {
type: 'string',
description: 'OpenAI API key (optional if OPENAI_API_KEY environment variable is set)'
},
projectId: {
type: 'string',
description: 'OpenAI project ID (optional)'
}
},
required: ['imagePath']
}
},
{
name: 'analyze_images_batch',
description: 'Analyze multiple images in batch and return structured metadata for each',
inputSchema: {
type: 'object',
properties: {
imagePaths: {
type: 'array',
items: { type: 'string' },
description: 'Array of paths to image files to analyze'
},
context: {
type: 'string',
description: 'Optional context about where the images will be used'
},
apiKey: {
type: 'string',
description: 'OpenAI API key (optional if OPENAI_API_KEY environment variable is set)'
},
projectId: {
type: 'string',
description: 'OpenAI project ID (optional)'
}
},
required: ['imagePaths']
}
}
]
};
});
// Handle tool calls
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
console.error(`[MCP Server] Tool called: ${request.params.name}`);
try {
if (request.params.name === 'analyze_image') {
const { imagePath, context, apiKey, projectId } = request.params.arguments;
// Use environment variables if not provided in arguments
const finalApiKey = apiKey || process.env.OPENAI_API_KEY;
const finalProjectId = projectId || process.env.OPENAI_PROJECT;
if (!imagePath || !finalApiKey) {
throw new Error('Missing required parameters: imagePath and apiKey are required');
}
console.error(`[MCP Server] Analyzing image: ${imagePath}`);
const result = await analyzeImage(imagePath, context, finalApiKey, finalProjectId);
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2)
}
]
};
}
if (request.params.name === 'analyze_images_batch') {
const { imagePaths, context, apiKey, projectId } = request.params.arguments;
// Use environment variables if not provided in arguments
const finalApiKey = apiKey || process.env.OPENAI_API_KEY;
const finalProjectId = projectId || process.env.OPENAI_PROJECT;
if (!imagePaths || !Array.isArray(imagePaths) || !finalApiKey) {
throw new Error('Missing required parameters: imagePaths (array) and apiKey are required');
}
console.error(`[MCP Server] Analyzing ${imagePaths.length} images in batch`);
const results = await analyzeImages(imagePaths, context, finalApiKey, finalProjectId);
return {
content: [
{
type: 'text',
text: JSON.stringify(results, null, 2)
}
]
};
}
throw new Error(`Unknown tool: ${request.params.name}`);
} catch (error) {
console.error(`[MCP Server] Tool execution error:`, error);
return {
content: [
{
type: 'text',
text: `Error: ${error.message}`
}
],
isError: true
};
}
});
console.error('[MCP Server] Handlers set up successfully');
}
async run() {
try {
console.error('[MCP Server] Starting server transport...');
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('[MCP Server] Server connected and running');
} catch (error) {
console.error('[MCP Server] Failed to start server:', error);
process.exit(1);
}
}
}
const server = new ImageAnalysisMCPServer();
server.run().catch((error) => {
console.error('[MCP Server] Server failed to start:', error);
process.exit(1);
});
}
async function main() {
const args = process.argv.slice(2);
// Check for MCP server mode
if (args.includes('--mcp-server')) {
return startMCPServer();
}
if (args.length === 0) {
console.log(`
Christmas MCP Image Describe - CLI Example
Usage:
node cli.js <image-path> [context] [api-key] [project-id]
christmas-mcp-image-describe --mcp-server # Start MCP server for VS Code
Arguments:
image-path Path to the image file to analyze
context Optional context (e.g., "homepage hero", "about section")
api-key OpenAI API key (or set OPENAI_API_KEY environment variable)
project-id OpenAI project ID (or set OPENAI_PROJECT environment variable)
Examples:
node cli.js ./sample.jpg
node cli.js ./hero.png "homepage hero"
node cli.js ./team.jpg "about section" sk-your-api-key
christmas-mcp-image-describe --mcp-server # For VS Code MCP integration
Environment Variables:
OPENAI_API_KEY Your OpenAI API key
OPENAI_PROJECT Your OpenAI project ID (optional)
`);
process.exit(1);
}
const imagePath = args[0];
const context = args[1] || '';
const apiKey = args[2] || process.env.OPENAI_API_KEY;
const project = args[3] || process.env.OPENAI_PROJECT;
if (!apiKey) {
console.error('Error: OpenAI API key is required. Set OPENAI_API_KEY environment variable or provide as argument.');
process.exit(1);
}
try {
console.log('Analyzing image...');
console.log(`Image: ${imagePath}`);
if (context) console.log(`Context: ${context}`);
console.log('');
const result = await analyzeImage(imagePath, context, apiKey, project);
console.log('Analysis Result:');
console.log('================');
console.log(JSON.stringify(result, null, 2));
console.log('\\nFormatted Output:');
console.log('=================');
console.log(`Description: ${result.description}`);
console.log(`Suggested Placement: ${result.placement}`);
console.log(`Tags: ${result.tags.join(', ')}`);
console.log(`Alt Text: ${result.alt}`);
} catch (error) {
console.error('Error analyzing image:', error.message);
process.exit(1);
}
}
main();