@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.
- package/package.json +1 -1
- package/src/mcpServer.js +32 -24
package/package.json
CHANGED
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
|
-
|
|
122
|
-
|
|
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 (
|
|
159
|
+
if (settled) return;
|
|
162
160
|
data += chunk;
|
|
163
|
-
if (data.length > MAX_RESP) {
|
|
161
|
+
if (data.length > MAX_RESP) { req.destroy(); settle(null); }
|
|
164
162
|
});
|
|
165
|
-
res.on("end", () => { if (!
|
|
163
|
+
res.on("end", () => { if (!settled) { try { settle(JSON.parse(data)); } catch { settle(null); } } });
|
|
166
164
|
});
|
|
167
|
-
req.on("error", () =>
|
|
168
|
-
req.on("timeout", () => { req.destroy();
|
|
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
|
-
|
|
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
|
-
|
|
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)
|
|
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
|
-
|
|
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)); }
|