@context-engine-bridge/context-engine-mcp-bridge 0.0.34 → 0.0.35
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/src/mcpServer.js +61 -63
package/package.json
CHANGED
package/src/mcpServer.js
CHANGED
|
@@ -118,21 +118,19 @@ function _extractPaths(obj, paths, workspace, depth = 0) {
|
|
|
118
118
|
for (const item of obj) _extractPaths(item, paths, workspace, depth + 1);
|
|
119
119
|
return;
|
|
120
120
|
}
|
|
121
|
+
let rawPath = null;
|
|
121
122
|
if (typeof obj.path === "string" && obj.path.length > 0) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
} else if (workspace) {
|
|
130
|
-
const contained = _resolveAndContain(obj.path, workspace);
|
|
123
|
+
rawPath = obj.path;
|
|
124
|
+
} else if (typeof obj.rel_path === "string" && obj.rel_path.length > 0) {
|
|
125
|
+
rawPath = obj.rel_path;
|
|
126
|
+
}
|
|
127
|
+
if (rawPath) {
|
|
128
|
+
if (workspace) {
|
|
129
|
+
const contained = _resolveAndContain(rawPath, workspace);
|
|
131
130
|
if (contained) paths.add(contained);
|
|
131
|
+
} else if (_isAbsolutePath(rawPath)) {
|
|
132
|
+
paths.add(rawPath);
|
|
132
133
|
}
|
|
133
|
-
} else if (typeof obj.rel_path === "string" && obj.rel_path.length > 0 && workspace) {
|
|
134
|
-
const contained = _resolveAndContain(obj.rel_path, workspace);
|
|
135
|
-
if (contained) paths.add(contained);
|
|
136
134
|
}
|
|
137
135
|
for (const [key, val] of Object.entries(obj)) {
|
|
138
136
|
if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
|
|
@@ -175,35 +173,17 @@ function _callLspHandler(port, secret, operation, params) {
|
|
|
175
173
|
|
|
176
174
|
async function _enrichWithLsp(result, lspConn, workspace) {
|
|
177
175
|
try {
|
|
176
|
+
debugLog("[ctxce] LSP enrich: workspace=" + workspace + " port=" + lspConn?.port);
|
|
178
177
|
if (!Array.isArray(result?.content)) return result;
|
|
179
178
|
const textBlock = result.content.find(c => c.type === "text");
|
|
180
179
|
if (!textBlock?.text) return result;
|
|
181
180
|
let parsed;
|
|
182
|
-
try { parsed = JSON.parse(textBlock.text); } catch {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
parsed._lsp_status = "circuit_open";
|
|
186
|
-
} else {
|
|
187
|
-
const paths = new Set();
|
|
188
|
-
_extractPaths(parsed, paths, workspace);
|
|
189
|
-
if (paths.size === 0) {
|
|
190
|
-
parsed._lsp_status = "no_paths";
|
|
191
|
-
} else {
|
|
192
|
-
const diag = await _callLspHandler(lspConn.port, lspConn.secret, "diagnostics_recent", { paths: [...paths] });
|
|
193
|
-
if (!diag) {
|
|
194
|
-
_lspCircuitRecordFailure();
|
|
195
|
-
parsed._lsp_status = "connection_failed";
|
|
196
|
-
} else {
|
|
197
|
-
_lspCircuitRecordSuccess();
|
|
198
|
-
if (!diag.ok || !diag.files || diag.total === 0) {
|
|
199
|
-
parsed._lsp_status = "no_diagnostics";
|
|
200
|
-
} else {
|
|
201
|
-
parsed._lsp = { diagnostics: diag.files, total: diag.total };
|
|
202
|
-
parsed._lsp_status = "ok";
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
181
|
+
try { parsed = JSON.parse(textBlock.text); } catch (e) {
|
|
182
|
+
debugLog("[ctxce] LSP enrich: JSON parse failed: " + String(e));
|
|
183
|
+
return result;
|
|
206
184
|
}
|
|
185
|
+
if (!parsed.ok) return result;
|
|
186
|
+
parsed._lsp_status = await _resolveLspStatus(parsed, lspConn, workspace);
|
|
207
187
|
textBlock.text = JSON.stringify(parsed);
|
|
208
188
|
return result;
|
|
209
189
|
} catch (err) {
|
|
@@ -213,6 +193,22 @@ async function _enrichWithLsp(result, lspConn, workspace) {
|
|
|
213
193
|
}
|
|
214
194
|
}
|
|
215
195
|
|
|
196
|
+
async function _resolveLspStatus(parsed, lspConn, workspace) {
|
|
197
|
+
if (_lspCircuitOpen()) return "circuit_open";
|
|
198
|
+
const paths = new Set();
|
|
199
|
+
_extractPaths(parsed, paths, workspace);
|
|
200
|
+
if (paths.size === 0) return "no_paths";
|
|
201
|
+
const diag = await _callLspHandler(lspConn.port, lspConn.secret, "diagnostics_recent", { paths: [...paths] });
|
|
202
|
+
if (!diag) {
|
|
203
|
+
_lspCircuitRecordFailure();
|
|
204
|
+
return "connection_failed";
|
|
205
|
+
}
|
|
206
|
+
_lspCircuitRecordSuccess();
|
|
207
|
+
if (!diag.ok || !diag.files || diag.total === 0) return "no_diagnostics";
|
|
208
|
+
parsed._lsp = { diagnostics: diag.files, total: diag.total };
|
|
209
|
+
return "ok";
|
|
210
|
+
}
|
|
211
|
+
|
|
216
212
|
function debugLog(message) {
|
|
217
213
|
try {
|
|
218
214
|
const text = typeof message === "string" ? message : String(message);
|
|
@@ -661,10 +657,8 @@ function _resolveWorkspace(providedWorkspace) {
|
|
|
661
657
|
const wsRoot = path.join(os.homedir(), ".ctxce", "workspaces");
|
|
662
658
|
try {
|
|
663
659
|
const dirs = fs.readdirSync(wsRoot).slice(0, MAX_WS_SCAN);
|
|
664
|
-
let
|
|
665
|
-
let
|
|
666
|
-
let bestMetaMatch = null;
|
|
667
|
-
let bestMetaTs = 0;
|
|
660
|
+
let bestMatch = null;
|
|
661
|
+
let bestTs = 0;
|
|
668
662
|
for (const dir of dirs) {
|
|
669
663
|
if (dir === "." || dir === ".." || dir.includes("/") || dir.includes("\0")) continue;
|
|
670
664
|
const dirPath = path.join(wsRoot, dir);
|
|
@@ -682,35 +676,22 @@ function _resolveWorkspace(providedWorkspace) {
|
|
|
682
676
|
if (conn.pid && conn.port && _isValidPort(conn.port)) {
|
|
683
677
|
try {
|
|
684
678
|
process.kill(conn.pid, 0);
|
|
685
|
-
|
|
686
|
-
|
|
679
|
+
const notExpired = !conn.created_at || (now - conn.created_at) <= LSP_CONN_MAX_AGE;
|
|
680
|
+
if (notExpired) {
|
|
687
681
|
const connTs = typeof conn.created_at === "number" ? conn.created_at : 0;
|
|
688
|
-
if (connTs >
|
|
689
|
-
|
|
690
|
-
|
|
682
|
+
if (connTs > bestTs) {
|
|
683
|
+
bestTs = connTs;
|
|
684
|
+
bestMatch = wp;
|
|
691
685
|
}
|
|
692
686
|
}
|
|
693
687
|
} catch (_) {}
|
|
694
688
|
}
|
|
695
689
|
} catch (_) {}
|
|
696
|
-
const updatedAt = typeof meta.updated_at === "number"
|
|
697
|
-
? meta.updated_at
|
|
698
|
-
: typeof meta.updated_at === "string"
|
|
699
|
-
? new Date(meta.updated_at).getTime() || 0
|
|
700
|
-
: 0;
|
|
701
|
-
if (updatedAt > bestMetaTs) {
|
|
702
|
-
bestMetaTs = updatedAt;
|
|
703
|
-
bestMetaMatch = wp;
|
|
704
|
-
}
|
|
705
690
|
} catch (_) {}
|
|
706
691
|
}
|
|
707
|
-
if (
|
|
692
|
+
if (bestMatch) {
|
|
708
693
|
debugLog("[ctxce] Resolved workspace from active LSP connection");
|
|
709
|
-
return
|
|
710
|
-
}
|
|
711
|
-
if (bestMetaMatch) {
|
|
712
|
-
debugLog("[ctxce] Resolved workspace from most recent meta.json");
|
|
713
|
-
return bestMetaMatch;
|
|
694
|
+
return bestMatch;
|
|
714
695
|
}
|
|
715
696
|
} catch (_) {}
|
|
716
697
|
|
|
@@ -1173,11 +1154,14 @@ async function createBridgeServer(options) {
|
|
|
1173
1154
|
let args = params.arguments;
|
|
1174
1155
|
|
|
1175
1156
|
let includeLsp = false;
|
|
1176
|
-
|
|
1177
|
-
|
|
1157
|
+
const rawLsp = args && typeof args === "object" ? args.include_lsp : undefined;
|
|
1158
|
+
if (rawLsp !== undefined) {
|
|
1178
1159
|
const { include_lsp: _stripped, ...rest } = args;
|
|
1179
1160
|
args = rest;
|
|
1180
1161
|
}
|
|
1162
|
+
if ((rawLsp === true || rawLsp === "true" || rawLsp === 1 || rawLsp === "1") && _LSP_ENRICHABLE_TOOLS.has(name)) {
|
|
1163
|
+
includeLsp = true;
|
|
1164
|
+
}
|
|
1181
1165
|
|
|
1182
1166
|
debugLog(`[ctxce] tools/call: ${name || "<no-name>"}`);
|
|
1183
1167
|
|
|
@@ -1304,7 +1288,21 @@ async function createBridgeServer(options) {
|
|
|
1304
1288
|
);
|
|
1305
1289
|
let finalResult = maybeRemapToolResult(name, result, workspace);
|
|
1306
1290
|
const lspConn = includeLsp && _readLspConnection(workspace);
|
|
1307
|
-
if (
|
|
1291
|
+
if (includeLsp) {
|
|
1292
|
+
debugLog("[ctxce] LSP gate: tool=" + name + " lsp=" + (lspConn ? "port:" + lspConn.port : "null"));
|
|
1293
|
+
}
|
|
1294
|
+
if (lspConn) {
|
|
1295
|
+
finalResult = await _enrichWithLsp(finalResult, lspConn, workspace);
|
|
1296
|
+
} else if (includeLsp) {
|
|
1297
|
+
try {
|
|
1298
|
+
const tb = Array.isArray(finalResult?.content) && finalResult.content.find(c => c.type === "text");
|
|
1299
|
+
if (tb?.text) {
|
|
1300
|
+
const p = JSON.parse(tb.text);
|
|
1301
|
+
p._lsp_status = "not_available";
|
|
1302
|
+
tb.text = JSON.stringify(p);
|
|
1303
|
+
}
|
|
1304
|
+
} catch (_) {}
|
|
1305
|
+
}
|
|
1308
1306
|
return finalResult;
|
|
1309
1307
|
} catch (err) {
|
|
1310
1308
|
lastError = err;
|