UNPKG

fahad-mcp-package

Version:

NPM wrapper to run the My Contextual Demo MCP Server (Python)

125 lines (106 loc) 6.05 kB
#!/usr/bin/env node const spawn = require('cross-spawn'); const path = require('path'); const fs = require('fs-extra'); const os = require('os'); const { execSync } = require('child_process'); // --- Configuration for your Python package --- const PYTHON_PACKAGE_NAME = 'fahad-mcp-server'; // Matches name in your Python setup.py const PYTHON_PACKAGE_VERSION = '0.1.5'; // Matches version in your Python setup.py (adjust if you've incremented) const CONSOLE_SCRIPT_NAME = 'fahad_mcp_server'; // Matches name in console_scripts of setup.py // Determine virtual environment path in user's home directory const venvDirName = `.${PYTHON_PACKAGE_NAME}-venv`; const venvPath = path.join(os.homedir(), venvDirName); // Determine Python and Pip executable names based on OS const pythonExecutable = process.platform === 'win32' ? 'python.exe' : 'python3'; const pipExecutable = process.platform === 'win32' ? 'pip.exe' : 'pip3'; /** * Helper function to get the detected Python version. * @param {string} pythonExec - The name of the Python executable (e.g., 'python', 'python3'). * @returns {object|null} An object {major, minor} or null if version cannot be determined. */ function getPythonVersion(pythonExec) { try { const versionOutput = execSync(`${pythonExec} --version`, { encoding: 'utf8', stdio: 'pipe' }); const match = versionOutput.match(/Python (\d+)\.(\d+)/); if (match) { return { major: parseInt(match[1]), minor: parseInt(match[2]) }; } } catch (e) { // Silently fail if python --version command itself fails } return null; } async function runPythonMCP() { console.error(`\nSetting up ${PYTHON_PACKAGE_NAME} Python environment...`); try { // 1. Check for Python 3 availability on the system execSync(`${pythonExecutable} --version`, { stdio: 'pipe' }); console.error('Python found on system.'); // NEW FIX: Check the Python version and enforce 3.10 or higher const pythonVersion = getPythonVersion(pythonExecutable); if (!pythonVersion || pythonVersion.major < 3 || (pythonVersion.major === 3 && pythonVersion.minor < 10)) { console.error(`Error: Detected Python version is ${pythonVersion ? `${pythonVersion.major}.${pythonVersion.minor}` : 'unknown'}.`); console.error(`This MCP server requires Python 3.10 or higher.`); console.error(`Please ensure 'python' (or 'python.exe' on Windows) in your system's PATH points to Python 3.10 or a newer version.`); console.error(`You might need to reinstall Python, ensuring "Add Python to PATH" is selected, or manually adjust your PATH environment variable.`); process.exit(1); } console.error(`Detected Python version: ${pythonVersion.major}.${pythonVersion.minor} (compatible).`); } catch (error) { console.error('Error: Python not found or not in PATH.'); console.error('Please install Python 3 (Python 3.10 or higher recommended) to run this MCP server.'); process.exit(1); } // Determine paths to Python and Pip within the virtual environment const venvBinPath = process.platform === 'win32' ? path.join(venvPath, 'Scripts') : path.join(venvPath, 'bin'); const venvPython = path.join(venvBinPath, pythonExecutable); const venvPip = path.join(venvBinPath, pipExecutable); // 2. Create or ensure virtual environment exists if (!fs.existsSync(venvPath)) { console.error(`Creating virtual environment at ${venvPath}...`); try { execSync(`${pythonExecutable} -m venv ${venvPath}`, { stdio: 'inherit' }); console.error('Virtual environment created successfully.'); } catch (error) { console.error(`Error creating virtual environment: ${error.message}`); process.exit(1); } } else { console.error(`Virtual environment already exists at ${venvPath}.`); } // IMPORTANT FIX: Upgrade pip within the virtual environment BEFORE installing other packages console.error(`Upgrading pip in the virtual environment...`); try { execSync(`${venvPython} -m pip install --upgrade pip`, { stdio: 'inherit' }); console.error('pip upgraded successfully.'); } catch (error) { console.error(`Error upgrading pip: ${error.message}`); // Do not exit here, but log the error as the installation might still proceed } // 3. Install/Upgrade the Python package in the virtual environment console.error(`Installing/Upgrading ${PYTHON_PACKAGE_NAME}==${PYTHON_PACKAGE_VERSION} in venv...`); try { execSync(`${venvPip} install --upgrade ${PYTHON_PACKAGE_NAME}==${PYTHON_PACKAGE_VERSION}`, { stdio: 'inherit' }); console.error(`${PYTHON_PACKAGE_NAME} installed successfully.`); } catch (error) { console.error(`Error installing ${PYTHON_PACKAGE_NAME}:`, error.message); console.error("This might happen if the package isn't yet available on PyPI, there's a network issue, or a core dependency like 'mcp' is still incompatible."); process.exit(1); } // 4. Run the Python MCP server using its console script console.error(`\nStarting ${PYTHON_PACKAGE_NAME} (Python process)...`); // The 'CONSOLE_SCRIPT_NAME' executable is located in the venv's bin/Scripts directory const pythonProcess = spawn(path.join(venvBinPath, CONSOLE_SCRIPT_NAME), process.argv.slice(2), { stdio: 'inherit', // Connects stdin/stdout/stderr to the parent npx process }); pythonProcess.on('close', (code) => { console.error(`\n${PYTHON_PACKAGE_NAME} exited with code ${code}`); process.exit(code); }); pythonProcess.on('error', (err) => { console.error(`\nFailed to start ${PYTHON_PACKAGE_NAME} (Python process): ${err.message}`); process.exit(1); }); } runPythonMCP();