vector-embedding-mcp-server
Version:
MCP Server for AI Embedding and RAG functionality
108 lines (93 loc) • 4.09 kB
JavaScript
/**
* Main entry point for vector-embedding-mcp-server
* This script determines which command to run based on arguments
*/
const { spawn } = require('child_process');
const path = require('path');
const fs = require('fs').promises;
const args = process.argv.slice(2);
// Logging function for consistency with mcp-server.js
// All logs go to stderr to avoid breaking MCP JSON-RPC protocol
const logFile = path.join(__dirname, 'mcp-server.log');
const logToFile = async (message) => {
const timestamp = new Date().toISOString();
const logMessage = `[${timestamp}] [Index] ${message}\n`;
await fs.appendFile(logFile, logMessage).catch(err => console.error(`❌ [Index] Failed to write log: ${err.message}`));
// Use stderr to avoid breaking MCP protocol
console.error(`[Index] ${message}`);
};
// Validate environment variables
const validateEnv = () => {
const requiredEnv = ['DATABASE_URL', 'INDEX_DOCS_FILE_PATH', 'DOCS_FILE_PATH'];
const missingEnv = requiredEnv.filter(env => !process.env[env]);
if (missingEnv.length > 0) {
throw new Error(`Missing required environment variables: ${missingEnv.join(', ')}`);
}
logToFile(`🗄️ DATABASE_URL: ${process.env.DATABASE_URL.replace(/\/\/.*@/, '//***@')}`);
logToFile(`📄 INDEX_DOCS_FILE_PATH: ${process.env.INDEX_DOCS_FILE_PATH}`);
logToFile(`📁 DOCS_FILE_PATH: ${process.env.DOCS_FILE_PATH}`);
};
// Spawn process with error handling
const spawnProcess = (script, scriptArgs, commandName) => {
return new Promise((resolve, reject) => {
logToFile(`🚀 Starting ${commandName} with script: ${script} and args: ${scriptArgs.join(' ')}`);
const child = spawn('node', [script, ...scriptArgs], {
stdio: ['inherit', 'inherit', 'inherit'], // Inherit stdin, stdout, stderr
env: { ...process.env, NODE_ENV: process.env.NODE_ENV || 'development' }
});
child.on('error', (error) => {
logToFile(`❌ [${commandName}] Spawn error: ${error.message}`);
reject(error);
});
child.on('close', (code) => {
logToFile(`🏁 [${commandName}] Completed with exit code: ${code}`);
if (code === 0) {
resolve();
} else {
reject(new Error(`[${commandName}] Failed with exit code ${code}`));
}
});
});
};
// Main execution
async function main() {
try {
const command = args[0] || 'mcp';
// Map commands to scripts
const commandMap = {
'migrate': { script: 'scripts/migrate.js', args: args.slice(1), name: 'Migration' },
'migrate:setup': { script: 'scripts/migrate.js', args: ['setup'], name: 'Migration Setup' },
'migrate:full': { script: 'scripts/migrate.js', args: ['full', ...args.slice(1)], name: 'Full Migration' },
'migrate:stats': { script: 'scripts/migrate.js', args: ['stats'], name: 'Migration Stats' },
'ingest-all': { script: 'scripts/ingest-all.js', args: args.slice(1), name: 'Ingest All Rules' },
'mcp': { script: 'mcp-server.js', args: args.slice(1), name: 'MCP Server' }
};
// For MCP server, skip validation and logging to avoid stdout pollution
// MCP servers must only output JSON-RPC messages to stdout
if (command === 'mcp' || !commandMap[command]) {
// Directly require MCP server without any logging to stdout
require('./src/mcp/mcp-server');
return;
}
// Validate environment variables (only for non-MCP commands)
validateEnv();
const commandConfig = commandMap[command];
if (commandConfig) {
const scriptPath = path.join(__dirname, commandConfig.script);
// Verify script exists
await fs.access(scriptPath).catch(() => {
throw new Error(`Script not found: ${scriptPath}`);
});
await spawnProcess(scriptPath, commandConfig.args, commandConfig.name);
}
} catch (error) {
await logToFile(`❌ Error: ${error.message}`);
console.error(`❌ [Index] Error: ${error.message}`);
process.exit(1);
}
}
main().catch(error => {
console.error(`❌ [Index] Fatal error: ${error.message}`);
process.exit(1);
});