local-mcp 3.0.236 → 3.0.238
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 +22 -0
- package/package.json +1 -1
- package/setup.js +55 -32
package/index.js
CHANGED
|
@@ -228,6 +228,28 @@ async function main() {
|
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
+
// ADR-0004 phase 3 (darwin): prefer the notarized server embedded in
|
|
232
|
+
// LocalMCPTray.app. Ensure the .app is installed, then launch its embedded
|
|
233
|
+
// server directly — skipping the standalone download + ad-hoc re-sign that
|
|
234
|
+
// resets Automation TCC (Mail/Notes/Messages/Safari) on every update. Only
|
|
235
|
+
// if the .app can't be provided do we fall through to the legacy standalone
|
|
236
|
+
// binary (which still ad-hoc signs as a last resort so the user isn't stranded).
|
|
237
|
+
if (process.platform === 'darwin') {
|
|
238
|
+
await ensureDarwinComponents()
|
|
239
|
+
const embedded = findEmbeddedServer()
|
|
240
|
+
if (embedded) {
|
|
241
|
+
let v = pkg.version
|
|
242
|
+
try {
|
|
243
|
+
v = fs.readFileSync(
|
|
244
|
+
path.join(os.homedir(), '.local', 'share', 'local-mcp', 'tray', '.version'),
|
|
245
|
+
'utf8'
|
|
246
|
+
).trim() || pkg.version
|
|
247
|
+
} catch {}
|
|
248
|
+
launchMcpStdio(embedded, v)
|
|
249
|
+
return
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
231
253
|
// Fast path: if stable binary exists AND its version is >= our npm package version, exec directly.
|
|
232
254
|
// Using >= (not ===) prevents Claude Desktop from downgrading a binary that the tray's
|
|
233
255
|
// UpdateManager has already upgraded. LMC-375: machine 5F8445AE downgraded 3.0.72→3.0.70
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "local-mcp",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.238",
|
|
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
|
@@ -369,41 +369,64 @@ async function runSetup(opts = {}) {
|
|
|
369
369
|
let stableCommand = NPX_COMMAND // fallback; replaced below once CACHE_DIR is known
|
|
370
370
|
let stableArgs = NPX_ARGS
|
|
371
371
|
let binaryVersion = ''
|
|
372
|
+
// ADR-0004 phase 3 (darwin): if the notarized server is already embedded in
|
|
373
|
+
// LocalMCPTray.app, skip pre-downloading + ad-hoc re-signing the standalone
|
|
374
|
+
// binary — the launcher (→ npx → index.js) prefers the embedded one anyway,
|
|
375
|
+
// and the ad-hoc copy is what resets Automation TCC. The tray is ensured later
|
|
376
|
+
// in setup; on a fresh install where the .app isn't present yet this is null
|
|
377
|
+
// and we keep the legacy pre-download as a fallback.
|
|
378
|
+
const _embeddedServer = process.platform === 'darwin'
|
|
379
|
+
? [
|
|
380
|
+
path.join(os.homedir(), 'Applications', 'LocalMCPTray.app', 'Contents', 'MacOS', 'local-mcp-server'),
|
|
381
|
+
path.join('/Applications', 'LocalMCPTray.app', 'Contents', 'MacOS', 'local-mcp-server'),
|
|
382
|
+
].find(p => { try { return fs.statSync(p).isFile() } catch { return false } })
|
|
383
|
+
: null
|
|
372
384
|
try {
|
|
373
385
|
const { ensureBinary, CACHE_DIR } = require('./download')
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
// Copy binary to stable path (npx fast-path will exec it directly)
|
|
378
|
-
const stablePath = path.join(CACHE_DIR, 'local-mcp-server')
|
|
379
|
-
try {
|
|
380
|
-
const tmpPath = stablePath + '.tmp'
|
|
381
|
-
fs.copyFileSync(binPath, tmpPath)
|
|
382
|
-
fs.chmodSync(tmpPath, 0o755)
|
|
383
|
-
try { execFileSync('codesign', ['--force', '--sign', '-', '--identifier', 'com.local-mcp.server', tmpPath], { stdio: 'pipe' }) } catch {}
|
|
384
|
-
// curl route-3 installs the binary one level deeper:
|
|
385
|
-
// ~/.local/share/local-mcp/bin/local-mcp-server/local-mcp-server
|
|
386
|
-
// leaving stablePath itself as a DIRECTORY. fs.renameSync throws EISDIR
|
|
387
|
-
// silently, so the npm stable binary is never written and the old curl
|
|
388
|
-
// server stays running forever (LMC-158).
|
|
386
|
+
if (_embeddedServer) {
|
|
387
|
+
// Embedded server present — no standalone download needed. Still write the
|
|
388
|
+
// launcher and record the embedded version for the npx fast-path skip.
|
|
389
389
|
try {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
//
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
390
|
+
binaryVersion = fs.readFileSync(
|
|
391
|
+
path.join(os.homedir(), '.local', 'share', 'local-mcp', 'tray', '.version'), 'utf8'
|
|
392
|
+
).trim()
|
|
393
|
+
} catch {}
|
|
394
|
+
process.stderr.write('✓ Using server embedded in LocalMCPTray.app\n\n')
|
|
395
|
+
} else {
|
|
396
|
+
process.stderr.write('Downloading LMCP runtime...\n')
|
|
397
|
+
const { binPath, version: bv } = await ensureBinary()
|
|
398
|
+
binaryVersion = bv || ''
|
|
399
|
+
// Copy binary to stable path (npx fast-path will exec it directly)
|
|
400
|
+
const stablePath = path.join(CACHE_DIR, 'local-mcp-server')
|
|
401
|
+
try {
|
|
402
|
+
const tmpPath = stablePath + '.tmp'
|
|
403
|
+
fs.copyFileSync(binPath, tmpPath)
|
|
404
|
+
fs.chmodSync(tmpPath, 0o755)
|
|
405
|
+
try { execFileSync('codesign', ['--force', '--sign', '-', '--identifier', 'com.local-mcp.server', tmpPath], { stdio: 'pipe' }) } catch {}
|
|
406
|
+
// curl route-3 installs the binary one level deeper:
|
|
407
|
+
// ~/.local/share/local-mcp/bin/local-mcp-server/local-mcp-server
|
|
408
|
+
// leaving stablePath itself as a DIRECTORY. fs.renameSync throws EISDIR
|
|
409
|
+
// silently, so the npm stable binary is never written and the old curl
|
|
410
|
+
// server stays running forever (LMC-158).
|
|
411
|
+
try {
|
|
412
|
+
const st = fs.statSync(stablePath)
|
|
413
|
+
if (st.isDirectory()) {
|
|
414
|
+
process.stderr.write(' Migrating from curl install: removing old versioned directory at stable path\n')
|
|
415
|
+
fs.rmSync(stablePath, { recursive: true, force: true })
|
|
416
|
+
}
|
|
417
|
+
} catch { /* stablePath doesn't exist — nothing to do */ }
|
|
418
|
+
fs.renameSync(tmpPath, stablePath)
|
|
419
|
+
// Write the actual binary version (from /runtime/latest), not the npm package
|
|
420
|
+
// version. npm and Swift binary versions can diverge (npm-only fixes bump npm
|
|
421
|
+
// without a Swift rebuild). Writing pkg.version here caused the tray to think
|
|
422
|
+
// a newer binary was on disk and restart-loop (LMC-TODO).
|
|
423
|
+
fs.writeFileSync(path.join(CACHE_DIR, '.server-version'), binaryVersion || '')
|
|
424
|
+
const settingsSrc = path.join(path.dirname(binPath), 'settings.html')
|
|
425
|
+
const settingsDst = path.join(CACHE_DIR, 'settings.html')
|
|
426
|
+
if (fs.existsSync(settingsSrc)) fs.copyFileSync(settingsSrc, settingsDst)
|
|
427
|
+
} catch {}
|
|
428
|
+
process.stderr.write('✓ Runtime ready\n\n')
|
|
429
|
+
}
|
|
407
430
|
// Write the launcher script now that we have CACHE_DIR.
|
|
408
431
|
// The launcher uses curl (no Node dependency) to send telemetry if Node is
|
|
409
432
|
// too old, then exec's npx. Claude Desktop runs this script instead of npx
|