@context-engine-bridge/context-engine-mcp-bridge 0.0.40 → 0.0.43

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 +32 -24
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@context-engine-bridge/context-engine-mcp-bridge",
3
- "version": "0.0.40",
3
+ "version": "0.0.43",
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
@@ -112,24 +112,21 @@ function _resolveAndContain(relPath, workspace) {
112
112
  return null;
113
113
  }
114
114
 
115
+ const _PATH_FIELDS = ["host_path", "path", "rel_path"];
116
+
115
117
  function _extractPaths(obj, paths, workspace, depth = 0) {
116
118
  if (!obj || typeof obj !== "object" || depth > 20) return;
117
119
  if (Array.isArray(obj)) {
118
120
  for (const item of obj) _extractPaths(item, paths, workspace, depth + 1);
119
121
  return;
120
122
  }
121
- let rawPath = null;
122
- if (typeof obj.path === "string" && obj.path.length > 0) {
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) {
123
+ const candidates = _PATH_FIELDS.map(f => obj[f]).filter(v => typeof v === "string" && v.length > 0);
124
+ for (const rawPath of candidates) {
128
125
  if (workspace) {
129
126
  const contained = _resolveAndContain(rawPath, workspace);
130
- if (contained) paths.add(contained);
127
+ if (contained) { paths.add(contained); break; }
131
128
  } else if (_isAbsolutePath(rawPath)) {
132
- paths.add(rawPath);
129
+ paths.add(rawPath); break;
133
130
  }
134
131
  }
135
132
  for (const [key, val] of Object.entries(obj)) {
@@ -141,6 +138,8 @@ function _extractPaths(obj, paths, workspace, depth = 0) {
141
138
  function _callLspHandler(port, secret, operation, params) {
142
139
  const postData = JSON.stringify(params);
143
140
  return new Promise((resolve) => {
141
+ let settled = false;
142
+ const settle = (v) => { if (!settled) { settled = true; resolve(v); } };
144
143
  const req = http.request({
145
144
  hostname: "127.0.0.1",
146
145
  port: parseInt(port, 10),
@@ -154,18 +153,17 @@ function _callLspHandler(port, secret, operation, params) {
154
153
  timeout: 3000,
155
154
  }, (res) => {
156
155
  let data = "";
157
- let exceeded = false;
158
156
  const MAX_RESP = 5 * 1024 * 1024;
159
- res.on("error", () => {});
157
+ res.on("error", () => settle(null));
160
158
  res.on("data", chunk => {
161
- if (exceeded) return;
159
+ if (settled) return;
162
160
  data += chunk;
163
- if (data.length > MAX_RESP) { exceeded = true; req.destroy(); resolve(null); }
161
+ if (data.length > MAX_RESP) { req.destroy(); settle(null); }
164
162
  });
165
- res.on("end", () => { if (!exceeded) { try { resolve(JSON.parse(data)); } catch { resolve(null); } } });
163
+ res.on("end", () => { if (!settled) { try { settle(JSON.parse(data)); } catch { settle(null); } } });
166
164
  });
167
- req.on("error", () => resolve(null));
168
- req.on("timeout", () => { req.destroy(); resolve(null); });
165
+ req.on("error", () => settle(null));
166
+ req.on("timeout", () => { req.destroy(); settle(null); });
169
167
  req.write(postData);
170
168
  req.end();
171
169
  });
@@ -188,8 +186,8 @@ async function _enrichWithLsp(result, lspConn, workspace) {
188
186
  return result;
189
187
  }
190
188
  const target = _lspTarget(parsed);
191
- if (!target.ok) return result;
192
- target._lsp_status = await _resolveLspStatus(target, lspConn, workspace);
189
+ if (!parsed.ok && !target.ok) return result;
190
+ parsed._lsp_status = await _resolveLspStatus(parsed, target, lspConn, workspace);
193
191
  textBlock.text = JSON.stringify(parsed);
194
192
  return result;
195
193
  } catch (err) {
@@ -199,7 +197,7 @@ async function _enrichWithLsp(result, lspConn, workspace) {
199
197
  }
200
198
  }
201
199
 
202
- async function _resolveLspStatus(target, lspConn, workspace) {
200
+ async function _resolveLspStatus(dest, target, lspConn, workspace) {
203
201
  if (_lspCircuitOpen()) return "circuit_open";
204
202
  const paths = new Set();
205
203
  _extractPaths(target, paths, workspace);
@@ -211,7 +209,7 @@ async function _resolveLspStatus(target, lspConn, workspace) {
211
209
  }
212
210
  _lspCircuitRecordSuccess();
213
211
  if (!diag.ok || !diag.files || diag.total === 0) return "no_diagnostics";
214
- target._lsp = { diagnostics: diag.files, total: diag.total };
212
+ dest._lsp = { diagnostics: diag.files, total: diag.total };
215
213
  return "ok";
216
214
  }
217
215
 
@@ -1073,9 +1071,20 @@ async function createBridgeServer(options) {
1073
1071
  description: "When true, auto-enrich results with live LSP diagnostics (errors/warnings) for files in the response. Zero extra tool calls needed.",
1074
1072
  };
1075
1073
  for (const tool of tools) {
1076
- if (_LSP_ENRICHABLE_TOOLS.has(tool.name) && tool.inputSchema?.properties) {
1074
+ if (!_LSP_ENRICHABLE_TOOLS.has(tool.name)) continue;
1075
+ if (tool.inputSchema?.properties) {
1077
1076
  tool.inputSchema = { ...tool.inputSchema, properties: { ...tool.inputSchema.properties, include_lsp: lspProp } };
1078
1077
  }
1078
+ if (tool.outputSchema) {
1079
+ tool.outputSchema = {
1080
+ ...tool.outputSchema,
1081
+ properties: {
1082
+ ...(tool.outputSchema.properties || {}),
1083
+ _lsp_status: { type: "string" },
1084
+ _lsp: { type: "object" },
1085
+ },
1086
+ };
1087
+ }
1079
1088
  }
1080
1089
 
1081
1090
  const pathProp = { type: "string", description: "Absolute file path" };
@@ -1239,7 +1248,7 @@ async function createBridgeServer(options) {
1239
1248
  let data = "";
1240
1249
  let exceeded = false;
1241
1250
  const MAX_RESP = 5 * 1024 * 1024;
1242
- res.on("error", () => {});
1251
+ res.on("error", () => { if (!exceeded) resolve({ ok: false, error: "LSP response stream error" }); });
1243
1252
  res.on("data", chunk => {
1244
1253
  if (exceeded) return;
1245
1254
  data += chunk;
@@ -1303,8 +1312,7 @@ async function createBridgeServer(options) {
1303
1312
  const tb = Array.isArray(result?.content) && result.content.find(c => c.type === "text");
1304
1313
  if (tb?.text) {
1305
1314
  const p = JSON.parse(tb.text);
1306
- const t = _lspTarget(p);
1307
- t._lsp_status = "not_available";
1315
+ p._lsp_status = "not_available";
1308
1316
  tb.text = JSON.stringify(p);
1309
1317
  }
1310
1318
  } catch (e) { debugLog("[ctxce] LSP not_available inject failed: " + String(e)); }