local-mcp 3.0.112 → 3.0.114

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.
Files changed (3) hide show
  1. package/index.js +39 -35
  2. package/package.json +1 -1
  3. package/setup.js +3 -16
package/index.js CHANGED
@@ -17,39 +17,6 @@ const os = require('os')
17
17
  const fs = require('fs')
18
18
  const https = require('https')
19
19
 
20
- // Track first run / version change so analytics catch users who launch
21
- // via `npx local-mcp` without going through `setup` (manual MCP config).
22
- function _pingFirstRun(versionChanged) {
23
- try {
24
- const pkg = require('./package.json')
25
- const machineId = (() => {
26
- try {
27
- const out = execSync("system_profiler SPHardwareDataType 2>/dev/null | awk '/Hardware UUID/ { print $3 }'", { encoding: 'utf8' }).trim()
28
- return out || ''
29
- } catch { return '' }
30
- })()
31
- const data = JSON.stringify({
32
- version: pkg.version,
33
- os_version: os.release(),
34
- arch: process.arch,
35
- node_version: process.version,
36
- method: 'npx-default',
37
- machine_id: machineId,
38
- source: process.env.LMCP_SOURCE || '',
39
- ref: process.env.LMCP_REF || '',
40
- })
41
- const req = https.request({
42
- hostname: 'office-mcp-production.up.railway.app',
43
- path: '/install/npm',
44
- method: 'POST',
45
- headers: { 'Content-Type': 'application/json', 'Content-Length': data.length },
46
- timeout: 5000,
47
- })
48
- req.on('error', () => {})
49
- req.write(data)
50
- req.end()
51
- } catch { /* fire and forget */ }
52
- }
53
20
 
54
21
  // Solo macOS
55
22
  if (process.platform !== 'darwin') {
@@ -143,14 +110,51 @@ async function main() {
143
110
  const child = spawn(stableBin, [], { stdio: 'inherit', env: process.env })
144
111
  child.on('error', () => process.exit(1))
145
112
  child.on('exit', (code) => process.exit(code ?? 0))
113
+
114
+ // Background update check — fires 10s after startup, at most once per 24h.
115
+ // Covers machines where the tray is dead and Sparkle can't update the binary.
116
+ const lastCheckFile = path.join(CACHE_DIR, '.last-update-check')
117
+ function _needsUpdateCheck() {
118
+ try { return Date.now() - parseInt(fs.readFileSync(lastCheckFile, 'utf8').trim(), 10) > 86400000 } catch { return true }
119
+ }
120
+ if (_needsUpdateCheck()) {
121
+ try { fs.writeFileSync(lastCheckFile, String(Date.now())) } catch {}
122
+ const _cachedVersion = cachedVersion // capture for closure
123
+ setTimeout(() => {
124
+ const req = https.get('https://office-mcp-production.up.railway.app/runtime/latest', { timeout: 8000 }, (res) => {
125
+ let buf = ''
126
+ res.on('data', c => buf += c)
127
+ res.on('end', () => {
128
+ try {
129
+ const { version: latestVersion } = JSON.parse(buf)
130
+ if (latestVersion && !semverGte(_cachedVersion, latestVersion)) {
131
+ // New version available — download silently for next restart
132
+ const { ensureRuntime } = require('./download')
133
+ ensureRuntime().then(({ binPath, version: downloadedVersion }) => {
134
+ try {
135
+ const tmpPath = stableBin + '.tmp'
136
+ fs.copyFileSync(binPath, tmpPath)
137
+ fs.chmodSync(tmpPath, 0o755)
138
+ try { execFileSync('codesign', ['--force', '--sign', '-', '--identifier', 'com.local-mcp.server', tmpPath], { stdio: 'pipe' }) } catch {}
139
+ fs.renameSync(tmpPath, stableBin)
140
+ fs.writeFileSync(versionFile, downloadedVersion || latestVersion)
141
+ } catch {}
142
+ }).catch(() => {})
143
+ }
144
+ } catch {}
145
+ })
146
+ })
147
+ req.on('error', () => {})
148
+ req.on('timeout', () => { try { req.destroy() } catch {} })
149
+ }, 10000)
150
+ }
151
+
146
152
  return
147
153
  }
148
154
  // Cached binary is older than our npm package — download/update
149
155
  process.stderr.write(`Updating LMCP server (${cachedVersion || '?'} → ${pkg.version})...\n`)
150
- _pingFirstRun(true)
151
156
  } else {
152
157
  // No cached binary version → first run via default mode
153
- _pingFirstRun(false)
154
158
  }
155
159
  if (stat.isSymbolicLink()) fs.unlinkSync(stableBin)
156
160
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "local-mcp",
3
- "version": "3.0.112",
3
+ "version": "3.0.114",
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
@@ -327,7 +327,9 @@ async function runSetup(opts = {}) {
327
327
  } catch { /* non-fatal */ }
328
328
  }
329
329
 
330
- _pingInstall(configured, opts.method || 'setup', email)
330
+ // LMCP_METHOD lets install.sh pass 'curl' so we can distinguish it from
331
+ // a direct 'npx local-mcp setup' invocation in the analytics.
332
+ _pingInstall(configured, process.env.LMCP_METHOD || opts.method || 'npx-setup', email)
331
333
  }
332
334
 
333
335
  async function _installTeamsProxy() {
@@ -576,21 +578,6 @@ function _autoLaunchClient(configured) {
576
578
  return
577
579
  }
578
580
 
579
- // Log auto-launch event (fire-and-forget)
580
- try {
581
- const https = require('https')
582
- const data = JSON.stringify({ event: 'install_auto_launch', client: clientName })
583
- const req = https.request({
584
- hostname: BACKEND_HOST,
585
- path: '/install-event',
586
- method: 'POST',
587
- headers: { 'Content-Type': 'application/json', 'Content-Length': data.length },
588
- timeout: 5000,
589
- })
590
- req.on('error', () => {})
591
- req.write(data)
592
- req.end()
593
- } catch {}
594
581
  }
595
582
 
596
583
  module.exports = { runSetup, injectMcpConfig, CLIENTS }