local-mcp 1.87.0 → 1.89.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 +83 -1
- package/package.json +1 -1
- package/postinstall.js +2 -3
- package/setup.js +17 -2
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,85 @@ async function ensureRuntime() {
|
|
|
142
143
|
return { pythonBin: binPath, serverPath: binPath, runtimeDir: versionDir, binPath }
|
|
143
144
|
}
|
|
144
145
|
|
|
145
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Descarga e instala el tray SwiftUI (menu bar app) — universal binary (arm64 + Intel).
|
|
148
|
+
* @returns {Promise<string|null>} Ruta al .app instalado, o null si falla
|
|
149
|
+
*/
|
|
150
|
+
async function ensureTray() {
|
|
151
|
+
|
|
152
|
+
const info = await getLatestBinary()
|
|
153
|
+
const version = info.version
|
|
154
|
+
const trayApp = path.join(TRAY_DIR, 'LocalMCPTray.app')
|
|
155
|
+
const verFile = path.join(TRAY_DIR, '.version')
|
|
156
|
+
|
|
157
|
+
// Ya instalado y actualizado
|
|
158
|
+
if (fs.existsSync(trayApp) && fs.existsSync(verFile)) {
|
|
159
|
+
if (fs.readFileSync(verFile, 'utf8').trim() === version) return trayApp
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const url = `https://download.local-mcp.com/local-mcp-tray-${version}-darwin-universal.tar.gz`
|
|
163
|
+
process.stderr.write(`\nDescargando tray v${version}...\n`)
|
|
164
|
+
|
|
165
|
+
fs.mkdirSync(TRAY_DIR, { recursive: true })
|
|
166
|
+
// Limpiar versión anterior si existe
|
|
167
|
+
if (fs.existsSync(trayApp)) {
|
|
168
|
+
try { execFileSync('rm', ['-rf', trayApp], { stdio: 'pipe' }) } catch { /* ignorar */ }
|
|
169
|
+
}
|
|
170
|
+
const tarPath = path.join(TRAY_DIR, `tray-${version}.tar.gz`)
|
|
171
|
+
|
|
172
|
+
await downloadFile(url, tarPath)
|
|
173
|
+
|
|
174
|
+
process.stderr.write(` Instalando tray...\n`)
|
|
175
|
+
execFileSync('tar', ['-xzf', tarPath, '-C', TRAY_DIR], { stdio: 'pipe' })
|
|
176
|
+
fs.unlinkSync(tarPath)
|
|
177
|
+
|
|
178
|
+
if (!fs.existsSync(trayApp)) {
|
|
179
|
+
throw new Error(`Tray no encontrado tras extraer: ${trayApp}`)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Quitar quarantine + firmar ad-hoc
|
|
183
|
+
try { execFileSync('xattr', ['-rd', 'com.apple.quarantine', trayApp], { stdio: 'pipe' }) } catch { /* no crítico */ }
|
|
184
|
+
const trayBin = path.join(trayApp, 'Contents', 'MacOS', 'LocalMCPTray')
|
|
185
|
+
try { execFileSync('codesign', ['--force', '--sign', '-', trayBin], { stdio: 'pipe' }) } catch { /* no crítico */ }
|
|
186
|
+
|
|
187
|
+
fs.writeFileSync(verFile, version, 'utf8')
|
|
188
|
+
|
|
189
|
+
// LaunchAgent — auto-start en cada reboot de sesión
|
|
190
|
+
_writeTrayLaunchAgent(trayApp)
|
|
191
|
+
|
|
192
|
+
process.stderr.write(` Tray instalado en ${trayApp}\n`)
|
|
193
|
+
return trayApp
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function _writeTrayLaunchAgent(trayApp) {
|
|
197
|
+
const trayBin = path.join(trayApp, 'Contents', 'MacOS', 'LocalMCPTray')
|
|
198
|
+
const plistDir = path.join(os.homedir(), 'Library', 'LaunchAgents')
|
|
199
|
+
const plistPath = path.join(plistDir, 'com.local-mcp.tray.plist')
|
|
200
|
+
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
201
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
202
|
+
<plist version="1.0">
|
|
203
|
+
<dict>
|
|
204
|
+
<key>Label</key>
|
|
205
|
+
<string>com.local-mcp.tray</string>
|
|
206
|
+
<key>ProgramArguments</key>
|
|
207
|
+
<array>
|
|
208
|
+
<string>${trayBin}</string>
|
|
209
|
+
</array>
|
|
210
|
+
<key>RunAtLoad</key>
|
|
211
|
+
<true/>
|
|
212
|
+
<key>KeepAlive</key>
|
|
213
|
+
<false/>
|
|
214
|
+
</dict>
|
|
215
|
+
</plist>
|
|
216
|
+
`
|
|
217
|
+
try {
|
|
218
|
+
fs.mkdirSync(plistDir, { recursive: true })
|
|
219
|
+
fs.writeFileSync(plistPath, plist, 'utf8')
|
|
220
|
+
// Recargar (unload silencioso si no estaba cargado)
|
|
221
|
+
try { execFileSync('launchctl', ['unload', plistPath], { stdio: 'pipe' }) } catch {}
|
|
222
|
+
execFileSync('launchctl', ['load', plistPath], { stdio: 'pipe' })
|
|
223
|
+
// launchctl load con RunAtLoad=true arranca el proceso — no necesitamos open()
|
|
224
|
+
} catch { /* no crítico */ }
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
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.
|
|
3
|
+
"version": "1.89.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
|
-
|
|
21
|
-
process.stderr.write(
|
|
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,28 @@ 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
|
-
|
|
176
|
-
|
|
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 — skip silencioso
|
|
188
|
+
console.log('\n✓ Tray installed — look for the Local MCP icon in your menu bar\n')
|
|
189
|
+
// ensureTray() ya escribió el LaunchAgent y lo cargó con RunAtLoad=true
|
|
190
|
+
// No hace falta llamar open() por separado
|
|
191
|
+
} catch (err) {
|
|
192
|
+
// No fatal — el servidor MCP funciona igual sin el tray
|
|
193
|
+
process.stderr.write(` (Tray not available: ${err.message})\n\n`)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
182
197
|
function _getMachineId() {
|
|
183
198
|
try {
|
|
184
199
|
// Try reading from macOS Keychain (same as server.py)
|