simple-milvus-mcp
Version:
MCP server for Milvus vector database with semantic and full-text search capabilities
201 lines • 11.5 kB
JavaScript
;
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