@agentdb/mcpproxy
Version:
MCP proxy server for remote HTTP endpoints supporting JSON and Server-Sent Events
145 lines (119 loc) • 4.2 kB
JavaScript
import { createWriteStream, chmodSync, existsSync, mkdirSync } from 'fs';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
import { pipeline } from 'stream/promises';
import fetch from 'node-fetch';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Configuration
const REPO = 'sutterhill/agentdb';
const BINARY_NAME = 'mcpproxy';
// Platform detection
function getPlatform() {
const platform = process.platform;
const arch = process.arch;
let platformName;
let archName;
switch (platform) {
case 'darwin':
platformName = 'apple-darwin';
break;
case 'linux':
platformName = 'unknown-linux-gnu';
break;
case 'win32':
platformName = 'pc-windows-msvc';
break;
default:
throw new Error(`Unsupported platform: ${platform}`);
}
switch (arch) {
case 'x64':
archName = 'x86_64';
break;
case 'arm64':
archName = 'aarch64';
break;
default:
throw new Error(`Unsupported architecture: ${arch}`);
}
return `${archName}-${platformName}`;
}
function getBinaryName() {
const target = getPlatform();
const extension = process.platform === 'win32' ? '.exe' : '';
return `${BINARY_NAME}-${target}${extension}`;
}
function getLocalBinaryPath() {
const extension = process.platform === 'win32' ? '.exe' : '';
return join(__dirname, '..', 'bin', `${BINARY_NAME}${extension}`);
}
async function downloadBinary() {
const binaryName = getBinaryName();
const localPath = getLocalBinaryPath();
// Create bin directory if it doesn't exist
const binDir = dirname(localPath);
if (!existsSync(binDir)) {
mkdirSync(binDir, { recursive: true });
}
// Skip download if binary already exists
if (existsSync(localPath)) {
console.log('Binary already exists, skipping download');
return;
}
// Check if we're in development mode (local build available)
const localBuildPath = join(__dirname, '..', '..', 'mcpproxy', 'target', 'release', 'mcpproxy');
if (existsSync(localBuildPath)) {
console.log('Using local development build...');
const { copyFileSync } = await import('fs');
copyFileSync(localBuildPath, localPath);
if (process.platform !== 'win32') {
chmodSync(localPath, 0o755);
}
console.log(`✓ Copied local build to ${localPath}`);
return;
}
const downloadUrl = `https://github.com/${REPO}/releases/latest/download/${binaryName}`;
console.log(`Downloading mcpproxy binary for ${getPlatform()}...`);
console.log(`URL: ${downloadUrl}`);
try {
const response = await fetch(downloadUrl);
if (!response.ok) {
throw new Error(`Failed to download binary: ${response.status} ${response.statusText}`);
}
const fileStream = createWriteStream(localPath);
await pipeline(response.body, fileStream);
// Make executable on Unix-like systems
if (process.platform !== 'win32') {
chmodSync(localPath, 0o755);
}
console.log(`✓ mcpproxy binary downloaded successfully to ${localPath}`);
} catch (error) {
console.warn('Failed to download mcpproxy binary:', error.message);
console.warn('');
console.warn('This is expected during development before releases are published.');
console.warn('');
console.warn('To use this package:');
console.warn('1. Build the binary first:');
console.warn(' cd ../mcpproxy && cargo build --release');
console.warn('2. Then install this package');
console.warn('');
console.warn('Or download manually from:');
console.warn(`https://github.com/${REPO}/releases/latest`);
// Don't exit with error during development
if (process.env.NODE_ENV === 'development' || process.env.npm_config_optional === 'true') {
console.warn('Continuing without binary (development mode)');
return;
}
process.exit(1);
}
}
// Only run if this script is executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
downloadBinary().catch(error => {
console.error('Download failed:', error);
process.exit(1);
});
}
export { downloadBinary, getLocalBinaryPath };