local-mcp 3.0.139 → 3.0.140
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/package.json +1 -1
- package/setup.js +68 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "local-mcp",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.140",
|
|
4
4
|
"description": "LMCP — 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
|
@@ -34,6 +34,19 @@ function _resolveNpxPath() {
|
|
|
34
34
|
// BEFORE Node loads our code (e.g. old nvm default in Claude Desktop's PATH).
|
|
35
35
|
// Returns the path to the launcher, or null if writing fails.
|
|
36
36
|
function _writeLaunchScript(npxAbsPath, cacheDir) {
|
|
37
|
+
// On Windows, don't write a bash launch script — use npx directly
|
|
38
|
+
if (_IS_WIN) {
|
|
39
|
+
try {
|
|
40
|
+
// Write a .cmd wrapper that Claude Desktop can execute
|
|
41
|
+
fs.mkdirSync(cacheDir, { recursive: true })
|
|
42
|
+
const cmdPath = path.join(cacheDir, 'lmcp-launch.cmd')
|
|
43
|
+
const script = `@echo off\r\n"${npxAbsPath}" -y local-mcp@latest %*\r\n`
|
|
44
|
+
fs.writeFileSync(cmdPath, script)
|
|
45
|
+
return cmdPath
|
|
46
|
+
} catch {
|
|
47
|
+
return null
|
|
48
|
+
}
|
|
49
|
+
}
|
|
37
50
|
try {
|
|
38
51
|
fs.mkdirSync(cacheDir, { recursive: true })
|
|
39
52
|
const launcherPath = path.join(cacheDir, 'lmcp-launch.sh')
|
|
@@ -71,13 +84,49 @@ const _IS_WIN = process.platform === 'win32'
|
|
|
71
84
|
const _IS_MAC = process.platform === 'darwin'
|
|
72
85
|
const _APPDATA = process.env.APPDATA || path.join(HOME, 'AppData', 'Roaming')
|
|
73
86
|
|
|
87
|
+
// Windows MSIX (Microsoft Store / WinGet) installs read config from a
|
|
88
|
+
// virtualized path inside %LOCALAPPDATA%\Packages\Claude_*\LocalCache\Roaming\Claude.
|
|
89
|
+
// The non-MSIX (.exe) install reads from %APPDATA%\Claude.
|
|
90
|
+
// We detect which one exists and write to both if needed.
|
|
91
|
+
function _findMsixClaudePath() {
|
|
92
|
+
if (!_IS_WIN) return null
|
|
93
|
+
const localAppData = process.env.LOCALAPPDATA || path.join(HOME, 'AppData', 'Local')
|
|
94
|
+
const packagesDir = path.join(localAppData, 'Packages')
|
|
95
|
+
try {
|
|
96
|
+
const entries = fs.readdirSync(packagesDir)
|
|
97
|
+
const claudePkg = entries.find(e => e.startsWith('Claude_'))
|
|
98
|
+
if (claudePkg) {
|
|
99
|
+
return path.join(packagesDir, claudePkg, 'LocalCache', 'Roaming', 'Claude', 'claude_desktop_config.json')
|
|
100
|
+
}
|
|
101
|
+
} catch {}
|
|
102
|
+
return null
|
|
103
|
+
}
|
|
104
|
+
|
|
74
105
|
function _claudeDesktopPath() {
|
|
75
|
-
if (_IS_WIN)
|
|
106
|
+
if (_IS_WIN) {
|
|
107
|
+
// Prefer MSIX path if the package exists
|
|
108
|
+
const msix = _findMsixClaudePath()
|
|
109
|
+
if (msix) return msix
|
|
110
|
+
return path.join(_APPDATA, 'Claude', 'claude_desktop_config.json')
|
|
111
|
+
}
|
|
76
112
|
if (_IS_MAC) return path.join(HOME, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json')
|
|
77
113
|
return path.join(HOME, '.config', 'Claude', 'claude_desktop_config.json')
|
|
78
114
|
}
|
|
79
115
|
|
|
116
|
+
// All paths where we should write the config (MSIX + non-MSIX on Windows)
|
|
117
|
+
function _claudeDesktopAllPaths() {
|
|
118
|
+
if (!_IS_WIN) return [_claudeDesktopPath()]
|
|
119
|
+
const paths = [path.join(_APPDATA, 'Claude', 'claude_desktop_config.json')]
|
|
120
|
+
const msix = _findMsixClaudePath()
|
|
121
|
+
if (msix && !paths.includes(msix)) paths.push(msix)
|
|
122
|
+
return paths
|
|
123
|
+
}
|
|
124
|
+
|
|
80
125
|
function _claudeDesktopDetect() {
|
|
126
|
+
if (_IS_WIN) {
|
|
127
|
+
// Check both MSIX and non-MSIX paths
|
|
128
|
+
return _claudeDesktopAllPaths().some(p => fs.existsSync(path.dirname(p)))
|
|
129
|
+
}
|
|
81
130
|
return fs.existsSync(path.dirname(_claudeDesktopPath()))
|
|
82
131
|
}
|
|
83
132
|
|
|
@@ -221,6 +270,11 @@ function _atomicWriteConfig(filePath, data) {
|
|
|
221
270
|
// Never overwrites a file whose JSON cannot be parsed.
|
|
222
271
|
|
|
223
272
|
function injectMcpConfig(client, command = NPX_COMMAND, args = NPX_ARGS) {
|
|
273
|
+
// On Windows, Claude Desktop needs cmd /c wrapper to find npx
|
|
274
|
+
if (_IS_WIN && client.id === 'claude-desktop') {
|
|
275
|
+
command = 'cmd'
|
|
276
|
+
args = ['/c', 'npx', '-y', 'local-mcp@latest']
|
|
277
|
+
}
|
|
224
278
|
// 1. Read existing config safely
|
|
225
279
|
const read = _safeReadConfig(client.cfgPath)
|
|
226
280
|
if (read.hadParseError) {
|
|
@@ -253,7 +307,14 @@ function injectMcpConfig(client, command = NPX_COMMAND, args = NPX_ARGS) {
|
|
|
253
307
|
}
|
|
254
308
|
|
|
255
309
|
// 3. Atomic write + verify
|
|
256
|
-
|
|
310
|
+
// On Windows, Claude Desktop MSIX reads from a different path than the .exe install.
|
|
311
|
+
// Write to all known paths so both install types work.
|
|
312
|
+
const allPaths = (client.id === 'claude-desktop' && _IS_WIN) ? _claudeDesktopAllPaths() : [client.cfgPath]
|
|
313
|
+
let write = { ok: false, error: 'no paths' }
|
|
314
|
+
for (const p of allPaths) {
|
|
315
|
+
fs.mkdirSync(path.dirname(p), { recursive: true })
|
|
316
|
+
write = _atomicWriteConfig(p, cfg)
|
|
317
|
+
}
|
|
257
318
|
return {
|
|
258
319
|
ok: write.ok,
|
|
259
320
|
stage: write.ok ? 'config_write' : 'config_write_failed',
|
|
@@ -530,7 +591,7 @@ async function runSetup(opts = {}) {
|
|
|
530
591
|
console.log('┌─────────────────────────────────────────────────────┐')
|
|
531
592
|
console.log('│ CURSOR — activate in 3 steps: │')
|
|
532
593
|
console.log('│ │')
|
|
533
|
-
console.log(
|
|
594
|
+
console.log(`│ 1. Quit Cursor completely (${_IS_WIN ? 'Alt+F4' : 'Cmd+Q'})${_IS_WIN ? ' ' : ' '}│`)
|
|
534
595
|
console.log('│ 2. Reopen Cursor │')
|
|
535
596
|
console.log('│ 3. Cursor Settings (⚙) → MCP → find "local-mcp" │')
|
|
536
597
|
console.log('│ → toggle it ON │')
|
|
@@ -547,7 +608,8 @@ async function runSetup(opts = {}) {
|
|
|
547
608
|
console.log('┌─────────────────────────────────────────────────────┐')
|
|
548
609
|
console.log('│ NEXT STEP — restart to activate: │')
|
|
549
610
|
console.log('│ │')
|
|
550
|
-
|
|
611
|
+
const quitKey = _IS_WIN ? 'Alt+F4' : 'Cmd+Q'
|
|
612
|
+
console.log(`│ 1. Quit ${primaryClient} completely (${quitKey})${''.padEnd(Math.max(0, 28 - primaryClient.length - quitKey.length))}│`)
|
|
551
613
|
console.log(`│ 2. Reopen ${primaryClient.padEnd(41)}│`)
|
|
552
614
|
console.log('│ │')
|
|
553
615
|
console.log('│ Then try: "Summarize my unread emails" │')
|
|
@@ -628,15 +690,14 @@ async function _installSlackProxy() {
|
|
|
628
690
|
}
|
|
629
691
|
|
|
630
692
|
async function _installTray() {
|
|
693
|
+
// Tray is macOS-only — skip on Windows/Linux
|
|
694
|
+
if (_IS_WIN || process.platform === 'linux') return
|
|
631
695
|
try {
|
|
632
696
|
const { ensureTray } = require('./download')
|
|
633
697
|
const trayApp = await ensureTray()
|
|
634
698
|
if (!trayApp) return // x64 — skip silencioso
|
|
635
699
|
console.log('\n✓ Tray installed — look for the LMCP icon in your menu bar\n')
|
|
636
|
-
// ensureTray() ya escribió el LaunchAgent y lo cargó con RunAtLoad=true
|
|
637
|
-
// No hace falta llamar open() por separado
|
|
638
700
|
} catch (err) {
|
|
639
|
-
// No fatal — el servidor MCP funciona igual sin el tray
|
|
640
701
|
process.stderr.write(` (Tray not available: ${err.message})\n\n`)
|
|
641
702
|
}
|
|
642
703
|
}
|