lmstudio-mcp-server
Version:
LM Studio MCP server with concurrent multi-agent support and memory safety
250 lines (207 loc) • 8.35 kB
JavaScript
/**
* LM Studio MCP Server - NPM Package Entry Point
* This script downloads and runs the LM Studio MCP server
*/
const { spawn } = require('child_process');
const path = require('path');
const fs = require('fs');
const https = require('https');
const { URL } = require('url');
// Configuration
const CONFIG = {
GITHUB_REPO: 'samscarrow/lmstudio-mcp-consolidated',
PYTHON_SCRIPT: 'lmstudio_bridge.py',
INSTALL_DIR: path.join(require('os').homedir(), '.lmstudio-mcp'),
DEFAULT_API_BASE: 'http://localhost:1234/v1'
};
class LMStudioMCPRunner {
constructor() {
this.installDir = CONFIG.INSTALL_DIR;
this.scriptPath = path.join(this.installDir, CONFIG.PYTHON_SCRIPT);
}
async log(message, type = 'info') {
const timestamp = new Date().toISOString();
const prefix = type === 'error' ? '❌' : type === 'warn' ? '⚠️' : 'ℹ️';
console.log(`${prefix} [${timestamp}] ${message}`);
}
async checkPython() {
return new Promise((resolve) => {
const python = spawn('python3', ['--version'], { stdio: 'pipe' });
python.on('close', (code) => resolve(code === 0));
python.on('error', () => resolve(false));
});
}
async downloadFile(url, destPath) {
return new Promise((resolve, reject) => {
const file = fs.createWriteStream(destPath);
https.get(url, (response) => {
if (response.statusCode === 302 || response.statusCode === 301) {
// Handle redirect
return this.downloadFile(response.headers.location, destPath)
.then(resolve)
.catch(reject);
}
if (response.statusCode !== 200) {
reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
return;
}
response.pipe(file);
file.on('finish', () => resolve());
file.on('error', reject);
}).on('error', reject);
});
}
async ensureInstalled() {
// Check if already installed
if (fs.existsSync(this.scriptPath)) {
this.log('LM Studio MCP server already installed');
return true;
}
this.log('Installing LM Studio MCP server...');
// Create install directory
if (!fs.existsSync(this.installDir)) {
fs.mkdirSync(this.installDir, { recursive: true });
}
// Download main files
const filesToDownload = [
'lmstudio_bridge.py',
'requirements.txt',
'README.md'
];
for (const file of filesToDownload) {
try {
const url = `https://raw.githubusercontent.com/${CONFIG.GITHUB_REPO}/main/${file}`;
const destPath = path.join(this.installDir, file);
this.log(`Downloading ${file}...`);
await this.downloadFile(url, destPath);
} catch (error) {
this.log(`Failed to download ${file}: ${error.message}`, 'error');
// Continue with other files
}
}
// Install Python dependencies
try {
this.log('Installing Python dependencies...');
const pip = spawn('pip3', ['install', '-r', path.join(this.installDir, 'requirements.txt')], {
stdio: 'inherit'
});
await new Promise((resolve, reject) => {
pip.on('close', (code) => {
if (code === 0) resolve();
else reject(new Error(`pip install failed with code ${code}`));
});
pip.on('error', reject);
});
this.log('✅ Installation complete!');
return true;
} catch (error) {
this.log(`Failed to install dependencies: ${error.message}`, 'error');
this.log('You may need to install dependencies manually:', 'warn');
this.log(` pip3 install -r ${path.join(this.installDir, 'requirements.txt')}`, 'warn');
return true; // Continue anyway
}
}
async run() {
try {
// Check prerequisites
if (!await this.checkPython()) {
this.log('Python 3 is required but not found. Please install Python 3.7+', 'error');
this.log('Visit: https://python.org/downloads', 'error');
process.exit(1);
}
// Ensure installed
await this.ensureInstalled();
// Check if script exists
if (!fs.existsSync(this.scriptPath)) {
this.log('LM Studio MCP script not found. Installation may have failed.', 'error');
process.exit(1);
}
// Set environment variables
const env = {
...process.env,
LMSTUDIO_API_BASE: process.env.LMSTUDIO_API_BASE || CONFIG.DEFAULT_API_BASE,
LOG_LEVEL: process.env.LOG_LEVEL || 'INFO'
};
this.log('Starting LM Studio MCP server...');
this.log(`API Base: ${env.LMSTUDIO_API_BASE}`);
// Run the Python script
const python = spawn('python3', [this.scriptPath], {
env,
stdio: 'inherit',
cwd: this.installDir
});
// Handle process events
python.on('error', (error) => {
this.log(`Failed to start server: ${error.message}`, 'error');
process.exit(1);
});
python.on('close', (code) => {
this.log(`Server exited with code ${code}`);
process.exit(code);
});
// Handle termination signals
process.on('SIGINT', () => {
this.log('Shutting down...');
python.kill('SIGINT');
});
process.on('SIGTERM', () => {
this.log('Shutting down...');
python.kill('SIGTERM');
});
} catch (error) {
this.log(`Error: ${error.message}`, 'error');
process.exit(1);
}
}
}
// CLI argument parsing
function showHelp() {
console.log(`
LM Studio MCP Server
Usage: npx @samscarrow/lmstudio-mcp [options]
Options:
--help, -h Show this help message
--version, -v Show version information
--api-base <url> Set LM Studio API base URL (default: http://localhost:1234/v1)
--log-level <level> Set log level (DEBUG, INFO, WARNING, ERROR)
--install-dir <path> Set custom installation directory
Environment Variables:
LMSTUDIO_API_BASE LM Studio API endpoint
LOG_LEVEL Logging level
Examples:
npx @samscarrow/lmstudio-mcp
npx @samscarrow/lmstudio-mcp --api-base http://192.168.1.100:1234/v1
LMSTUDIO_API_BASE=http://localhost:1234/v1 npx @samscarrow/lmstudio-mcp
`);
}
// Main execution
if (require.main === module) {
const args = process.argv.slice(2);
// Handle command line arguments
if (args.includes('--help') || args.includes('-h')) {
showHelp();
process.exit(0);
}
if (args.includes('--version') || args.includes('-v')) {
const pkg = require('../package.json');
console.log(`${pkg.name} v${pkg.version}`);
process.exit(0);
}
// Parse other arguments
const apiBaseIndex = args.indexOf('--api-base');
if (apiBaseIndex !== -1 && apiBaseIndex + 1 < args.length) {
process.env.LMSTUDIO_API_BASE = args[apiBaseIndex + 1];
}
const logLevelIndex = args.indexOf('--log-level');
if (logLevelIndex !== -1 && logLevelIndex + 1 < args.length) {
process.env.LOG_LEVEL = args[logLevelIndex + 1];
}
const installDirIndex = args.indexOf('--install-dir');
if (installDirIndex !== -1 && installDirIndex + 1 < args.length) {
CONFIG.INSTALL_DIR = args[installDirIndex + 1];
}
// Run the server
const runner = new LMStudioMCPRunner();
runner.run();
}