@softtechai/quickmcp 1.0.13 → 1.0.14
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/quickmcp-direct-stdio.js +1 -94
package/package.json
CHANGED
package/quickmcp-direct-stdio.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const path = require('path');
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const os = require('os');
|
|
6
|
-
const net = require('net');
|
|
7
4
|
|
|
8
5
|
// Use the current working directory provided by the caller.
|
|
9
6
|
// Do not change directories; keep paths relative to this script.
|
|
@@ -44,101 +41,11 @@ const sqliteManager = new SQLiteManager();
|
|
|
44
41
|
if (process.env.QUICKMCP_ENABLE_WEB === '1') {
|
|
45
42
|
try {
|
|
46
43
|
console.error('[QuickMCP] QUICKMCP_ENABLE_WEB=1 -> starting Web UI server...');
|
|
47
|
-
//
|
|
48
|
-
const canWrite = (dir) => {
|
|
49
|
-
try { fs.accessSync(dir, fs.constants.W_OK); return true; } catch { return false; }
|
|
50
|
-
};
|
|
51
|
-
let runDir = process.cwd();
|
|
52
|
-
if (runDir === '/' || !canWrite(runDir)) {
|
|
53
|
-
const home = os.homedir() || os.tmpdir();
|
|
54
|
-
runDir = path.join(home, '.quickmcp');
|
|
55
|
-
try { fs.mkdirSync(runDir, { recursive: true }); } catch {}
|
|
56
|
-
try { process.chdir(runDir); } catch {}
|
|
57
|
-
}
|
|
58
|
-
// Prepare uploads directory and expose as env for newer builds
|
|
59
|
-
const uploadsDir = path.join(runDir, 'uploads');
|
|
60
|
-
try { fs.mkdirSync(uploadsDir, { recursive: true }); } catch {}
|
|
61
|
-
if (!process.env.QUICKMCP_UPLOAD_DIR) process.env.QUICKMCP_UPLOAD_DIR = uploadsDir;
|
|
62
|
-
|
|
63
|
-
// Acquire a simple lock so only one process owns the UI (port 3000)
|
|
64
|
-
const lockPath = path.join(runDir, 'ui-3000.lock');
|
|
65
|
-
let hasLock = false;
|
|
66
|
-
try {
|
|
67
|
-
const fd = fs.openSync(lockPath, 'wx');
|
|
68
|
-
fs.closeSync(fd);
|
|
69
|
-
hasLock = true;
|
|
70
|
-
const cleanup = () => { try { fs.unlinkSync(lockPath); } catch {} };
|
|
71
|
-
process.once('exit', cleanup);
|
|
72
|
-
process.once('SIGINT', () => { cleanup(); process.exit(0); });
|
|
73
|
-
process.once('SIGTERM', () => { cleanup(); process.exit(0); });
|
|
74
|
-
} catch (e) {
|
|
75
|
-
if (e && e.code !== 'EEXIST') {
|
|
76
|
-
console.error('[QuickMCP] UI lock error (continuing without UI):', e.message || e);
|
|
77
|
-
}
|
|
78
|
-
// Another process holds the UI lock; skip starting UI in this process
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (!hasLock) {
|
|
82
|
-
return; // do not try to start UI
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Only start Web UI if preferred port is actually free.
|
|
86
|
-
const preferredPort = parseInt(process.env.PORT || '3000', 10);
|
|
87
|
-
const probe = net.createServer();
|
|
88
|
-
probe.once('error', (err) => {
|
|
89
|
-
if (err && (err.code === 'EADDRINUSE' || err.code === 'EACCES')) {
|
|
90
|
-
// Port is busy or not permitted; skip starting Web UI to avoid crashing Claude session
|
|
91
|
-
try { fs.unlinkSync(lockPath); } catch {}
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
// For other errors, still try starting server; better to attempt than silently skip for unknown cases
|
|
95
|
-
safeStartWebServer();
|
|
96
|
-
});
|
|
97
|
-
probe.once('listening', () => {
|
|
98
|
-
probe.close(() => {
|
|
99
|
-
safeStartWebServer();
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
try {
|
|
103
|
-
// Probe on IPv6 unspecified to mirror Express default, falling back to IPv4 if needed
|
|
104
|
-
probe.listen(preferredPort, '::');
|
|
105
|
-
} catch (_e) {
|
|
106
|
-
// If probing throws synchronously (rare), just skip UI
|
|
107
|
-
}
|
|
108
|
-
} catch (e) {
|
|
109
|
-
console.error('[QuickMCP] Failed to start Web UI:', e && e.message);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Start the web server but swallow a race-condition EADDRINUSE from Express listen
|
|
114
|
-
function safeStartWebServer() {
|
|
115
|
-
let handled = false;
|
|
116
|
-
const handler = (err) => {
|
|
117
|
-
if (!handled && err && err.code === 'EADDRINUSE' && err.syscall === 'listen') {
|
|
118
|
-
handled = true;
|
|
119
|
-
// Swallow this once so the STDIO server keeps running; another instance already owns :3000
|
|
120
|
-
process.removeListener('uncaughtException', handler);
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
// Not our case; restore default behavior
|
|
124
|
-
process.removeListener('uncaughtException', handler);
|
|
125
|
-
throw err;
|
|
126
|
-
};
|
|
127
|
-
// Install one-time handler to catch immediate async throw from Express
|
|
128
|
-
process.prependOnceListener('uncaughtException', handler);
|
|
129
|
-
try {
|
|
44
|
+
// This require starts the Express app and integrated MCP sidecar
|
|
130
45
|
require('./dist/web/server.js');
|
|
131
46
|
} catch (e) {
|
|
132
|
-
// Synchronous load error
|
|
133
|
-
process.removeListener('uncaughtException', handler);
|
|
134
47
|
console.error('[QuickMCP] Failed to start Web UI:', e && e.message);
|
|
135
48
|
}
|
|
136
|
-
// Remove handler on next tick if nothing happened, to avoid swallowing unrelated errors later
|
|
137
|
-
setImmediate(() => {
|
|
138
|
-
if (!handled) {
|
|
139
|
-
process.removeListener('uncaughtException', handler);
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
49
|
}
|
|
143
50
|
|
|
144
51
|
// Diagnostics: print environment and mssql details to help debug Claude Desktop
|