@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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/mcpServer.js +61 -63
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@context-engine-bridge/context-engine-mcp-bridge",
3
- "version": "0.0.34",
3
+ "version": "0.0.35",
4
4
  "description": "Context Engine MCP bridge (http/stdio proxy combining indexer + memory servers)",
5
5
  "bin": {
6
6
  "ctxce": "bin/ctxce.js",
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
- if (_isAbsolutePath(obj.path)) {
123
- if (workspace) {
124
- const contained = _resolveAndContain(obj.path, workspace);
125
- if (contained) paths.add(contained);
126
- } else {
127
- paths.add(obj.path);
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 { return result; }
183
- if (!parsed.ok) return result;
184
- if (_lspCircuitOpen()) {
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 bestLspMatch = null;
665
- let bestLspTs = 0;
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
- if (conn.created_at && (now - conn.created_at) > LSP_CONN_MAX_AGE) {
686
- } else {
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 > bestLspTs) {
689
- bestLspTs = connTs;
690
- bestLspMatch = wp;
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 (bestLspMatch) {
692
+ if (bestMatch) {
708
693
  debugLog("[ctxce] Resolved workspace from active LSP connection");
709
- return bestLspMatch;
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
- if (args && typeof args === "object" && args.include_lsp === true && _LSP_ENRICHABLE_TOOLS.has(name)) {
1177
- includeLsp = true;
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 (lspConn) finalResult = await _enrichWithLsp(finalResult, lspConn, workspace);
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;