local-mcp 3.0.137 → 3.0.138
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +14 -0
- package/package.json +1 -1
- package/setup.js +73 -4
package/index.js
CHANGED
|
@@ -24,6 +24,20 @@ if (process.platform !== 'darwin') {
|
|
|
24
24
|
process.exit(1)
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
// Node version guard — Claude Desktop can silently launch LMCP with an old
|
|
28
|
+
// nvm default (e.g. v11) that makes `npx -y` fail before this file loads.
|
|
29
|
+
// If this code IS running on an old Node, surface the error clearly so the
|
|
30
|
+
// user sees it in Claude Desktop's MCP logs instead of a cryptic spawn error.
|
|
31
|
+
if (parseInt(process.version.slice(1)) < 16) {
|
|
32
|
+
const msg = `LMCP requires Node 16+. Running ${process.version}.\n` +
|
|
33
|
+
'If you use nvm, run: nvm alias default 22\n' +
|
|
34
|
+
'Then restart Claude Desktop / Cursor.'
|
|
35
|
+
process.stderr.write(msg + '\n')
|
|
36
|
+
// Exit with a non-zero code so the MCP host marks the server as failed
|
|
37
|
+
// (vs hanging forever with no output).
|
|
38
|
+
process.exit(1)
|
|
39
|
+
}
|
|
40
|
+
|
|
27
41
|
const cmd = process.argv[2]
|
|
28
42
|
|
|
29
43
|
async function main() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "local-mcp",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.138",
|
|
4
4
|
"description": "LMCP — connect Claude Desktop, Cursor, Windsurf to Mail, Calendar, Contacts, Teams, OneDrive on macOS. Privacy-first: all data stays on your Mac.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
package/setup.js
CHANGED
|
@@ -16,6 +16,49 @@ const { execSync, execFileSync } = require('child_process')
|
|
|
16
16
|
const HOME = os.homedir()
|
|
17
17
|
const NPX_COMMAND = 'npx'
|
|
18
18
|
const NPX_ARGS = ['-y', 'local-mcp@latest']
|
|
19
|
+
|
|
20
|
+
// Resolve absolute path to npx from the current Node binary so Claude Desktop
|
|
21
|
+
// doesn't pick up an old npx from its own PATH (common with nvm users whose
|
|
22
|
+
// nvm default points to Node v11/v12 — those npx versions don't support -y).
|
|
23
|
+
// Falls back to plain 'npx' if resolution fails (non-nvm setups, symlinks, etc.)
|
|
24
|
+
function _resolveNpxPath() {
|
|
25
|
+
try {
|
|
26
|
+
const candidate = path.join(path.dirname(process.execPath), 'npx')
|
|
27
|
+
if (fs.existsSync(candidate)) return candidate
|
|
28
|
+
} catch {}
|
|
29
|
+
return NPX_COMMAND
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Write a shell launcher script that wraps npx with a Node version check and
|
|
33
|
+
// curl-based telemetry. This gives us visibility into failures that happen
|
|
34
|
+
// BEFORE Node loads our code (e.g. old nvm default in Claude Desktop's PATH).
|
|
35
|
+
// Returns the path to the launcher, or null if writing fails.
|
|
36
|
+
function _writeLaunchScript(npxAbsPath, cacheDir) {
|
|
37
|
+
try {
|
|
38
|
+
fs.mkdirSync(cacheDir, { recursive: true })
|
|
39
|
+
const launcherPath = path.join(cacheDir, 'lmcp-launch.sh')
|
|
40
|
+
const script = [
|
|
41
|
+
'#!/bin/bash',
|
|
42
|
+
'# LMCP launcher — generated by npx local-mcp setup, do not edit.',
|
|
43
|
+
'# Checks Node version before launching npx; sends telemetry if too old.',
|
|
44
|
+
'NODE_VER=$(node --version 2>/dev/null || echo "none")',
|
|
45
|
+
'NODE_MAJOR=$(echo "$NODE_VER" | sed \'s/v//\' | cut -d. -f1)',
|
|
46
|
+
'if [ "${NODE_MAJOR:-0}" -lt 16 ] 2>/dev/null; then',
|
|
47
|
+
' # curl telemetry — no Node dependency, fire-and-forget',
|
|
48
|
+
` curl -sf --max-time 3 -X POST "https://${BACKEND_HOST}/install-event" \\`,
|
|
49
|
+
' -H "Content-Type: application/json" \\',
|
|
50
|
+
' -d "{\\\"stage\\\":\\\"node_too_old\\\",\\\"version\\\":\\\"$NODE_VER\\\"}" &>/dev/null &',
|
|
51
|
+
' printf \'LMCP requires Node 16+. Current: %s\\nFix: nvm alias default 22 — then restart Claude Desktop.\\n\' "$NODE_VER" >&2',
|
|
52
|
+
' exit 1',
|
|
53
|
+
'fi',
|
|
54
|
+
`exec "${npxAbsPath}" -y local-mcp@latest "$@"`,
|
|
55
|
+
].join('\n') + '\n'
|
|
56
|
+
fs.writeFileSync(launcherPath, script, { mode: 0o755 })
|
|
57
|
+
return launcherPath
|
|
58
|
+
} catch {
|
|
59
|
+
return null
|
|
60
|
+
}
|
|
61
|
+
}
|
|
19
62
|
const STABLE_LINK = path.join(os.homedir(), '.local', 'share', 'local-mcp', 'bin', 'local-mcp-server')
|
|
20
63
|
const BACKEND_HOST = 'office-mcp-production.up.railway.app'
|
|
21
64
|
|
|
@@ -212,9 +255,21 @@ async function runSetup(opts = {}) {
|
|
|
212
255
|
console.log('║ LMCP — Setup Wizard ║')
|
|
213
256
|
console.log('╚══════════════════════════════════════╝\n')
|
|
214
257
|
|
|
258
|
+
// Warn if running on an old Node version. Claude Desktop resolves 'npx' from
|
|
259
|
+
// its own PATH (not the user's shell), so an old nvm default (v11/v12) causes
|
|
260
|
+
// a silent "You must supply a command" failure on first launch.
|
|
261
|
+
const nodeMajor = parseInt(process.version.slice(1))
|
|
262
|
+
if (nodeMajor < 16) {
|
|
263
|
+
console.error(`\n⚠️ Warning: you're running Node ${process.version}.`)
|
|
264
|
+
console.error(' Claude Desktop may fail to start LMCP because it finds an old npx on its PATH.')
|
|
265
|
+
console.error(' Fix: nvm alias default 22 (then relaunch Claude Desktop)\n')
|
|
266
|
+
}
|
|
267
|
+
|
|
215
268
|
// Pre-download binary so first launch is instant
|
|
216
|
-
// All clients use
|
|
217
|
-
|
|
269
|
+
// All clients use a shell launcher that wraps npx (self-healing if binary is
|
|
270
|
+
// missing/broken, and surfaces telemetry + clear errors if Node is too old).
|
|
271
|
+
let npxAbsPath = _resolveNpxPath() // baked into the launcher script
|
|
272
|
+
let stableCommand = NPX_COMMAND // fallback; replaced below once CACHE_DIR is known
|
|
218
273
|
let stableArgs = NPX_ARGS
|
|
219
274
|
let binaryVersion = ''
|
|
220
275
|
try {
|
|
@@ -252,11 +307,25 @@ async function runSetup(opts = {}) {
|
|
|
252
307
|
if (fs.existsSync(settingsSrc)) fs.copyFileSync(settingsSrc, settingsDst)
|
|
253
308
|
} catch {}
|
|
254
309
|
process.stderr.write('✓ Runtime ready\n\n')
|
|
310
|
+
// Write the launcher script now that we have CACHE_DIR.
|
|
311
|
+
// The launcher uses curl (no Node dependency) to send telemetry if Node is
|
|
312
|
+
// too old, then exec's npx. Claude Desktop runs this script instead of npx
|
|
313
|
+
// directly, so failures are visible in MCP logs AND in our backend events.
|
|
314
|
+
const launcherPath = _writeLaunchScript(npxAbsPath, CACHE_DIR)
|
|
315
|
+
if (launcherPath) stableCommand = launcherPath
|
|
255
316
|
} catch (err) {
|
|
256
317
|
process.stderr.write(` (Runtime download failed, will download on first run: ${err.message})\n\n`)
|
|
318
|
+
// Still try to write a launcher even if binary download failed — the version
|
|
319
|
+
// check + telemetry path is independent of the binary.
|
|
320
|
+
try {
|
|
321
|
+
const { CACHE_DIR } = require('./download')
|
|
322
|
+
const launcherPath = _writeLaunchScript(npxAbsPath, CACHE_DIR)
|
|
323
|
+
if (launcherPath) stableCommand = launcherPath
|
|
324
|
+
} catch {}
|
|
257
325
|
}
|
|
258
|
-
//
|
|
259
|
-
//
|
|
326
|
+
// stableCommand is now the shell launcher script path. It wraps npx with a
|
|
327
|
+
// Node version check + curl telemetry before exec'ing. If launcher creation
|
|
328
|
+
// failed it falls back to plain 'npx'.
|
|
260
329
|
|
|
261
330
|
// Detectar clientes
|
|
262
331
|
const detected = CLIENTS.filter(c => c.detect())
|