UNPKG

simple-milvus-mcp

Version:

MCP server for Milvus vector database with semantic and full-text search capabilities

201 lines 11.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.startMilvusLiteServer = void 0; /* istanbul ignore file */ const child_process_1 = require("child_process"); const path = __importStar(require("path")); const logger_1 = require("../utils/logger"); // Assuming logger is correctly set up function startMilvusLiteServer(options = {}) { const dataPath = options.dataPath || ''; // Python script defaults to 'test.db' if this is empty const pythonCmd = process.platform === 'win32' ? 'python' : 'python3'; // Ensure logger level is set if provided if (options.logLevel) { logger_1.logger.level = options.logLevel; } else { // Default logger level if not set (optional, depends on your logger's default) // logger.level = 'info'; } return new Promise((resolve, reject) => { var _a, _b, _c; const startPy = path.join(__dirname, 'start.py'); // Ensure 'start.py' is in the same directory or adjust path logger_1.logger.debug(`Starting Milvus Lite server with python script: ${startPy} using ${pythonCmd}`); if (dataPath) { logger_1.logger.debug(`Data path for Milvus Lite: ${dataPath}`); } else { logger_1.logger.debug(`No data path specified, Milvus Lite will use its default.`); } const childProcess = (0, child_process_1.spawn)(pythonCmd, ['-u', startPy, dataPath], { // stdio: ['pipe', 'pipe', 'pipe'] // Default, but can be explicit }); let promiseSettled = false; const settlePromise = (settler) => { if (!promiseSettled) { promiseSettled = true; settler(); } }; // Graceful shutdown signal handling for the parent Node.js process const signalHandler = (signal) => { logger_1.logger.debug(`${signal} received for parent process, attempting to stop Milvus Lite server.`); if (childProcess && !childProcess.killed) { childProcess.kill(signal === 'SIGINT' ? 'SIGINT' : 'SIGTERM'); // Forward the signal } // process.exit(); // Exiting the parent process should be handled by the caller or signal default behavior }; process.on('SIGINT', () => signalHandler('SIGINT')); process.on('SIGTERM', () => signalHandler('SIGTERM')); // The 'exit' handler for the parent process might be too late or might not run for all exit types. // It's generally better to ensure resources are cleaned up on signals or before explicit exit. process.on('exit', () => { if (childProcess && !childProcess.killed) { logger_1.logger.debug('Node.js process exiting, ensuring Milvus Lite server process is killed.'); childProcess.kill(); // Default SIGTERM } }); childProcess.on('error', (err) => { logger_1.logger.error(`Error starting Milvus Lite server: ${err}`); reject(err); }); (_a = childProcess.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => { const message = data.toString(); logger_1.logger.error(`Milvus Lite server stderr: ${message}`); if (message.includes("No module named 'milvus_lite'")) { reject(new Error('Milvus Lite is not installed. Please install it using "pip install milvus-lite".')); } }); childProcess.on('exit', (code) => { logger_1.logger.debug(`Milvus Lite server exited with code: ${code}`); if (code !== 0) { reject(new Error(`Milvus Lite server exited with code ${code}`)); } }); (_b = childProcess.stdout) === null || _b === void 0 ? void 0 : _b.on('data', (data) => { const messages = data .toString() .split('\n') .filter(msg => msg.trim() !== ''); messages.forEach(message => { logger_1.logger.debug(`Milvus Lite stdout: ${message}`); try { const parsed = JSON.parse(message); if (parsed.error) { logger_1.logger.error(`Error from Milvus Lite script: ${parsed.error}`); settlePromise(() => reject(new Error(parsed.error))); if (childProcess && !childProcess.killed) { childProcess.kill(); // Kill the process as it reported a fatal error } } else if (parsed.uri && parsed.version) { logger_1.logger.debug(`Milvus Lite server started. URI: ${parsed.uri}, Version: ${parsed.version}`); settlePromise(() => resolve({ uri: parsed.uri, version: parsed.version, stopServer: () => __awaiter(this, void 0, void 0, function* () { return new Promise(resolveStop => { if (childProcess && !childProcess.killed) { logger_1.logger.debug('StopServer: Sending SIGINT to Milvus Lite server...'); // Handle stop confirmation let stopTimeout = null; const onStopExit = (code, signal) => { if (stopTimeout) clearTimeout(stopTimeout); logger_1.logger.debug(`Milvus Lite server process stopped. Code: ${code}, Signal: ${signal}`); resolveStop(); }; childProcess.once('exit', onStopExit); childProcess.kill('SIGINT'); // Python script handles SIGINT to stop server_manager_instance // Timeout to force kill if SIGINT doesn't work stopTimeout = setTimeout(() => { if (childProcess && !childProcess.killed) { logger_1.logger.warn('Milvus Lite server did not stop with SIGINT in 5s, sending SIGKILL.'); childProcess.kill('SIGKILL'); // Resolve a bit later to allow SIGKILL to process, though 'exit' should still fire setTimeout(resolveStop, 200); } }, 5000); } else { logger_1.logger.debug('StopServer: Milvus Lite server already stopped or not running.'); resolveStop(); } }); }), })); } else if (parsed.info) { logger_1.logger.info(`Info from Milvus Lite script: ${parsed.info}`); } // Ignore other JSON messages if any, or add more specific handling } catch (e) { // This means the line was not JSON. It might be other debug output from Python. logger_1.logger.debug(`Non-JSON stdout from Milvus Lite script: ${message}`); } }); }); (_c = childProcess.stderr) === null || _c === void 0 ? void 0 : _c.on('data', (data) => { const errMessage = data.toString().trim(); logger_1.logger.error(`Milvus Lite stderr: ${errMessage}`); // Generally, errors from Python script that cause it to exit will also result in a non-zero exit code. // You could choose to reject here if stderr always indicates a fatal error for your script. // However, be cautious not to reject twice if stdout or exit handler already does. // For now, just logging it. The exit handler will catch failures. }); childProcess.on('exit', (code, signal) => { logger_1.logger.debug(`Milvus Lite server process exited with code: ${code}, signal: ${signal}`); if (!promiseSettled) { // If promise hasn't been resolved (e.g. with URI) or rejected (e.g. by JSON error) let exitErrorMsg = 'Milvus Lite server process exited prematurely.'; if (signal) { exitErrorMsg = `Milvus Lite server process was terminated by signal: ${signal}.`; } else if (code !== null && code !== 0) { exitErrorMsg = `Milvus Lite server process exited with error code: ${code}.`; } else if (code === 0) { // Exited cleanly but didn't resolve the promise (e.g. no URI sent) exitErrorMsg = 'Milvus Lite server process exited cleanly but did not report a URI.'; } logger_1.logger.error(exitErrorMsg + ' Check logs for more details.'); settlePromise(() => reject(new Error(exitErrorMsg))); } }); }); } exports.startMilvusLiteServer = startMilvusLiteServer; //# sourceMappingURL=MilvusLiteServer.js.map