local-mcp 3.0.370 → 3.0.371

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 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 271 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.
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
  [![npm](https://img.shields.io/npm/v/local-mcp?style=flat-square&label=npm)](https://www.npmjs.com/package/local-mcp)
6
6
  [![macOS](https://img.shields.io/badge/macOS-13%2B-111111?style=flat-square)](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
- ## All 271 tools (macOS)
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
- async function downloadFile(url, destPath) {
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} is not yet available for ${arch}.\n` +
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "local-mcp",
3
- "version": "3.0.370",
3
+ "version": "3.0.371",
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/setup.js CHANGED
@@ -584,7 +584,7 @@ async function runSetup(opts = {}) {
584
584
  if (configured.length > 0) {
585
585
  if (healthOk) {
586
586
  console.log(`✅ LMCP configured for: ${configured.join(', ')}\n`)
587
- console.log(' ✓ Server binary verified — 100 tools ready\n')
587
+ console.log(' ✓ Server binary verified — 215+ tools ready\n')
588
588
  } else {
589
589
  console.log(`⚠ LMCP configured for: ${configured.join(', ')}`)
590
590
  console.log(' Server binary could not be verified — it may still work after restart.\n')