local-mcp 3.0.370 → 3.0.372
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/README.md +2 -2
- package/download.js +49 -7
- package/index.js +17 -5
- package/package.json +4 -2
- package/postinstall.js +0 -5
- package/setup.js +5 -18
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Local MCP
|
|
2
2
|
|
|
3
|
-
> **The only Mac MCP you can use from ChatGPT & Claude.ai on the web** — plus
|
|
3
|
+
> **The only Mac MCP you can use from ChatGPT & Claude.ai on the web** — plus 215+ local tools for Claude Desktop, Cursor, Windsurf, VS Code & Zed. Connect any AI to Mail, Calendar, Contacts, iMessage, Teams, Slack, WhatsApp, Signal, OneDrive, Google Drive, Microsoft 365, Notes, Reminders, OmniFocus, Safari, Chrome, Word/Excel/PowerPoint and more. 100% local, no API keys, free — your data never leaves your machine.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/local-mcp)
|
|
6
6
|
[](https://local-mcp.com?ref=npm)
|
|
@@ -74,7 +74,7 @@ LMCP runs a native MCP server that bridges your Mac apps to any AI client:
|
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
|
|
77
|
-
##
|
|
77
|
+
## Tool catalog (macOS)
|
|
78
78
|
|
|
79
79
|
Email (12): `list_accounts` `list_email_accounts` `list_emails` `read_email` `send_email` `reply_email` `create_draft` `search_emails` `move_email` `save_attachment` `create_email_folder` `list_email_folders`
|
|
80
80
|
|
package/download.js
CHANGED
|
@@ -18,6 +18,15 @@ function extractTar(tarPath, destDir) {
|
|
|
18
18
|
const tarBin = process.platform === 'win32'
|
|
19
19
|
? path.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'tar.exe')
|
|
20
20
|
: 'tar'
|
|
21
|
+
// Windows 10 1803+ ships bsdtar at System32\tar.exe. On an older/stripped Windows
|
|
22
|
+
// it's absent — fail with a clear cause instead of a bare execFileSync ENOENT that
|
|
23
|
+
// the caller would otherwise mask as "not yet available" (#1256).
|
|
24
|
+
if (process.platform === 'win32' && !fs.existsSync(tarBin)) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`tar.exe not found at ${tarBin} — Windows 10 1803+ (with built-in bsdtar) is ` +
|
|
27
|
+
`required to unpack the LMCP server.`
|
|
28
|
+
)
|
|
29
|
+
}
|
|
21
30
|
execFileSync(tarBin, ['-xzf', tarPath, '-C', destDir], { stdio: 'pipe' })
|
|
22
31
|
}
|
|
23
32
|
|
|
@@ -122,7 +131,7 @@ async function getLatestBinary() {
|
|
|
122
131
|
/**
|
|
123
132
|
* Descarga un archivo con barra de progreso.
|
|
124
133
|
*/
|
|
125
|
-
|
|
134
|
+
function downloadOnce(url, destPath) {
|
|
126
135
|
return new Promise((resolve, reject) => {
|
|
127
136
|
const file = fs.createWriteStream(destPath)
|
|
128
137
|
const proto = url.startsWith('https') ? https : http
|
|
@@ -164,6 +173,27 @@ async function downloadFile(url, destPath) {
|
|
|
164
173
|
})
|
|
165
174
|
}
|
|
166
175
|
|
|
176
|
+
// Retry transient download failures (timeouts, resets, 5xx). A 4xx is permanent —
|
|
177
|
+
// a missing/forbidden artifact won't appear on a retry, so fail fast and let the
|
|
178
|
+
// caller decide whether that means "not yet published". Backoff grows per attempt.
|
|
179
|
+
async function downloadFile(url, destPath) {
|
|
180
|
+
const maxAttempts = 3
|
|
181
|
+
let lastErr
|
|
182
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
183
|
+
try {
|
|
184
|
+
return await downloadOnce(url, destPath)
|
|
185
|
+
} catch (err) {
|
|
186
|
+
lastErr = err
|
|
187
|
+
if (/HTTP 4\d\d/.test(err.message)) throw err // permanent, don't retry
|
|
188
|
+
if (attempt < maxAttempts) {
|
|
189
|
+
process.stderr.write(`\n Download failed (${err.message}) — retrying (${attempt}/${maxAttempts - 1})...\n`)
|
|
190
|
+
await new Promise(r => setTimeout(r, 1000 * attempt))
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
throw lastErr
|
|
195
|
+
}
|
|
196
|
+
|
|
167
197
|
/**
|
|
168
198
|
* Asegura que el binario esté descargado y listo.
|
|
169
199
|
* @returns {Promise<{binPath: string}>}
|
|
@@ -233,11 +263,20 @@ async function ensureBinary() {
|
|
|
233
263
|
extractTar(tarPath, CACHE_DIR)
|
|
234
264
|
fs.unlinkSync(tarPath)
|
|
235
265
|
} catch (err) {
|
|
236
|
-
// Go binary not yet published for this version — fall back to message
|
|
237
266
|
try { fs.unlinkSync(tarPath) } catch {}
|
|
267
|
+
// Only a 404 means the artifact for this version/arch genuinely isn't published.
|
|
268
|
+
// Every other failure (network, missing tar.exe, disk) is an environment problem —
|
|
269
|
+
// surface it verbatim so it's diagnosable. Masking ALL failures as "in preview" sent
|
|
270
|
+
// us chasing a backend version-alignment ghost that didn't exist (#1256): the artifact
|
|
271
|
+
// was published, valid and hash-correct; the client just failed to fetch/unpack it.
|
|
272
|
+
if (/HTTP 404/.test(err.message)) {
|
|
273
|
+
throw new Error(
|
|
274
|
+
`LMCP ${platformVersion} is not yet available for ${arch}.\n` +
|
|
275
|
+
`The Windows/Linux Go server is in preview — check https://local-mcp.com for updates.`
|
|
276
|
+
)
|
|
277
|
+
}
|
|
238
278
|
throw new Error(
|
|
239
|
-
`LMCP ${platformVersion}
|
|
240
|
-
`The Windows/Linux Go server is in preview — check https://local-mcp.com for updates.`
|
|
279
|
+
`Failed to install LMCP ${platformVersion} (${arch}) from ${url}:\n ${err.message}`
|
|
241
280
|
)
|
|
242
281
|
}
|
|
243
282
|
|
|
@@ -360,9 +399,12 @@ async function ensureTeamsProxy() {
|
|
|
360
399
|
* @returns {Promise<string|null>} Ruta al .app instalado, o null si falla
|
|
361
400
|
*/
|
|
362
401
|
async function ensureTray() {
|
|
363
|
-
// Windows:
|
|
364
|
-
|
|
365
|
-
|
|
402
|
+
// Windows/Linux: the tray + background daemon are installed by the native
|
|
403
|
+
// installer (LMCP-Setup.exe on Windows; the systemd unit on Linux), NOT by npm.
|
|
404
|
+
// The npm package is a stdio proxy for MCP hosts, so there is no tray to fetch
|
|
405
|
+
// here — no-op instead of downloading a lmcp-tray binary.
|
|
406
|
+
if (process.platform !== 'darwin') {
|
|
407
|
+
return null
|
|
366
408
|
}
|
|
367
409
|
|
|
368
410
|
// Respect explicit uninstall — don't resurrect tray if user ran `uninstall`.
|
package/index.js
CHANGED
|
@@ -51,10 +51,12 @@ function clearUninstallSentinels() {
|
|
|
51
51
|
for (const p of uninstallSentinelPaths()) { try { fs.unlinkSync(p) } catch {} }
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
// Platform support: macOS
|
|
55
|
-
|
|
54
|
+
// Platform support: macOS (Swift tray + embedded server), Windows & Linux
|
|
55
|
+
// (go-server standalone binary downloaded from R2). Re-enabled for the
|
|
56
|
+
// Windows/Linux public re-launch — the waitlist gate is retired.
|
|
57
|
+
const SUPPORTED_PLATFORMS = ['darwin', 'win32', 'linux']
|
|
56
58
|
if (!SUPPORTED_PLATFORMS.includes(process.platform)) {
|
|
57
|
-
console.error(`LMCP
|
|
59
|
+
console.error(`LMCP supports macOS, Windows and Linux. Your platform (${process.platform}) is not supported yet — see https://local-mcp.com`)
|
|
58
60
|
process.exit(1)
|
|
59
61
|
}
|
|
60
62
|
|
|
@@ -222,7 +224,12 @@ async function main() {
|
|
|
222
224
|
|
|
223
225
|
// ── Modo default: stdio MCP server ──────────────────────────────────────────
|
|
224
226
|
const { CACHE_DIR } = require('./download')
|
|
225
|
-
|
|
227
|
+
// macOS ships the Swift `local-mcp-server` (standalone fallback to the embedded
|
|
228
|
+
// tray server); Windows/Linux ship the go-server `lmcp-server` binary that
|
|
229
|
+
// download.js writes to CACHE_DIR. Keep this name in sync with download.js.
|
|
230
|
+
const binName = process.platform === 'darwin'
|
|
231
|
+
? 'local-mcp-server'
|
|
232
|
+
: (process.platform === 'win32' ? 'lmcp-server.exe' : 'lmcp-server')
|
|
226
233
|
const stableBin = path.join(CACHE_DIR, binName)
|
|
227
234
|
const versionFile = path.join(CACHE_DIR, '.server-version')
|
|
228
235
|
const pkg = require('./package.json')
|
|
@@ -365,7 +372,12 @@ async function main() {
|
|
|
365
372
|
// because stale npx cache had old pkg.version and triggered the slow path unnecessarily.
|
|
366
373
|
try {
|
|
367
374
|
const stat = fs.lstatSync(stableBin)
|
|
368
|
-
|
|
375
|
+
// Windows .exe files carry no Unix exec bit — Node's fs reports mode 0o666 —
|
|
376
|
+
// so the `& 0o111` gate is always false there, which forced EVERY spawn onto
|
|
377
|
+
// the slow path (a /runtime/latest network round-trip before launch, and a
|
|
378
|
+
// hard failure when offline despite a valid cached binary). Only require the
|
|
379
|
+
// exec bit off-Windows, where it's meaningful.
|
|
380
|
+
if (stat.isFile() && (process.platform === 'win32' || (stat.mode & 0o111))) {
|
|
369
381
|
const cachedVersion = fs.existsSync(versionFile)
|
|
370
382
|
? fs.readFileSync(versionFile, 'utf8').trim()
|
|
371
383
|
: ''
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "local-mcp",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.372",
|
|
4
4
|
"description": "Let ChatGPT, Claude, Cursor & any MCP client actually use your Mac — read & reply to email, manage your calendar, text over iMessage, find files, work with Teams, Slack & Office. On your Mac, no API keys, free.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -20,7 +20,9 @@
|
|
|
20
20
|
"node": ">=18"
|
|
21
21
|
},
|
|
22
22
|
"os": [
|
|
23
|
-
"darwin"
|
|
23
|
+
"darwin",
|
|
24
|
+
"linux",
|
|
25
|
+
"win32"
|
|
24
26
|
],
|
|
25
27
|
"keywords": [
|
|
26
28
|
"mcp",
|
package/postinstall.js
CHANGED
|
@@ -9,11 +9,6 @@ if (!process.env.npm_config_global || process.env.CI || process.env.SKIP_SETUP)
|
|
|
9
9
|
process.exit(0)
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
// Solo macOS
|
|
13
|
-
if (process.platform !== 'darwin') {
|
|
14
|
-
process.exit(0)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
12
|
const { runSetup } = require('./setup')
|
|
18
13
|
|
|
19
14
|
runSetup({ all: true }).catch(err => {
|
package/setup.js
CHANGED
|
@@ -331,23 +331,10 @@ function injectMcpConfig(client, command = NPX_COMMAND, args = NPX_ARGS) {
|
|
|
331
331
|
// ── Main ──────────────────────────────────────────────────────────────────────
|
|
332
332
|
|
|
333
333
|
async function runSetup(opts = {}) {
|
|
334
|
-
// macOS
|
|
335
|
-
//
|
|
336
|
-
//
|
|
337
|
-
//
|
|
338
|
-
// Windows R2 binaries stay so the existing fleet keeps auto-updating.)
|
|
339
|
-
if (process.platform !== 'darwin') {
|
|
340
|
-
const osName = process.platform === 'win32' ? 'Windows' : process.platform === 'linux' ? 'Linux' : process.platform
|
|
341
|
-
console.log(`\n LMCP is macOS-only right now — ${osName} isn't supported yet.`)
|
|
342
|
-
console.log(' Join the waitlist to be notified when it ships: https://local-mcp.com\n')
|
|
343
|
-
try { // best-effort: record the gated attempt so we can size non-mac demand
|
|
344
|
-
const https = require('https')
|
|
345
|
-
const req = https.request({ hostname: BACKEND_HOST, path: '/install/started/npm-gated-' + process.platform, method: 'POST', timeout: 2500 })
|
|
346
|
-
req.on('error', () => {}); req.end()
|
|
347
|
-
} catch {}
|
|
348
|
-
return
|
|
349
|
-
}
|
|
350
|
-
|
|
334
|
+
// Cross-platform: macOS configures the Swift tray + embedded server; Windows/Linux
|
|
335
|
+
// download the go-server standalone binary (download.js) and write the MCP client
|
|
336
|
+
// config (the config writer already handles Windows paths). The Mac-only waitlist
|
|
337
|
+
// gate was retired for the Windows/Linux public re-launch.
|
|
351
338
|
const forceAll = opts.all || process.argv.includes('--all')
|
|
352
339
|
const refArg = process.argv.find(a => a.startsWith('--ref='))
|
|
353
340
|
if (refArg) process.env.LMCP_REF = refArg.split('=')[1]
|
|
@@ -584,7 +571,7 @@ async function runSetup(opts = {}) {
|
|
|
584
571
|
if (configured.length > 0) {
|
|
585
572
|
if (healthOk) {
|
|
586
573
|
console.log(`✅ LMCP configured for: ${configured.join(', ')}\n`)
|
|
587
|
-
console.log(' ✓ Server binary verified —
|
|
574
|
+
console.log(' ✓ Server binary verified — 215+ tools ready\n')
|
|
588
575
|
} else {
|
|
589
576
|
console.log(`⚠ LMCP configured for: ${configured.join(', ')}`)
|
|
590
577
|
console.log(' Server binary could not be verified — it may still work after restart.\n')
|