local-mcp 3.0.14 → 3.0.15
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/download.js +3 -3
- package/index.js +25 -16
- package/package.json +1 -1
- package/setup.js +9 -6
package/download.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
/**
|
|
3
|
-
* download.js — descarga y cachea el binario standalone de
|
|
3
|
+
* download.js — descarga y cachea el binario standalone de LMCP desde R2.
|
|
4
4
|
* El binario fue compilado con PyInstaller — no requiere Python instalado.
|
|
5
5
|
* Cache: ~/.local/share/local-mcp/bin/{version}/
|
|
6
6
|
*/
|
|
@@ -37,7 +37,7 @@ function getArch() {
|
|
|
37
37
|
const arch = process.arch
|
|
38
38
|
if (arch === 'arm64') return 'darwin-arm64'
|
|
39
39
|
if (arch === 'x64') return 'darwin-x64'
|
|
40
|
-
throw new Error(`Arquitectura no soportada: ${arch}.
|
|
40
|
+
throw new Error(`Arquitectura no soportada: ${arch}. LMCP requiere macOS arm64 o x64.`)
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
@@ -129,7 +129,7 @@ async function ensureBinary() {
|
|
|
129
129
|
return { binPath, versionDir }
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
process.stderr.write(`\
|
|
132
|
+
process.stderr.write(`\nLMCP v${version} no encontrado en cache.\n`)
|
|
133
133
|
process.stderr.write(`Descargando desde ${url}\n`)
|
|
134
134
|
|
|
135
135
|
fs.mkdirSync(versionDir, { recursive: true })
|
package/index.js
CHANGED
|
@@ -18,7 +18,7 @@ const fs = require('fs')
|
|
|
18
18
|
|
|
19
19
|
// Solo macOS
|
|
20
20
|
if (process.platform !== 'darwin') {
|
|
21
|
-
console.error('
|
|
21
|
+
console.error('LMCP solo está disponible para macOS.')
|
|
22
22
|
process.exit(1)
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -63,7 +63,7 @@ async function main() {
|
|
|
63
63
|
res.on('end', () => {
|
|
64
64
|
try {
|
|
65
65
|
const s = JSON.parse(data)
|
|
66
|
-
console.log(`
|
|
66
|
+
console.log(`LMCP v${s.version} — ${s.server}`)
|
|
67
67
|
console.log(`Licencia: ${s.license?.status} (${s.license?.days_left}d)`)
|
|
68
68
|
} catch { console.log(data) }
|
|
69
69
|
})
|
|
@@ -74,23 +74,30 @@ async function main() {
|
|
|
74
74
|
// ── Modo default: stdio MCP server ──────────────────────────────────────────
|
|
75
75
|
const { CACHE_DIR } = require('./download')
|
|
76
76
|
const stableBin = path.join(CACHE_DIR, 'local-mcp-server')
|
|
77
|
+
const versionFile = path.join(CACHE_DIR, '.server-version')
|
|
78
|
+
const pkg = require('./package.json')
|
|
77
79
|
|
|
78
|
-
// Fast path: if stable binary exists
|
|
79
|
-
// This makes npx startup near-instant when everything is healthy.
|
|
80
|
+
// Fast path: if stable binary exists, version matches, exec directly.
|
|
80
81
|
try {
|
|
81
82
|
const stat = fs.lstatSync(stableBin)
|
|
82
|
-
// Only use fast path if it's a real file (not a symlink — symlinks can break)
|
|
83
83
|
if (stat.isFile() && (stat.mode & 0o111)) {
|
|
84
|
-
//
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
84
|
+
// Check if cached binary matches current npm version
|
|
85
|
+
const cachedVersion = fs.existsSync(versionFile)
|
|
86
|
+
? fs.readFileSync(versionFile, 'utf8').trim()
|
|
87
|
+
: ''
|
|
88
|
+
if (cachedVersion === pkg.version) {
|
|
89
|
+
// Version matches — use fast path
|
|
90
|
+
const { ensureTray, ensureTeamsProxy } = require('./download')
|
|
91
|
+
ensureTray().catch(() => {})
|
|
92
|
+
ensureTeamsProxy().catch(() => {})
|
|
93
|
+
const child = spawn(stableBin, [], { stdio: 'inherit', env: process.env })
|
|
94
|
+
child.on('error', () => process.exit(1))
|
|
95
|
+
child.on('exit', (code) => process.exit(code ?? 0))
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
// Version mismatch — fall through to download new binary
|
|
99
|
+
process.stderr.write(`Updating LMCP server (${cachedVersion || '?'} → ${pkg.version})...\n`)
|
|
92
100
|
}
|
|
93
|
-
// If it's a symlink (legacy), remove it and fall through to download
|
|
94
101
|
if (stat.isSymbolicLink()) fs.unlinkSync(stableBin)
|
|
95
102
|
} catch {
|
|
96
103
|
// stat failed — binary missing, fall through to download
|
|
@@ -107,7 +114,7 @@ async function main() {
|
|
|
107
114
|
try {
|
|
108
115
|
runtime = await ensureRuntime()
|
|
109
116
|
} catch (err) {
|
|
110
|
-
process.stderr.write(`\nError al preparar el runtime de
|
|
117
|
+
process.stderr.write(`\nError al preparar el runtime de LMCP:\n${err.message}\n`)
|
|
111
118
|
process.stderr.write(`Intentá reinstalar: npx local-mcp update\n\n`)
|
|
112
119
|
process.exit(1)
|
|
113
120
|
}
|
|
@@ -121,6 +128,8 @@ async function main() {
|
|
|
121
128
|
fs.chmodSync(tmpPath, 0o755)
|
|
122
129
|
try { execFileSync('codesign', ['--force', '--sign', '-', '--identifier', 'com.local-mcp.server', tmpPath], { stdio: 'pipe' }) } catch {}
|
|
123
130
|
fs.renameSync(tmpPath, stableBin)
|
|
131
|
+
// Write version file so fast path knows when to update
|
|
132
|
+
fs.writeFileSync(versionFile, pkg.version)
|
|
124
133
|
// Also copy settings.html
|
|
125
134
|
const settingsSrc = path.join(path.dirname(binPath), 'settings.html')
|
|
126
135
|
const settingsDst = path.join(CACHE_DIR, 'settings.html')
|
|
@@ -130,7 +139,7 @@ async function main() {
|
|
|
130
139
|
// Run the binary
|
|
131
140
|
const child = spawn(binPath, [], { stdio: 'inherit', env: process.env })
|
|
132
141
|
child.on('error', (err) => {
|
|
133
|
-
process.stderr.write(`Error ejecutando
|
|
142
|
+
process.stderr.write(`Error ejecutando LMCP: ${err.message}\n`)
|
|
134
143
|
process.exit(1)
|
|
135
144
|
})
|
|
136
145
|
child.on('exit', (code) => process.exit(code ?? 0))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "local-mcp",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.15",
|
|
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
|
@@ -117,7 +117,7 @@ async function runSetup(opts = {}) {
|
|
|
117
117
|
if (refArg) process.env.LMCP_REF = refArg.split('=')[1]
|
|
118
118
|
|
|
119
119
|
console.log('\n╔══════════════════════════════════════╗')
|
|
120
|
-
console.log('║
|
|
120
|
+
console.log('║ LMCP — Setup Wizard ║')
|
|
121
121
|
console.log('╚══════════════════════════════════════╝\n')
|
|
122
122
|
|
|
123
123
|
// Pre-download binary so first launch is instant
|
|
@@ -126,7 +126,7 @@ async function runSetup(opts = {}) {
|
|
|
126
126
|
let stableArgs = NPX_ARGS
|
|
127
127
|
try {
|
|
128
128
|
const { ensureBinary, CACHE_DIR } = require('./download')
|
|
129
|
-
process.stderr.write('Downloading
|
|
129
|
+
process.stderr.write('Downloading LMCP runtime...\n')
|
|
130
130
|
const { binPath } = await ensureBinary()
|
|
131
131
|
// Copy binary to stable path (npx fast-path will exec it directly)
|
|
132
132
|
const stablePath = path.join(CACHE_DIR, 'local-mcp-server')
|
|
@@ -136,6 +136,9 @@ async function runSetup(opts = {}) {
|
|
|
136
136
|
fs.chmodSync(tmpPath, 0o755)
|
|
137
137
|
try { execFileSync('codesign', ['--force', '--sign', '-', '--identifier', 'com.local-mcp.server', tmpPath], { stdio: 'pipe' }) } catch {}
|
|
138
138
|
fs.renameSync(tmpPath, stablePath)
|
|
139
|
+
// Write version file so fast path knows when to update
|
|
140
|
+
const pkg = require('./package.json')
|
|
141
|
+
fs.writeFileSync(path.join(CACHE_DIR, '.server-version'), pkg.version)
|
|
139
142
|
const settingsSrc = path.join(path.dirname(binPath), 'settings.html')
|
|
140
143
|
const settingsDst = path.join(CACHE_DIR, 'settings.html')
|
|
141
144
|
if (fs.existsSync(settingsSrc)) fs.copyFileSync(settingsSrc, settingsDst)
|
|
@@ -198,17 +201,17 @@ async function runSetup(opts = {}) {
|
|
|
198
201
|
console.log('\n──────────────────────────────────────')
|
|
199
202
|
if (configured.length > 0) {
|
|
200
203
|
if (healthOk) {
|
|
201
|
-
console.log(`✅
|
|
204
|
+
console.log(`✅ LMCP configured for: ${configured.join(', ')}\n`)
|
|
202
205
|
console.log(' ✓ Server binary verified — 82 tools ready\n')
|
|
203
206
|
} else {
|
|
204
|
-
console.log(`⚠
|
|
207
|
+
console.log(`⚠ LMCP configured for: ${configured.join(', ')}`)
|
|
205
208
|
console.log(' Server binary could not be verified — it may still work after restart.\n')
|
|
206
209
|
}
|
|
207
210
|
console.log('┌─────────────────────────────────────────────────────┐')
|
|
208
211
|
console.log('│ NEXT STEP — This is important: │')
|
|
209
212
|
console.log('│ │')
|
|
210
213
|
console.log(`│ Quit and reopen ${configured[0].padEnd(35)}│`)
|
|
211
|
-
console.log('│
|
|
214
|
+
console.log('│ LMCP will appear automatically. │')
|
|
212
215
|
console.log('│ │')
|
|
213
216
|
console.log('│ Then try: "Summarize my unread emails" │')
|
|
214
217
|
console.log('└─────────────────────────────────────────────────────┘\n')
|
|
@@ -239,7 +242,7 @@ async function _installTray() {
|
|
|
239
242
|
const { ensureTray } = require('./download')
|
|
240
243
|
const trayApp = await ensureTray()
|
|
241
244
|
if (!trayApp) return // x64 — skip silencioso
|
|
242
|
-
console.log('\n✓ Tray installed — look for the
|
|
245
|
+
console.log('\n✓ Tray installed — look for the LMCP icon in your menu bar\n')
|
|
243
246
|
// ensureTray() ya escribió el LaunchAgent y lo cargó con RunAtLoad=true
|
|
244
247
|
// No hace falta llamar open() por separado
|
|
245
248
|
} catch (err) {
|