'use strict'; const fs = require('fs'); const path = require('path'); const os = require('os'); /** * Resolve the OpsxDB Go MCP binary path. * Order: OPSXDB_MCP_BIN → PATH → common install locations. * Skips this package's Node launcher and any #! script shims (npm/npx bin * is also named opsxdb-mcp and must not be mistaken for the Go server). * @returns {string|null} */ function resolveBinary() { const envBin = process.env.OPSXDB_MCP_BIN; if (envBin) { const resolved = path.resolve(envBin); if (isGoMcpBinary(resolved)) return resolved; } const onPath = findOnPath('opsxdb-mcp'); if (onPath) return onPath; const home = os.homedir(); const candidates = [ path.join(home, 'devops', 'opsxdb', 'bin', 'opsxdb-mcp'), path.join(home, '.opsxdb', 'bin', 'opsxdb-mcp'), path.join(home, '.local', 'bin', 'opsxdb-mcp'), '/usr/local/bin/opsxdb-mcp', '/opt/homebrew/bin/opsxdb-mcp', ]; for (const c of candidates) { if (isGoMcpBinary(c)) return c; } return null; } function findOnPath(name) { const pathEnv = process.env.PATH || ''; for (const dir of pathEnv.split(path.delimiter)) { if (!dir) continue; const p = path.join(dir, name); if (isGoMcpBinary(p)) return p; if (process.platform === 'win32') { const pe = p + '.exe'; if (isGoMcpBinary(pe)) return pe; } } return null; } function selfCliPath() { return path.resolve(__dirname, '..', 'bin', 'cli.js'); } function isSameFile(a, b) { try { return fs.realpathSync(a) === fs.realpathSync(b); } catch { return false; } } /** * True only for a real Go/native opsxdb-mcp binary (ELF / Mach-O / PE), * not npm bin shims or this package's Node cli.js. */ function isGoMcpBinary(filePath) { try { if (!filePath) return false; const st = fs.statSync(filePath); if (!st.isFile()) return false; if (isSameFile(filePath, selfCliPath())) return false; if (!isLikelyNativeBinary(filePath)) return false; fs.accessSync(filePath, fs.constants.X_OK); return true; } catch { return false; } } function isLikelyNativeBinary(filePath) { let fd; try { fd = fs.openSync(filePath, 'r'); const buf = Buffer.alloc(8); const n = fs.readSync(fd, buf, 0, 8, 0); if (n < 2) return false; // Reject scripts (npm shims, node shebang) if (buf[0] === 0x23 && buf[1] === 0x21) return false; // #! // ELF if (n >= 4 && buf[0] === 0x7f && buf[1] === 0x45 && buf[2] === 0x4c && buf[3] === 0x46) { return true; } // PE if (buf[0] === 0x4d && buf[1] === 0x5a) return true; if (n < 4) return false; const be = buf.readUInt32BE(0); const le = buf.readUInt32LE(0); // Mach-O 64 / 32 (both endians) + fat const macho = new Set([ 0xfeedfacf, 0xcffaedfe, 0xfeedface, 0xcefaedfe, 0xcafebabe, 0xbebafeca, 0xcafebabf, 0xbfbafeca, ]); if (macho.has(be) || macho.has(le)) return true; return false; } catch { return false; } finally { if (fd !== undefined) { try { fs.closeSync(fd); } catch { /* ignore */ } } } } function missingBinaryMessage() { return `opsxdb-mcp: Go binary not found. This npm package (@rlwj-lab/opsxdb-mcp) is a Node launcher for the OpsxDB MCP server (stdio). The real server is a Go binary named opsxdb-mcp. Build it from the opsxdb repo: cd server && go build -o ../bin/opsxdb-mcp ./cmd/opsxdb-mcp Then either: - put that binary on your PATH (ahead of any npm shim), or - export OPSXDB_MCP_BIN=/absolute/path/to/opsxdb-mcp Cursor / Claude Desktop example: { "mcpServers": { "opsxdb": { "command": "npx", "args": ["-y", "@rlwj-lab/opsxdb-mcp"], "env": { "OPSXDB_MCP_BIN": "/absolute/path/to/opsxdb-mcp" } } } } Config files (same as native binary): ~/.opsxdb/mcp.json ~/.opsxdb/connections.json `; } module.exports = { resolveBinary, missingBinaryMessage, isGoMcpBinary, };