local-mcp 1.87.0 → 1.88.0

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 CHANGED
@@ -14,6 +14,7 @@ const { execFileSync } = require('child_process')
14
14
 
15
15
  const BACKEND_URL = 'https://office-mcp-production.up.railway.app'
16
16
  const CACHE_DIR = path.join(os.homedir(), '.local', 'share', 'local-mcp', 'bin')
17
+ const TRAY_DIR = path.join(os.homedir(), '.local', 'share', 'local-mcp', 'tray')
17
18
 
18
19
  function getArch() {
19
20
  const arch = process.arch
@@ -142,4 +143,53 @@ async function ensureRuntime() {
142
143
  return { pythonBin: binPath, serverPath: binPath, runtimeDir: versionDir, binPath }
143
144
  }
144
145
 
145
- module.exports = { ensureBinary, ensureRuntime, CACHE_DIR }
146
+ /**
147
+ * Descarga e instala el tray SwiftUI (menu bar app) para arm64.
148
+ * En x64 retorna null silenciosamente — no hay build de tray para Intel.
149
+ * @returns {Promise<string|null>} Ruta al .app instalado, o null si no aplica
150
+ */
151
+ async function ensureTray() {
152
+ // Solo arm64 — no hay build x64 del tray
153
+ if (process.arch !== 'arm64') return null
154
+
155
+ const info = await getLatestBinary()
156
+ const version = info.version
157
+ const trayApp = path.join(TRAY_DIR, 'LocalMCPTray.app')
158
+ const verFile = path.join(TRAY_DIR, '.version')
159
+
160
+ // Ya instalado y actualizado
161
+ if (fs.existsSync(trayApp) && fs.existsSync(verFile)) {
162
+ if (fs.readFileSync(verFile, 'utf8').trim() === version) return trayApp
163
+ }
164
+
165
+ const url = `https://download.local-mcp.com/local-mcp-tray-${version}-darwin-arm64.tar.gz`
166
+ process.stderr.write(`\nDescargando tray v${version}...\n`)
167
+
168
+ fs.mkdirSync(TRAY_DIR, { recursive: true })
169
+ // Limpiar versión anterior si existe
170
+ if (fs.existsSync(trayApp)) {
171
+ try { execFileSync('rm', ['-rf', trayApp], { stdio: 'pipe' }) } catch { /* ignorar */ }
172
+ }
173
+ const tarPath = path.join(TRAY_DIR, `tray-${version}.tar.gz`)
174
+
175
+ await downloadFile(url, tarPath)
176
+
177
+ process.stderr.write(` Instalando tray...\n`)
178
+ execFileSync('tar', ['-xzf', tarPath, '-C', TRAY_DIR], { stdio: 'pipe' })
179
+ fs.unlinkSync(tarPath)
180
+
181
+ if (!fs.existsSync(trayApp)) {
182
+ throw new Error(`Tray no encontrado tras extraer: ${trayApp}`)
183
+ }
184
+
185
+ // Quitar quarantine + firmar ad-hoc
186
+ try { execFileSync('xattr', ['-rd', 'com.apple.quarantine', trayApp], { stdio: 'pipe' }) } catch { /* no crítico */ }
187
+ const trayBin = path.join(trayApp, 'Contents', 'MacOS', 'LocalMCPTray')
188
+ try { execFileSync('codesign', ['--force', '--sign', '-', trayBin], { stdio: 'pipe' }) } catch { /* no crítico */ }
189
+
190
+ fs.writeFileSync(verFile, version, 'utf8')
191
+ process.stderr.write(` Tray instalado en ${trayApp}\n`)
192
+ return trayApp
193
+ }
194
+
195
+ module.exports = { ensureBinary, ensureRuntime, ensureTray, CACHE_DIR, TRAY_DIR }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "local-mcp",
3
- "version": "1.87.0",
3
+ "version": "1.88.0",
4
4
  "description": "MCP server for macOS \u2014 connect Claude Desktop, Cursor, Windsurf to Mail, Calendar, Contacts, Teams, OneDrive. Privacy-first: all data stays on your Mac.",
5
5
  "main": "index.js",
6
6
  "bin": {
package/postinstall.js CHANGED
@@ -17,8 +17,7 @@ if (process.platform !== 'darwin') {
17
17
  const { runSetup } = require('./setup')
18
18
 
19
19
  runSetup({ all: true }).catch(err => {
20
- // No fallar la instalación si el setup falla
21
- process.stderr.write(`\nAviso: setup automático falló: ${err.message}\n`)
22
- process.stderr.write('Ejecutá "local-mcp setup" manualmente para configurar tus clientes.\n\n')
20
+ process.stderr.write(`\nSetup failed: ${err.message}\n`)
21
+ process.stderr.write('Run manually: npx -y local-mcp@latest setup\n\n')
23
22
  process.exit(0)
24
23
  })
package/setup.js CHANGED
@@ -172,13 +172,30 @@ async function runSetup(opts = {}) {
172
172
 
173
173
  console.log('MCP config written:')
174
174
  console.log(JSON.stringify({ mcpServers: { 'local-mcp': { command: NPX_COMMAND, args: NPX_ARGS } } }, null, 2))
175
- console.log('\nOptional — full app with tray menu bar:')
176
- console.log(' curl -fsSL https://local-mcp.com/install | bash\n')
175
+
176
+ // Instalar y lanzar el tray (menu bar app) arm64 only, non-fatal
177
+ await _installTray()
177
178
 
178
179
  // Ping de tracking (fire-and-forget, no bloquea)
179
180
  _pingInstall(configured, opts.method || 'setup')
180
181
  }
181
182
 
183
+ async function _installTray() {
184
+ try {
185
+ const { ensureTray } = require('./download')
186
+ const trayApp = await ensureTray()
187
+ if (!trayApp) return // x64 o error silencioso
188
+ console.log('\n✓ Tray installed (menu bar icon)')
189
+ // Lanzar en background — no bloquea, el proceso se detacha
190
+ const { spawn } = require('child_process')
191
+ spawn('open', [trayApp], { detached: true, stdio: 'ignore' }).unref()
192
+ console.log('✓ Tray launched — look for the Local MCP icon in your menu bar\n')
193
+ } catch (err) {
194
+ // No fatal — el servidor MCP funciona igual sin el tray
195
+ process.stderr.write(` (Tray not available: ${err.message})\n\n`)
196
+ }
197
+ }
198
+
182
199
  function _getMachineId() {
183
200
  try {
184
201
  // Try reading from macOS Keychain (same as server.py)