local-mcp 2.6.0 → 2.8.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/index.js +40 -42
- package/package.json +1 -1
- package/setup.js +16 -12
package/index.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* npx local-mcp status → muestra estado del servidor local
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
const { spawn } = require('child_process')
|
|
14
|
+
const { spawn, execFileSync, execSync } = require('child_process')
|
|
15
15
|
const path = require('path')
|
|
16
16
|
const os = require('os')
|
|
17
17
|
const fs = require('fs')
|
|
@@ -71,11 +71,32 @@ async function main() {
|
|
|
71
71
|
return
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
// Modo default: stdio MCP server
|
|
74
|
+
// ── Modo default: stdio MCP server ──────────────────────────────────────────
|
|
75
|
+
const { CACHE_DIR } = require('./download')
|
|
76
|
+
const stableBin = path.join(CACHE_DIR, 'local-mcp-server')
|
|
77
|
+
|
|
78
|
+
// Fast path: if stable binary exists and is a real file (not a broken symlink), exec it directly.
|
|
79
|
+
// This makes npx startup near-instant when everything is healthy.
|
|
80
|
+
try {
|
|
81
|
+
const stat = fs.lstatSync(stableBin)
|
|
82
|
+
// Only use fast path if it's a real file (not a symlink — symlinks can break)
|
|
83
|
+
if (stat.isFile() && (stat.mode & 0o111)) {
|
|
84
|
+
const child = spawn(stableBin, [], { stdio: 'inherit', env: process.env })
|
|
85
|
+
child.on('error', () => process.exit(1))
|
|
86
|
+
child.on('exit', (code) => process.exit(code ?? 0))
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
// If it's a symlink (legacy), remove it and fall through to download
|
|
90
|
+
if (stat.isSymbolicLink()) fs.unlinkSync(stableBin)
|
|
91
|
+
} catch {
|
|
92
|
+
// stat failed — binary missing, fall through to download
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Slow path: download/repair binary
|
|
75
96
|
const { ensureRuntime, ensureTray } = require('./download')
|
|
76
97
|
|
|
77
|
-
// Actualizar tray en background
|
|
78
|
-
ensureTray().catch(() => {
|
|
98
|
+
// Actualizar tray en background
|
|
99
|
+
ensureTray().catch(() => {})
|
|
79
100
|
|
|
80
101
|
let runtime
|
|
81
102
|
try {
|
|
@@ -88,49 +109,26 @@ async function main() {
|
|
|
88
109
|
|
|
89
110
|
const { binPath } = runtime
|
|
90
111
|
|
|
91
|
-
//
|
|
92
|
-
// El binario corre como hijo de node → TCC muestra "node" en los diálogos de
|
|
93
|
-
// permisos (Messages, Mail, etc.) en lugar de "local-mcp-server".
|
|
94
|
-
// Solución: crear un symlink estable y apuntar Claude Desktop directamente
|
|
95
|
-
// al binario. En la próxima sesión, Claude Desktop llama al binario sin node
|
|
96
|
-
// como padre → TCC ve "com.local-mcp.server" directamente.
|
|
97
|
-
const { CACHE_DIR } = require('./download')
|
|
98
|
-
const stableLink = path.join(CACHE_DIR, 'local-mcp-server')
|
|
112
|
+
// Copy binary to stable path (survives version cleanup)
|
|
99
113
|
try {
|
|
100
|
-
|
|
101
|
-
fs.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
process.stderr.write(`\n✓ Config de Claude Desktop actualizado.\n`)
|
|
114
|
-
process.stderr.write(` Reiniciá Claude Desktop para que Pilot MCP corra sin node como padre.\n`)
|
|
115
|
-
process.stderr.write(` (Esto elimina los diálogos de permisos repetidos.)\n\n`)
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
} catch { /* no crítico — seguimos con spawn normal */ }
|
|
119
|
-
|
|
120
|
-
// Spawn para esta sesión (siguiente sesión ya será binario directo)
|
|
121
|
-
const child = spawn(binPath, [], {
|
|
122
|
-
stdio: 'inherit',
|
|
123
|
-
env: process.env,
|
|
124
|
-
})
|
|
125
|
-
|
|
114
|
+
const tmpPath = stableBin + '.tmp'
|
|
115
|
+
fs.copyFileSync(binPath, tmpPath)
|
|
116
|
+
fs.chmodSync(tmpPath, 0o755)
|
|
117
|
+
try { execFileSync('codesign', ['--force', '--sign', '-', '--identifier', 'com.local-mcp.server', tmpPath], { stdio: 'pipe' }) } catch {}
|
|
118
|
+
fs.renameSync(tmpPath, stableBin)
|
|
119
|
+
// Also copy settings.html
|
|
120
|
+
const settingsSrc = path.join(path.dirname(binPath), 'settings.html')
|
|
121
|
+
const settingsDst = path.join(CACHE_DIR, 'settings.html')
|
|
122
|
+
if (fs.existsSync(settingsSrc)) fs.copyFileSync(settingsSrc, settingsDst)
|
|
123
|
+
} catch {}
|
|
124
|
+
|
|
125
|
+
// Run the binary
|
|
126
|
+
const child = spawn(binPath, [], { stdio: 'inherit', env: process.env })
|
|
126
127
|
child.on('error', (err) => {
|
|
127
128
|
process.stderr.write(`Error ejecutando Pilot MCP: ${err.message}\n`)
|
|
128
129
|
process.exit(1)
|
|
129
130
|
})
|
|
130
|
-
|
|
131
|
-
child.on('exit', (code) => {
|
|
132
|
-
process.exit(code ?? 0)
|
|
133
|
-
})
|
|
131
|
+
child.on('exit', (code) => process.exit(code ?? 0))
|
|
134
132
|
}
|
|
135
133
|
|
|
136
134
|
main().catch(err => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "local-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.0",
|
|
4
4
|
"description": "Pilot MCP — 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
|
@@ -112,28 +112,32 @@ async function runSetup(opts = {}) {
|
|
|
112
112
|
console.log('║ Pilot MCP — Setup Wizard ║')
|
|
113
113
|
console.log('╚══════════════════════════════════════╝\n')
|
|
114
114
|
|
|
115
|
-
//
|
|
116
|
-
//
|
|
115
|
+
// Pre-download binary so first launch is instant
|
|
116
|
+
// All clients use npx as launcher (self-healing if binary is missing/broken)
|
|
117
117
|
let stableCommand = NPX_COMMAND
|
|
118
118
|
let stableArgs = NPX_ARGS
|
|
119
119
|
try {
|
|
120
120
|
const { ensureBinary, CACHE_DIR } = require('./download')
|
|
121
121
|
process.stderr.write('Downloading Pilot MCP runtime...\n')
|
|
122
122
|
const { binPath } = await ensureBinary()
|
|
123
|
-
//
|
|
124
|
-
const
|
|
123
|
+
// Copy binary to stable path (npx fast-path will exec it directly)
|
|
124
|
+
const stablePath = path.join(CACHE_DIR, 'local-mcp-server')
|
|
125
125
|
try {
|
|
126
|
-
|
|
127
|
-
fs.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
126
|
+
const tmpPath = stablePath + '.tmp'
|
|
127
|
+
fs.copyFileSync(binPath, tmpPath)
|
|
128
|
+
fs.chmodSync(tmpPath, 0o755)
|
|
129
|
+
try { execFileSync('codesign', ['--force', '--sign', '-', '--identifier', 'com.local-mcp.server', tmpPath], { stdio: 'pipe' }) } catch {}
|
|
130
|
+
fs.renameSync(tmpPath, stablePath)
|
|
131
|
+
const settingsSrc = path.join(path.dirname(binPath), 'settings.html')
|
|
132
|
+
const settingsDst = path.join(CACHE_DIR, 'settings.html')
|
|
133
|
+
if (fs.existsSync(settingsSrc)) fs.copyFileSync(settingsSrc, settingsDst)
|
|
134
|
+
} catch {}
|
|
135
|
+
process.stderr.write('✓ Runtime ready\n\n')
|
|
134
136
|
} catch (err) {
|
|
135
137
|
process.stderr.write(` (Runtime download failed, will download on first run: ${err.message})\n\n`)
|
|
136
138
|
}
|
|
139
|
+
// Always use npx as the command — it has a fast-path that execs the binary directly
|
|
140
|
+
// but can self-heal if the binary is missing or broken
|
|
137
141
|
|
|
138
142
|
// Detectar clientes
|
|
139
143
|
const detected = CLIENTS.filter(c => c.detect())
|